From b7e554078ed511a3e98da612042ef4f8155639d3 Mon Sep 17 00:00:00 2001 From: "ran.solash" Date: Wed, 24 Apr 2024 18:01:01 +0300 Subject: [PATCH] optionaly --- CHANGELOG.md | 7 +++++++ README.md | 4 ++-- project.clj | 4 ++-- resources/proto/people.proto | 2 +- src/clj/pronto/emitters.clj | 2 +- src/clj/pronto/type_gen.clj | 4 ++-- src/clj/pronto/utils.clj | 3 +++ test/pronto/core_test.clj | 29 ++++++++++++++++++++++++++--- 8 files changed, 44 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f33d1f2..4bde950 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ ## This library follows [Semantic Versioning](https://semver.org). ## This CHANGELOG follows [keepachangelog](https://keepachangelog.com/en/1.0.0/). +### VERSION [3.0.0]: +#### Changed +* Minimal supported protobuf version 3.15.0. +* when a getting an optional field that was not set, a nil will be returned instead of the deafault value of this field. +* Allow assoc a nil to optional fields - It will clear the field. +* Allow checking if an optional field was set or not with `p/has-field?`. + ### VERSION [2.1.2]: #### Changed * return `:unrecognized` for unknown enum values in order to support forward compatibility. diff --git a/README.md b/README.md index 22b71be..19fb725 100644 --- a/README.md +++ b/README.md @@ -22,9 +22,9 @@ ignored completely. ## Installation Add a dependency to your `project.clj` file: - [com.appsflyer/pronto "2.1.2"] + [com.appsflyer/pronto "3.0.0"] -Note that the library comes with no Java protobuf dependencies of its own and they are expected to be provided by consumers of the library, with a minimal version of `3.9.0`. +Note that the library comes with no Java protobuf dependencies of its own and they are expected to be provided by consumers of the library, with a minimal version of `3.15.0`. ## How does it work? diff --git a/project.clj b/project.clj index 9365dfb..163d3d5 100644 --- a/project.clj +++ b/project.clj @@ -1,7 +1,7 @@ -(def protobuf-version "3.9.0") +(def protobuf-version "3.15.0") -(defproject com.appsflyer/pronto "2.1.2" +(defproject com.appsflyer/pronto "3.0.0" :description "clojure support for protocol buffers" :url "https://github.com/AppsFlyer/pronto" :license {:name "Eclipse Public License" diff --git a/resources/proto/people.proto b/resources/proto/people.proto index c153ed0..6f50cfd 100644 --- a/resources/proto/people.proto +++ b/resources/proto/people.proto @@ -63,7 +63,7 @@ enum Level { message Like { string desc = 1; - Level level = 2; + optional Level level = 2; } message House { diff --git a/src/clj/pronto/emitters.clj b/src/clj/pronto/emitters.clj index 0bff1f6..643ec77 100644 --- a/src/clj/pronto/emitters.clj +++ b/src/clj/pronto/emitters.clj @@ -221,7 +221,7 @@ fields k true (fn [field] (let [^Descriptors$FieldDescriptor fd (:fd field)] - (if (u/struct? fd) + (if (or (u/struct? fd) (u/optional? fd)) (let [has-method (symbol (str ".has" (u/field->camel-case (:fd field))))] `(~has-method ~o)) `(throw (IllegalArgumentException. (str "field " ~k " cannot be checked for field existence")))))))) diff --git a/src/clj/pronto/type_gen.clj b/src/clj/pronto/type_gen.clj index cd6627b..bd43cbb 100644 --- a/src/clj/pronto/type_gen.clj +++ b/src/clj/pronto/type_gen.clj @@ -60,7 +60,7 @@ res (u/with-type-hint (gensym 'res) field-type)) clear-method (symbol (str ".clear" (u/field->camel-case fd)))] - (if (u/message? fd) + (if (or (u/message? fd) (u/optional? fd)) `(if (nil? ~v) (~clear-method ~builder) (let [~res ~(w/unwrap wrapper v)] @@ -73,7 +73,7 @@ has-method (symbol (str ".has" (u/field->camel-case fd))) get-form `(let [~v (~getter ~o)] ~(w/wrap wrapper v))] - (if-not (u/message? fd) + (if-not (or (u/message? fd) (u/optional? fd)) get-form `(when (~has-method ~o) ~get-form))))))) diff --git a/src/clj/pronto/utils.clj b/src/clj/pronto/utils.clj index c7521e1..6760009 100644 --- a/src/clj/pronto/utils.clj +++ b/src/clj/pronto/utils.clj @@ -85,6 +85,9 @@ (not (.isMapField fd)) (not (.isRepeated fd)))) +(defn optional? [^Descriptors$FieldDescriptor fd] + (.hasOptionalKeyword fd)) + (defn enum? [^Descriptors$FieldDescriptor fd] (= (.getType fd) Descriptors$FieldDescriptor$Type/ENUM)) diff --git a/test/pronto/core_test.clj b/test/pronto/core_test.clj index 0efc097..f93c80a 100644 --- a/test/pronto/core_test.clj +++ b/test/pronto/core_test.clj @@ -812,10 +812,33 @@ an error in the generated code" (is (= ["DESC1" "DESC2" "DESC3"] (map :desc (:likes new-p))))))) -(deftest hint-validity [] +(deftest hint-validity (testing "hinting should only work within with-hints or p->" (is (thrown? Exception (macroexpand '(pronto.lens/hint (p/proto-map mapper People$Person) People$Person - mapper))))) - ) + mapper)))))) + +(deftest optional-field + (testing "usage of optional fields" + (let [p1 (p/proto-map mapper People$Like :level :LOW) + p2 (p/proto-map mapper People$Like)] + (is (= (:level p1) :LOW)) + (is (true? (p/has-field? p1 :level))) + (-> (p/clear-field p1 :level) + (p/has-field? :level) + false? + is) + (is (= (p/clear-field p1 :level) p2)) + + (-> (assoc p1 :level nil) + (p/has-field? :level) + false? + is) + (is (= (assoc p1 :level nil) p2)) + + (is (false? (p/has-field? p2 :level))) + (is (= (:level p2) nil)) + + (is (= (assoc p2 :level :LOW) p1)) + (is (p/has-field? (assoc p2 :level :LOW) :level)))))