From 0483bf9195538127e41b13b97dd2787caadb44ae Mon Sep 17 00:00:00 2001 From: Roman Kalnytskyi Date: Sun, 15 Apr 2018 12:09:35 +0300 Subject: [PATCH] fix compile time error with impossible relation typecasting in mqrt --- spec/query_builder/model_query_spec.cr | 8 ++ src/jennifer.cr | 4 + .../multi_query_relation_tree.cr | 79 +------------------ src/jennifer/relation/base.cr | 25 ++++++ src/jennifer/relation/belongs_to.cr | 24 ++++++ src/jennifer/relation/many_to_many.cr | 27 +++++++ 6 files changed, 89 insertions(+), 78 deletions(-) diff --git a/spec/query_builder/model_query_spec.cr b/spec/query_builder/model_query_spec.cr index 4c16f993..203d0a08 100644 --- a/spec/query_builder/model_query_spec.cr +++ b/spec/query_builder/model_query_spec.cr @@ -663,6 +663,14 @@ describe Jennifer::QueryBuilder::ModelQuery do .order({"period" => :desc}) .results.size.should eq(1) end + + it "allows to use float for filtering decimal fields" do + converter = Jennifer::Model::ParameterConverter.new + c = Factory.create_contact + c.ballance = converter.parse("15.1", "Numeric").as(PG::Numeric) + c.save + Contact.all.where { _ballance == 15.1 }.count.should eq(1) + end end end end diff --git a/src/jennifer.cr b/src/jennifer.cr index ac6e87b3..f5542d22 100644 --- a/src/jennifer.cr +++ b/src/jennifer.cr @@ -68,6 +68,10 @@ module Jennifer raise "stubed relation" end + def preload_relation(collection, out_collection, pk_repo) + raise "stubbed relation" + end + {% for method in %i(table_name model_class type set_callback condition_clause foreign_field primary_field join_query) %} def {{method.id}} raise "stubed relation" diff --git a/src/jennifer/query_builder/multi_query_relation_tree.cr b/src/jennifer/query_builder/multi_query_relation_tree.cr index 99107973..faf205b3 100644 --- a/src/jennifer/query_builder/multi_query_relation_tree.cr +++ b/src/jennifer/query_builder/multi_query_relation_tree.cr @@ -20,84 +20,7 @@ module Jennifer (@bucket.size + 1).times { |_| pk_repo << {} of DBAny => Array(DBAny) } @bucket.each_with_index do |pair, index| - preload_relation(repo[pair[0]], repo[index + 1].as(Array(Model::Resource)), pair[1], pk_repo[index]) - end - end - - private def preload_relation(collection, out_collection : Array(Model::Resource), relation : Relation::ManyToMany, pk_repo) - return if collection.empty? - _primary = relation.primary_field - _foreign = relation.foreign_field - - unless pk_repo.has_key?(_primary) - array = pk_repo[_primary] = Array(DBAny).new(collection.size) - collection.each { |e| array << e.attribute(_primary) } - end - - join_fk = "__join_fk__" - query = relation.query(pk_repo[_primary]) - fields = query._select_fields - fields << Criteria.new(_foreign, relation.join_table!).alias(join_fk) - new_collection = query.select(fields).db_results - - name = relation.name - if new_collection.empty? - collection.each(&.relation_retrieved(name)) - else - primary_fields = pk_repo[_primary] - collection.each_with_index do |mod, i| - pv = primary_fields[i] - new_collection.each { |hash| out_collection << mod.append_relation(name, hash) if hash[join_fk] == pv } - end - end - end - - private def preload_relation(collection, out_collection : Array(Model::Resource), relation : Relation::BelongsTo, pk_repo) - return if collection.empty? - _primary = relation.primary_field - _foreign = relation.foreign_field - - unless pk_repo.has_key?(_foreign) - array = pk_repo[_foreign] = Array(DBAny).new(collection.size) - collection.each { |e| array << e.attribute(_foreign) } - end - - new_collection = relation.query(pk_repo[_foreign]).db_results - - name = relation.name - if new_collection.empty? - collection.each(&.relation_retrieved(name)) - else - foreign_fields = pk_repo[_foreign] - collection.each_with_index do |mod, i| - fk = foreign_fields[i] - new_collection.each { |hash| out_collection << mod.append_relation(name, hash) if hash[_primary] == fk } - end - end - end - - private def preload_relation(collection, out_collection : Array(Model::Resource), relation, pk_repo) - return if collection.empty? - _primary = relation.primary_field - _foreign = relation.foreign_field - - unless pk_repo.has_key?(_primary) - array = pk_repo[_primary] = Array(DBAny).new(collection.size) - collection.each { |e| array << e.attribute(_primary) } - end - - new_collection = relation.query(pk_repo[_primary]).db_results - - name = relation.name - if new_collection.empty? - collection.each(&.relation_retrieved(name)) - else - primary_fields = pk_repo[_primary] - collection.each_with_index do |mod, i| - pv = primary_fields[i] - # TODO: check if deleting elements from array will increase performance - new_collection.each { |hash| out_collection << mod.append_relation(name, hash) if hash[_foreign] == pv } - end + pair[1].preload_relation(repo[pair[0]], repo[index + 1].as(Array(Model::Resource)), pk_repo[index]) end end end diff --git a/src/jennifer/relation/base.cr b/src/jennifer/relation/base.cr index 9f69a19f..b0352881 100644 --- a/src/jennifer/relation/base.cr +++ b/src/jennifer/relation/base.cr @@ -12,6 +12,8 @@ module Jennifer abstract def join_condition(a, b) abstract def query(a) abstract def insert(a, b) + # Preloads relation into *collection* from *out_collection* depending on keys from *pk_repo*. + abstract def preload_relation(collection, out_collection, pk_repo) end # T - related model @@ -98,6 +100,29 @@ module Jennifer def primary_field @primary ||= Q.primary_field_name end + + def preload_relation(collection, out_collection : Array(Model::Resource), pk_repo) + return if collection.empty? + + unless pk_repo.has_key?(primary_field) + array = pk_repo[primary_field] = Array(DBAny).new(collection.size) + collection.each { |e| array << e.attribute(primary_field) } + end + + new_collection = query(pk_repo[primary_field]).db_results + + name = self.name + if new_collection.empty? + collection.each(&.relation_retrieved(name)) + else + primary_fields = pk_repo[primary_field] + collection.each_with_index do |mod, i| + pv = primary_fields[i] + # TODO: check if deleting elements from array will increase performance + new_collection.each { |hash| out_collection << mod.append_relation(name, hash) if hash[foreign_field] == pv } + end + end + end end end end diff --git a/src/jennifer/relation/belongs_to.cr b/src/jennifer/relation/belongs_to.cr index 235fa2b1..91fabd9c 100644 --- a/src/jennifer/relation/belongs_to.cr +++ b/src/jennifer/relation/belongs_to.cr @@ -108,6 +108,30 @@ module Jennifer def primary_field @primary ||= T.primary_field_name end + + def preload_relation(collection, out_collection : Array(Model::Resource), pk_repo) + return if collection.empty? + _primary = primary_field + _foreign = foreign_field + + unless pk_repo.has_key?(_foreign) + array = pk_repo[_foreign] = Array(DBAny).new(collection.size) + collection.each { |e| array << e.attribute(_foreign) } + end + + new_collection = query(pk_repo[_foreign]).db_results + + name = self.name + if new_collection.empty? + collection.each(&.relation_retrieved(name)) + else + foreign_fields = pk_repo[_foreign] + collection.each_with_index do |mod, i| + fk = foreign_fields[i] + new_collection.each { |hash| out_collection << mod.append_relation(name, hash) if hash[_primary] == fk } + end + end + end end end end diff --git a/src/jennifer/relation/many_to_many.cr b/src/jennifer/relation/many_to_many.cr index 7d038e75..b2b60418 100644 --- a/src/jennifer/relation/many_to_many.cr +++ b/src/jennifer/relation/many_to_many.cr @@ -74,6 +74,33 @@ module Jennifer @association_foreign || T.to_s.foreign_key end + def preload_relation(collection, out_collection : Array(Model::Resource), pk_repo) + return if collection.empty? + _primary = primary_field + + unless pk_repo.has_key?(_primary) + array = pk_repo[_primary] = Array(DBAny).new(collection.size) + collection.each { |e| array << e.attribute(_primary) } + end + + join_fk = "__join_fk__" + query = query(pk_repo[_primary]) + fields = query._select_fields + fields << QueryBuilder::Criteria.new(foreign_field, join_table!).alias(join_fk) + new_collection = query.select(fields).db_results + + name = self.name + if new_collection.empty? + collection.each(&.relation_retrieved(name)) + else + primary_fields = pk_repo[_primary] + collection.each_with_index do |mod, i| + pv = primary_fields[i] + new_collection.each { |hash| out_collection << mod.append_relation(name, hash) if hash[join_fk] == pv } + end + end + end + private def add_join_table_record(obj, rel) adapter.insert( join_table!,