From 133b78fc28407b348562009be04958989020fb17 Mon Sep 17 00:00:00 2001 From: Jamie Gaskins Date: Sun, 10 Mar 2024 15:41:11 -0500 Subject: [PATCH 1/4] Fix namespaced vs top-level type-name collisions Allow top-level property types to have the same name as DB-namespaced ones. --- spec/serializable_spec.cr | 24 ++++++++++++++++++++++++ src/db/serializable.cr | 4 ++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/spec/serializable_spec.cr b/spec/serializable_spec.cr index 4ad2cf9..c70fc88 100644 --- a/spec/serializable_spec.cr +++ b/spec/serializable_spec.cr @@ -104,6 +104,23 @@ struct ModelWithEnum end end +# Ensure types that happen to have the same name as types within the `DB` +# namespace don't clash here +struct Transaction + include DB::Serializable + + @[DB::Field(key: "c0")] + getter id : Int32 + @[DB::Field(key: "c1")] + getter status : Status + + enum Status + Pending + Complete + Canceled + end +end + macro from_dummy(query, type) with_dummy do |db| rs = db.query({{ query }}) @@ -206,6 +223,13 @@ describe "DB::Serializable" do end end + it "should compile when top-level names collide with DB-namespaced names" do + expect_model("1,Pending", Transaction, { + id: 1, + status: Transaction::Status::Pending, + }) + end + it "should initialize multiple instances from a single resultset" do with_dummy do |db| db.query("1,a 2,b") do |rs| diff --git a/src/db/serializable.cr b/src/db/serializable.cr index ce92ca6..428847e 100644 --- a/src/db/serializable.cr +++ b/src/db/serializable.cr @@ -136,7 +136,7 @@ module DB {% elsif value[:nilable] || value[:default] != nil %} rs.read(::Union({{value[:type]}} | Nil)) {% else %} - rs.read({{value[:type]}}) + rs.read(::{{value[:type]}}) {% end %} rescue exc ::raise ::DB::MappingException.new(exc.message, self.class.to_s, {{name.stringify}}, cause: exc) @@ -166,7 +166,7 @@ module DB {% elsif value[:default] != nil %} @{{key}} = %var{key}.is_a?(Nil) ? {{value[:default]}} : %var{key} {% else %} - @{{key}} = %var{key}.as({{value[:type]}}) + @{{key}} = %var{key}.as(::{{value[:type]}}) {% end %} {% end %} {% end %} From 2b6e4efbeb11335d2eaafd5763a06875a5583d4f Mon Sep 17 00:00:00 2001 From: Jamie Gaskins Date: Sun, 10 Mar 2024 15:45:53 -0500 Subject: [PATCH 2/4] Fix one more potential naming collision --- src/db/serializable.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/serializable.cr b/src/db/serializable.cr index 428847e..f74d49d 100644 --- a/src/db/serializable.cr +++ b/src/db/serializable.cr @@ -134,7 +134,7 @@ module DB {% if value[:converter] %} {{value[:converter]}}.from_rs(rs) {% elsif value[:nilable] || value[:default] != nil %} - rs.read(::Union({{value[:type]}} | Nil)) + rs.read(::Union(::{{value[:type]}} | Nil)) {% else %} rs.read(::{{value[:type]}}) {% end %} From 47a667c2d898a973b2165a2f5605b60e0fced93f Mon Sep 17 00:00:00 2001 From: Jamie Gaskins Date: Sun, 10 Mar 2024 15:56:37 -0500 Subject: [PATCH 3/4] Add full type qual up top to handle type unions --- src/db/serializable.cr | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/db/serializable.cr b/src/db/serializable.cr index f74d49d..4a54b2f 100644 --- a/src/db/serializable.cr +++ b/src/db/serializable.cr @@ -109,7 +109,11 @@ module DB {% unless ann && ann[:ignore] %} {% properties[ivar.id] = { - type: ivar.type, + type: if ivar.type.union? + "Union(#{ivar.type.union_types.map { |t| "::#{t}".id }.join(" | ").id})".id + else + "::#{ivar.type}".id + end, key: ((ann && ann[:key]) || ivar).id.stringify, default: ivar.default_value, nilable: ivar.type.nilable?, @@ -134,9 +138,9 @@ module DB {% if value[:converter] %} {{value[:converter]}}.from_rs(rs) {% elsif value[:nilable] || value[:default] != nil %} - rs.read(::Union(::{{value[:type]}} | Nil)) + rs.read(::Union({{value[:type]}} | Nil)) {% else %} - rs.read(::{{value[:type]}}) + rs.read({{value[:type]}}) {% end %} rescue exc ::raise ::DB::MappingException.new(exc.message, self.class.to_s, {{name.stringify}}, cause: exc) @@ -166,7 +170,7 @@ module DB {% elsif value[:default] != nil %} @{{key}} = %var{key}.is_a?(Nil) ? {{value[:default]}} : %var{key} {% else %} - @{{key}} = %var{key}.as(::{{value[:type]}}) + @{{key}} = %var{key}.as({{value[:type]}}) {% end %} {% end %} {% end %} From 45d55ba4732ce5acd88d236fbdab9161927d7037 Mon Sep 17 00:00:00 2001 From: Jamie Gaskins Date: Sun, 10 Mar 2024 16:00:20 -0500 Subject: [PATCH 4/4] Run `crystal tool format` --- src/db/serializable.cr | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/db/serializable.cr b/src/db/serializable.cr index 4a54b2f..3ec448c 100644 --- a/src/db/serializable.cr +++ b/src/db/serializable.cr @@ -109,11 +109,11 @@ module DB {% unless ann && ann[:ignore] %} {% properties[ivar.id] = { - type: if ivar.type.union? - "Union(#{ivar.type.union_types.map { |t| "::#{t}".id }.join(" | ").id})".id - else - "::#{ivar.type}".id - end, + type: if ivar.type.union? + "Union(#{ivar.type.union_types.map { |t| "::#{t}".id }.join(" | ").id})".id + else + "::#{ivar.type}".id + end, key: ((ann && ann[:key]) || ivar).id.stringify, default: ivar.default_value, nilable: ivar.type.nilable?,