From 20991b96c74e03214004562e076007e141efa875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Couton?= Date: Mon, 18 Jul 2022 18:52:24 +0200 Subject: [PATCH 01/37] add query_fn --- lib/couchbase-orm/connection.rb | 2 +- lib/couchbase-orm/n1ql.rb | 31 ++++++++++++++++++------------- spec/n1ql_spec.rb | 12 +++++++++++- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/lib/couchbase-orm/connection.rb b/lib/couchbase-orm/connection.rb index 9886c640..21eab03b 100644 --- a/lib/couchbase-orm/connection.rb +++ b/lib/couchbase-orm/connection.rb @@ -12,7 +12,7 @@ def self.cluster @cluster ||= begin options = Couchbase::Cluster::ClusterOptions.new options.authenticate(ENV["COUCHBASE_USER"], ENV["COUCHBASE_PASSWORD"]) - cluster = Couchbase::Cluster.connect('couchbase://127.0.0.1', options) + Couchbase::Cluster.connect('couchbase://127.0.0.1', options) end end diff --git a/lib/couchbase-orm/n1ql.rb b/lib/couchbase-orm/n1ql.rb index 7c157aec..6556eb30 100644 --- a/lib/couchbase-orm/n1ql.rb +++ b/lib/couchbase-orm/n1ql.rb @@ -35,7 +35,7 @@ module ClassMethods # # ... # end # TODO: add range keys [:startkey, :endkey] - def n1ql(name, select: nil, emit_key: [], **options) + def n1ql(name, query_fn: nil, emit_key: [], **options) emit_key = Array.wrap(emit_key) emit_key.each do |key| raise "unknown emit_key attribute for n1ql :#{name}, emit_key: :#{key}" if key && @attributes[key].nil? @@ -50,7 +50,7 @@ def n1ql(name, select: nil, emit_key: [], **options) singleton_class.__send__(:define_method, name) do |**opts, &result_modifier| opts = options.merge(opts).reverse_merge(scan_consistency: :request_plus) values = convert_values(opts.delete(:key)) - current_query = run_query(method_opts[:emit_key], values, select: select, **opts.except(:include_docs)) + current_query = run_query(method_opts[:emit_key], values, query_fn, **opts.except(:include_docs)) if result_modifier opts[:include_docs] = true @@ -113,17 +113,22 @@ def build_limit(limit) limit ? "limit #{limit}" : "" end - def run_query(keys, values, select: nil, descending: false, limit: nil, **options) - bucket_name = bucket.name - where = build_where(keys, values) - order = build_order(keys, descending) - limit = build_limit(limit) - select ||= "raw meta().id" - raise "select must be a string" unless select.is_a?(String) - n1ql_query = "select #{select} from `#{bucket_name}` where #{where} order by #{order} #{limit}" - result = cluster.query(n1ql_query, Couchbase::Options::Query.new(**options)) - CouchbaseOrm.logger.debug "N1QL query: #{n1ql_query} return #{result.rows.to_a.length} rows" - N1qlProxy.new(result) + def run_query(keys, values, query_fn, descending: false, limit: nil, **options) + if query_fn + result = query_fn.call(bucket, values, cluster) + N1qlProxy.new(result) + else + bucket_name = bucket.name + where = build_where(keys, values) + order = build_order(keys, descending) + limit = build_limit(limit) + select = "raw meta().id" + raise "select must be a string" unless select.is_a?(String) + n1ql_query = "select #{select} from `#{bucket_name}` where #{where} order by #{order} #{limit}" + result = cluster.query(n1ql_query, Couchbase::Options::Query.new(**options)) + CouchbaseOrm.logger.debug "N1QL query: #{n1ql_query} return #{result.rows.to_a.length} rows" + N1qlProxy.new(result) + end end end end diff --git a/spec/n1ql_spec.rb b/spec/n1ql_spec.rb index 66da5f8a..d6d0110f 100644 --- a/spec/n1ql_spec.rb +++ b/spec/n1ql_spec.rb @@ -7,7 +7,10 @@ class N1QLTest < CouchbaseOrm::Base enum rating: [:awesome, :good, :okay, :bad], default: :okay n1ql :all - n1ql :by_name, emit_key: :name + n1ql :by_custom_rating, query_fn: proc { |bucket, _values, cluster| + cluster.query("SELECT raw meta().id FROM `#{bucket.name}` WHERE rating IN [1, 2] ORDER BY name ASC") + } + n1ql :by_name, emit_key: [:name, :rating] n1ql :by_rating, emit_key: :rating # This generates both: @@ -56,6 +59,13 @@ class N1QLTest < CouchbaseOrm::Base } expect(Set.new(docs)).to eq(Set.new(%w[bob jane])) + + docs = N1QLTest.by_custom_rating().collect { |ob| + ob.name + } + + expect(Set.new(docs)).to eq(Set.new(%w[bob jane mel])) + end after(:all) do From 8716f5080e9e0211bdb2c50d46cc32c06fad538c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Couton?= Date: Mon, 18 Jul 2022 19:23:29 +0200 Subject: [PATCH 02/37] can have custom_order --- lib/couchbase-orm/n1ql.rb | 8 ++++---- spec/n1ql_spec.rb | 7 +++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/couchbase-orm/n1ql.rb b/lib/couchbase-orm/n1ql.rb index 6556eb30..d859c8be 100644 --- a/lib/couchbase-orm/n1ql.rb +++ b/lib/couchbase-orm/n1ql.rb @@ -35,7 +35,7 @@ module ClassMethods # # ... # end # TODO: add range keys [:startkey, :endkey] - def n1ql(name, query_fn: nil, emit_key: [], **options) + def n1ql(name, query_fn: nil, emit_key: [], custom_order: nil, **options) emit_key = Array.wrap(emit_key) emit_key.each do |key| raise "unknown emit_key attribute for n1ql :#{name}, emit_key: :#{key}" if key && @attributes[key].nil? @@ -50,7 +50,7 @@ def n1ql(name, query_fn: nil, emit_key: [], **options) singleton_class.__send__(:define_method, name) do |**opts, &result_modifier| opts = options.merge(opts).reverse_merge(scan_consistency: :request_plus) values = convert_values(opts.delete(:key)) - current_query = run_query(method_opts[:emit_key], values, query_fn, **opts.except(:include_docs)) + current_query = run_query(method_opts[:emit_key], values, query_fn, custom_order: custom_order, **opts.except(:include_docs)) if result_modifier opts[:include_docs] = true @@ -113,14 +113,14 @@ def build_limit(limit) limit ? "limit #{limit}" : "" end - def run_query(keys, values, query_fn, descending: false, limit: nil, **options) + def run_query(keys, values, query_fn, custom_order: nil, descending: false, limit: nil, **options) if query_fn result = query_fn.call(bucket, values, cluster) N1qlProxy.new(result) else bucket_name = bucket.name where = build_where(keys, values) - order = build_order(keys, descending) + order = custom_order || build_order(keys, descending) limit = build_limit(limit) select = "raw meta().id" raise "select must be a string" unless select.is_a?(String) diff --git a/spec/n1ql_spec.rb b/spec/n1ql_spec.rb index d6d0110f..a9e5d980 100644 --- a/spec/n1ql_spec.rb +++ b/spec/n1ql_spec.rb @@ -12,6 +12,7 @@ class N1QLTest < CouchbaseOrm::Base } n1ql :by_name, emit_key: [:name, :rating] n1ql :by_rating, emit_key: :rating + n1ql :by_rating_reverse, emit_key: :rating, custom_order: "name DESC" # This generates both: # view :by_rating, emit_key: :rating # same as above @@ -60,6 +61,12 @@ class N1QLTest < CouchbaseOrm::Base expect(Set.new(docs)).to eq(Set.new(%w[bob jane])) + docs = N1QLTest.by_rating_reverse(key: 1).collect { |ob| + ob.name + } + + expect(docs).to eq(%w[jane bob]) + docs = N1QLTest.by_custom_rating().collect { |ob| ob.name } From 1c8cae67426ca6d0e2d41d1f4c1cb58bbe7f379b Mon Sep 17 00:00:00 2001 From: Damien Voreiter Date: Tue, 19 Jul 2022 12:26:58 +0200 Subject: [PATCH 03/37] don't remove nil values but add them in request --- lib/couchbase-orm/n1ql.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/couchbase-orm/n1ql.rb b/lib/couchbase-orm/n1ql.rb index d859c8be..ec28ccd9 100644 --- a/lib/couchbase-orm/n1ql.rb +++ b/lib/couchbase-orm/n1ql.rb @@ -96,8 +96,7 @@ def convert_values(values) def build_where(keys, values) where = keys.each_with_index - .reject { |key, i| values.try(:[], i).nil? } - .map { |key, i| "#{key} = #{values[i] }" } + .map { |key, i| "#{key} = #{values[i].nil? ? "IS NULL" : values[i]}" } .join(" AND ") "type=\"#{design_document}\" #{"AND " + where unless where.blank?}" end From 19523c7d4925baa47a6aaa24f9b7a8339826fddc Mon Sep 17 00:00:00 2001 From: Damien Voreiter Date: Tue, 19 Jul 2022 12:32:55 +0200 Subject: [PATCH 04/37] oupsi move = --- lib/couchbase-orm/n1ql.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/couchbase-orm/n1ql.rb b/lib/couchbase-orm/n1ql.rb index ec28ccd9..3986bc01 100644 --- a/lib/couchbase-orm/n1ql.rb +++ b/lib/couchbase-orm/n1ql.rb @@ -96,7 +96,7 @@ def convert_values(values) def build_where(keys, values) where = keys.each_with_index - .map { |key, i| "#{key} = #{values[i].nil? ? "IS NULL" : values[i]}" } + .map { |key, i| "#{key} #{values[i].nil? ? "IS NULL" : "= #{values[i]}"}" } .join(" AND ") "type=\"#{design_document}\" #{"AND " + where unless where.blank?}" end From 9c7cc567ba41d42c76d4ad589dccdd3d08dc6c9e Mon Sep 17 00:00:00 2001 From: Damien Voreiter Date: Tue, 19 Jul 2022 14:55:19 +0200 Subject: [PATCH 05/37] try to add is missing --- lib/couchbase-orm/n1ql.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/couchbase-orm/n1ql.rb b/lib/couchbase-orm/n1ql.rb index 3986bc01..c9efc0f4 100644 --- a/lib/couchbase-orm/n1ql.rb +++ b/lib/couchbase-orm/n1ql.rb @@ -96,7 +96,7 @@ def convert_values(values) def build_where(keys, values) where = keys.each_with_index - .map { |key, i| "#{key} #{values[i].nil? ? "IS NULL" : "= #{values[i]}"}" } + .map { |key, i| values[i].nil? ? "(#{key} IS NULL OR #{key} IS MISSING)" : "#{key} = #{values[i]}" } .join(" AND ") "type=\"#{design_document}\" #{"AND " + where unless where.blank?}" end From 4bfd2dda475ca1cb6c797d5d5129925a1cd42cff Mon Sep 17 00:00:00 2001 From: Damien Voreiter Date: Wed, 20 Jul 2022 15:09:11 +0200 Subject: [PATCH 06/37] re add select (wanted ?) to fix test --- lib/couchbase-orm/n1ql.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/couchbase-orm/n1ql.rb b/lib/couchbase-orm/n1ql.rb index c9efc0f4..3c0c1076 100644 --- a/lib/couchbase-orm/n1ql.rb +++ b/lib/couchbase-orm/n1ql.rb @@ -35,7 +35,7 @@ module ClassMethods # # ... # end # TODO: add range keys [:startkey, :endkey] - def n1ql(name, query_fn: nil, emit_key: [], custom_order: nil, **options) + def n1ql(name, select: nil, query_fn: nil, emit_key: [], custom_order: nil, **options) emit_key = Array.wrap(emit_key) emit_key.each do |key| raise "unknown emit_key attribute for n1ql :#{name}, emit_key: :#{key}" if key && @attributes[key].nil? @@ -50,7 +50,7 @@ def n1ql(name, query_fn: nil, emit_key: [], custom_order: nil, **options) singleton_class.__send__(:define_method, name) do |**opts, &result_modifier| opts = options.merge(opts).reverse_merge(scan_consistency: :request_plus) values = convert_values(opts.delete(:key)) - current_query = run_query(method_opts[:emit_key], values, query_fn, custom_order: custom_order, **opts.except(:include_docs)) + current_query = run_query(method_opts[:emit_key], values, query_fn, select: select, custom_order: custom_order, **opts.except(:include_docs)) if result_modifier opts[:include_docs] = true @@ -112,7 +112,7 @@ def build_limit(limit) limit ? "limit #{limit}" : "" end - def run_query(keys, values, query_fn, custom_order: nil, descending: false, limit: nil, **options) + def run_query(keys, values, query_fn, select: nil, custom_order: nil, descending: false, limit: nil, **options) if query_fn result = query_fn.call(bucket, values, cluster) N1qlProxy.new(result) @@ -121,7 +121,7 @@ def run_query(keys, values, query_fn, custom_order: nil, descending: false, limi where = build_where(keys, values) order = custom_order || build_order(keys, descending) limit = build_limit(limit) - select = "raw meta().id" + select ||= "raw meta().id" raise "select must be a string" unless select.is_a?(String) n1ql_query = "select #{select} from `#{bucket_name}` where #{where} order by #{order} #{limit}" result = cluster.query(n1ql_query, Couchbase::Options::Query.new(**options)) From 30534a77b3a0f234a17eac6ad822a24f2020f3ab Mon Sep 17 00:00:00 2001 From: Damien Voreiter Date: Wed, 20 Jul 2022 15:48:37 +0200 Subject: [PATCH 07/37] try to remove values empty but keep nil values --- lib/couchbase-orm/n1ql.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/couchbase-orm/n1ql.rb b/lib/couchbase-orm/n1ql.rb index 3c0c1076..ec180e64 100644 --- a/lib/couchbase-orm/n1ql.rb +++ b/lib/couchbase-orm/n1ql.rb @@ -96,6 +96,7 @@ def convert_values(values) def build_where(keys, values) where = keys.each_with_index + .reject { |_key, i| values[i].empty? } .map { |key, i| values[i].nil? ? "(#{key} IS NULL OR #{key} IS MISSING)" : "#{key} = #{values[i]}" } .join(" AND ") "type=\"#{design_document}\" #{"AND " + where unless where.blank?}" From 8d885da3dd09aab818e755f537ab60a4068d0422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Couton?= Date: Fri, 22 Jul 2022 17:44:36 +0200 Subject: [PATCH 08/37] have a read_fn --- lib/couchbase-orm/base.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/couchbase-orm/base.rb b/lib/couchbase-orm/base.rb index 185d7ad6..ac624457 100644 --- a/lib/couchbase-orm/base.rb +++ b/lib/couchbase-orm/base.rb @@ -199,7 +199,10 @@ def id=(value) end def read_attribute(attr_name) - @__attributes__[attr_name] + read_fn = self.class.attributes[attr_name][:read_fn] + value = @__attributes__[attr_name] + value = read_fn.call(value) if read_fn + value end alias_method :[], :read_attribute From 87c8331094aed2d3d05e9e773511a39a534764a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Couton?= Date: Mon, 25 Jul 2022 13:02:01 +0200 Subject: [PATCH 09/37] add example with include_docs false --- spec/n1ql_spec.rb | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/spec/n1ql_spec.rb b/spec/n1ql_spec.rb index a9e5d980..e8da605b 100644 --- a/spec/n1ql_spec.rb +++ b/spec/n1ql_spec.rb @@ -13,6 +13,7 @@ class N1QLTest < CouchbaseOrm::Base n1ql :by_name, emit_key: [:name, :rating] n1ql :by_rating, emit_key: :rating n1ql :by_rating_reverse, emit_key: :rating, custom_order: "name DESC" + n1ql :by_rating_without_docs, emit_key: :rating, include_docs: false # This generates both: # view :by_rating, emit_key: :rating # same as above @@ -50,10 +51,10 @@ class N1QLTest < CouchbaseOrm::Base end it "should return matching results" do - N1QLTest.create! name: :bob, rating: :awesome - N1QLTest.create! name: :jane, rating: :awesome - N1QLTest.create! name: :greg, rating: :bad - N1QLTest.create! name: :mel, rating: :good + inst_bob = N1QLTest.create! name: :bob, rating: :awesome + inst_jane = N1QLTest.create! name: :jane, rating: :awesome + inst_greg = N1QLTest.create! name: :greg, rating: :bad + inst_mel = N1QLTest.create! name: :mel, rating: :good docs = N1QLTest.find_by_rating(1).collect { |ob| ob.name @@ -73,6 +74,10 @@ class N1QLTest < CouchbaseOrm::Base expect(Set.new(docs)).to eq(Set.new(%w[bob jane mel])) + + docs = N1QLTest.by_rating_without_docs(key: 1) + + expect(Set.new(docs)).to eq(Set.new([inst_bob.id, inst_jane.id])) end after(:all) do From 9806edf7b7a6a610319599f901344c0f4840221a Mon Sep 17 00:00:00 2001 From: Damien Voreiter Date: Mon, 25 Jul 2022 14:20:39 +0200 Subject: [PATCH 10/37] add column_names & attribute_names to orm --- lib/couchbase-orm/base.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/couchbase-orm/base.rb b/lib/couchbase-orm/base.rb index ac624457..bc0fa3a4 100644 --- a/lib/couchbase-orm/base.rb +++ b/lib/couchbase-orm/base.rb @@ -96,6 +96,14 @@ def attribute(*names, **options) end end + def column_names + @attributes.map { |col| col[0].to_s } + end + + def attribute_names + @attributes.map { |col| col[0].to_s } + end + def attributes @attributes ||= {} end From 04cfdea3578debff548acc0d0a9147f54e631a70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Couton?= Date: Mon, 25 Jul 2022 18:17:22 +0200 Subject: [PATCH 11/37] add options in params of query_fn --- lib/couchbase-orm/n1ql.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/couchbase-orm/n1ql.rb b/lib/couchbase-orm/n1ql.rb index ec180e64..7b2127b0 100644 --- a/lib/couchbase-orm/n1ql.rb +++ b/lib/couchbase-orm/n1ql.rb @@ -115,7 +115,7 @@ def build_limit(limit) def run_query(keys, values, query_fn, select: nil, custom_order: nil, descending: false, limit: nil, **options) if query_fn - result = query_fn.call(bucket, values, cluster) + result = query_fn.call(bucket, values, cluster, Couchbase::Options::Query.new(**options)) N1qlProxy.new(result) else bucket_name = bucket.name @@ -125,6 +125,7 @@ def run_query(keys, values, query_fn, select: nil, custom_order: nil, descending select ||= "raw meta().id" raise "select must be a string" unless select.is_a?(String) n1ql_query = "select #{select} from `#{bucket_name}` where #{where} order by #{order} #{limit}" + puts options result = cluster.query(n1ql_query, Couchbase::Options::Query.new(**options)) CouchbaseOrm.logger.debug "N1QL query: #{n1ql_query} return #{result.rows.to_a.length} rows" N1qlProxy.new(result) From 6914cb962f3d17ecb81cff3801cd1d52385313df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Couton?= Date: Thu, 28 Jul 2022 17:17:55 +0200 Subject: [PATCH 12/37] clean --- lib/couchbase-orm/n1ql.rb | 1 - lib/couchbase-orm/railtie.rb | 3 --- 2 files changed, 4 deletions(-) diff --git a/lib/couchbase-orm/n1ql.rb b/lib/couchbase-orm/n1ql.rb index 7b2127b0..dedc48bf 100644 --- a/lib/couchbase-orm/n1ql.rb +++ b/lib/couchbase-orm/n1ql.rb @@ -125,7 +125,6 @@ def run_query(keys, values, query_fn, select: nil, custom_order: nil, descending select ||= "raw meta().id" raise "select must be a string" unless select.is_a?(String) n1ql_query = "select #{select} from `#{bucket_name}` where #{where} order by #{order} #{limit}" - puts options result = cluster.query(n1ql_query, Couchbase::Options::Query.new(**options)) CouchbaseOrm.logger.debug "N1QL query: #{n1ql_query} return #{result.rows.to_a.length} rows" N1qlProxy.new(result) diff --git a/lib/couchbase-orm/railtie.rb b/lib/couchbase-orm/railtie.rb index c1071aef..8c6257dd 100644 --- a/lib/couchbase-orm/railtie.rb +++ b/lib/couchbase-orm/railtie.rb @@ -23,11 +23,8 @@ module Rails #:nodoc: module Couchbase #:nodoc: class Railtie < Rails::Railtie #:nodoc: - - puts "Railtie < Rails::Railtie" config.couchbase2 = ActiveSupport::OrderedOptions.new config.couchbase2.ensure_design_documents = true - puts "config.couchbase.ensure_design_documents : #{config.couchbase2.ensure_design_documents}" # Maping of rescued exceptions to HTTP responses # From 99a2ca8efb2694ba7d9bb73913b755f52547f46e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Couton?= Date: Thu, 28 Jul 2022 17:41:47 +0200 Subject: [PATCH 13/37] fix n1ql --- lib/couchbase-orm/n1ql.rb | 2 +- spec/base_spec.rb | 206 ++++++++++++++++++++------------------ spec/n1ql_spec.rb | 16 ++- 3 files changed, 121 insertions(+), 103 deletions(-) diff --git a/lib/couchbase-orm/n1ql.rb b/lib/couchbase-orm/n1ql.rb index dedc48bf..a71a5d63 100644 --- a/lib/couchbase-orm/n1ql.rb +++ b/lib/couchbase-orm/n1ql.rb @@ -96,7 +96,7 @@ def convert_values(values) def build_where(keys, values) where = keys.each_with_index - .reject { |_key, i| values[i].empty? } + .reject { |_key, i| i > values.count } .map { |key, i| values[i].nil? ? "(#{key} IS NULL OR #{key} IS MISSING)" : "#{key} = #{values[i]}" } .join(" AND ") "type=\"#{design_document}\" #{"AND " + where unless where.blank?}" diff --git a/spec/base_spec.rb b/spec/base_spec.rb index 0a898c39..4acf03f5 100644 --- a/spec/base_spec.rb +++ b/spec/base_spec.rb @@ -2,130 +2,136 @@ require File.expand_path("../support", __FILE__) - class BaseTest < CouchbaseOrm::Base - attribute :name, :job + extend ActiveModel::Naming + attribute :name, :job + attribute(:prescribing_date, type: String, read_fn: proc { |value| encode_date(value) }) # timestamp without time zone, + + class << self + def encode_date(value) + puts "DateTime.strptime(value, '%Q') : #{DateTime.strptime(value, '%Y-%m-%d') if value.present? && value.is_a?(String) && value.length == 10}" + return DateTime.strptime(value, '%Y-%m-%d') if value.present? && value.is_a?(String) && value.length == 10 + return DateTime.strptime(value, '%Y-%m-%d %H:%M:%s %z') if value.present? && value.is_a?(String) + value + end + end end class CompareTest < CouchbaseOrm::Base - attribute :age + attribute :age end +class TypeNamedTest < CouchbaseOrm::Base + attribute :count +end describe CouchbaseOrm::Base do - it "should be comparable to other objects" do - base = BaseTest.create!(name: 'joe') - base2 = BaseTest.create!(name: 'joe') - base3 = BaseTest.create!(ActiveSupport::HashWithIndifferentAccess.new(name: 'joe')) - - expect(base).to eq(base) - expect(base).to be(base) - expect(base).not_to eq(base2) - - same_base = BaseTest.find(base.id) - expect(base).to eq(same_base) - expect(base).not_to be(same_base) - expect(base2).not_to eq(same_base) - - base.delete - base2.delete - base3.delete - end + it "should be comparable to other objects" do + base = BaseTest.create!(name: 'joe', prescribing_date: Time.now) - it "should load database responses" do - base = BaseTest.create!(name: 'joe') - resp = BaseTest.bucket.default_collection.get(base.id) + puts "base.prescribing_date #{base.prescribing_date} #{base.prescribing_date.class}" + base.reload - base_loaded = BaseTest.new(resp, id: base.id) + puts "base.prescribing_date #{base.prescribing_date} #{base.prescribing_date.class}" - expect(base_loaded.id).to eq(base.id) - expect(base_loaded).to eq(base) - expect(base_loaded).not_to be(base) + base.update({ prescribing_date: '2022-07-01' }) - base.destroy - end + end - it "should not load objects if there is a type mismatch" do - base = BaseTest.create!(name: 'joe') + it "should load database responses" do + base = BaseTest.create!(name: 'joe') + resp = BaseTest.bucket.default_collection.get(base.id) - expect { CompareTest.find_by_id(base.id) }.to raise_error(CouchbaseOrm::Error::TypeMismatchError) + base_loaded = BaseTest.new(resp, id: base.id) - base.destroy - end + expect(base_loaded.id).to eq(base.id) + expect(base_loaded).to eq(base) + expect(base_loaded).not_to be(base) - it "should support serialisation" do - base = BaseTest.create!(name: 'joe') + base.destroy + end - base_id = base.id - expect(base.to_json).to eq({name: 'joe', job: nil, id: base_id}.to_json) - expect(base.to_json(only: :name)).to eq({name: 'joe'}.to_json) + it "should not load objects if there is a type mismatch" do + base = BaseTest.create!(name: 'joe') - base.destroy - end + expect { CompareTest.find_by_id(base.id) }.to raise_error(CouchbaseOrm::Error::TypeMismatchError) - it "should support dirty attributes" do - begin - base = BaseTest.new - expect(base.changes.empty?).to be(true) - expect(base.previous_changes.empty?).to be(true) - - base.name = 'change' - expect(base.changes.empty?).to be(false) - - base = BaseTest.new({name: 'bob'}) - expect(base.changes.empty?).to be(false) - expect(base.previous_changes.empty?).to be(true) - - # A saved model should have no changes - base = BaseTest.create!(name: 'joe') - expect(base.changes.empty?).to be(true) - expect(base.previous_changes.empty?).to be(false) - - # Attributes are copied from the existing model - base = BaseTest.new(base) - expect(base.changes.empty?).to be(false) - expect(base.previous_changes.empty?).to be(true) - ensure - base.destroy if base.id - end - end + base.destroy + end - it "should try to load a model with nothing but an ID" do - begin - base = BaseTest.create!(name: 'joe') - obj = CouchbaseOrm.try_load(base.id) - expect(obj).to eq(base) - ensure - base.destroy - end - end + it "should support serialisation" do + base = BaseTest.create!(name: 'joe') - it "should try to load a model with nothing but single-multiple ID" do - begin - bases = [BaseTest.create!(name: 'joe')] - objs = CouchbaseOrm.try_load(bases.map(&:id)) - expect(objs).to match_array(bases) - ensure - bases.each(&:destroy) - end - end + base_id = base.id + expect(base.to_json).to eq({ name: 'joe', job: nil, id: base_id }.to_json) + expect(base.to_json(only: :name)).to eq({ name: 'joe' }.to_json) - it "should try to load a model with nothing but multiple ID" do - begin - bases = [BaseTest.create!(name: 'joe'), CompareTest.create!(age: 12)] - objs = CouchbaseOrm.try_load(bases.map(&:id)) - expect(objs).to match_array(bases) - ensure - bases.each(&:destroy) - end - end + base.destroy + end - describe BaseTest do - it_behaves_like "ActiveModel" - end + it "should support dirty attributes" do + begin + base = BaseTest.new + expect(base.changes.empty?).to be(true) + expect(base.previous_changes.empty?).to be(true) + + base.name = 'change' + expect(base.changes.empty?).to be(false) + + base = BaseTest.new({ name: 'bob' }) + expect(base.changes.empty?).to be(false) + expect(base.previous_changes.empty?).to be(true) + + # A saved model should have no changes + base = BaseTest.create!(name: 'joe') + expect(base.changes.empty?).to be(true) + expect(base.previous_changes.empty?).to be(false) - describe CompareTest do - it_behaves_like "ActiveModel" + # Attributes are copied from the existing model + base = BaseTest.new(base) + expect(base.changes.empty?).to be(false) + expect(base.previous_changes.empty?).to be(true) + ensure + base.destroy if base.id end + end + + it "should try to load a model with nothing but an ID" do + begin + base = BaseTest.create!(name: 'joe') + obj = CouchbaseOrm.try_load(base.id) + expect(obj).to eq(base) + ensure + base.destroy + end + end + + it "should try to load a model with nothing but single-multiple ID" do + begin + bases = [BaseTest.create!(name: 'joe')] + objs = CouchbaseOrm.try_load(bases.map(&:id)) + expect(objs).to match_array(bases) + ensure + bases.each(&:destroy) + end + end + + it "should try to load a model with nothing but multiple ID" do + begin + bases = [BaseTest.create!(name: 'joe'), CompareTest.create!(age: 12)] + objs = CouchbaseOrm.try_load(bases.map(&:id)) + expect(objs).to match_array(bases) + ensure + bases.each(&:destroy) + end + end + + describe BaseTest do + it_behaves_like "ActiveModel" + end + + describe CompareTest do + it_behaves_like "ActiveModel" + end end diff --git a/spec/n1ql_spec.rb b/spec/n1ql_spec.rb index e8da605b..59f4e587 100644 --- a/spec/n1ql_spec.rb +++ b/spec/n1ql_spec.rb @@ -4,6 +4,7 @@ class N1QLTest < CouchbaseOrm::Base attribute :name, type: String + attribute :lastname, type: String enum rating: [:awesome, :good, :okay, :bad], default: :okay n1ql :all @@ -11,6 +12,7 @@ class N1QLTest < CouchbaseOrm::Base cluster.query("SELECT raw meta().id FROM `#{bucket.name}` WHERE rating IN [1, 2] ORDER BY name ASC") } n1ql :by_name, emit_key: [:name, :rating] + n1ql :by_lastname, emit_key: [:lastname] n1ql :by_rating, emit_key: :rating n1ql :by_rating_reverse, emit_key: :rating, custom_order: "name DESC" n1ql :by_rating_without_docs, emit_key: :rating, include_docs: false @@ -53,8 +55,8 @@ class N1QLTest < CouchbaseOrm::Base it "should return matching results" do inst_bob = N1QLTest.create! name: :bob, rating: :awesome inst_jane = N1QLTest.create! name: :jane, rating: :awesome - inst_greg = N1QLTest.create! name: :greg, rating: :bad - inst_mel = N1QLTest.create! name: :mel, rating: :good + N1QLTest.create! name: :greg, rating: :bad + N1QLTest.create! name: :mel, rating: :good docs = N1QLTest.find_by_rating(1).collect { |ob| ob.name @@ -80,6 +82,16 @@ class N1QLTest < CouchbaseOrm::Base expect(Set.new(docs)).to eq(Set.new([inst_bob.id, inst_jane.id])) end + it "should return matching results with nil usage" do + N1QLTest.create! name: :bob, lastname: nil + N1QLTest.create! name: :jane, lastname: "dupond" + + docs = N1QLTest.by_lastname(key: [nil]).collect { |ob| + ob.name + } + expect(docs).to eq(%w[bob]) + end + after(:all) do N1QLTest.all.to_a.each(&:destroy) end From 203f4691404ca50d1a09a953b2ae0bfd92d2587b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Couton?= Date: Thu, 28 Jul 2022 17:41:55 +0200 Subject: [PATCH 14/37] fix n1ql --- spec/base_spec.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/base_spec.rb b/spec/base_spec.rb index 4acf03f5..cfb45078 100644 --- a/spec/base_spec.rb +++ b/spec/base_spec.rb @@ -9,7 +9,6 @@ class BaseTest < CouchbaseOrm::Base class << self def encode_date(value) - puts "DateTime.strptime(value, '%Q') : #{DateTime.strptime(value, '%Y-%m-%d') if value.present? && value.is_a?(String) && value.length == 10}" return DateTime.strptime(value, '%Y-%m-%d') if value.present? && value.is_a?(String) && value.length == 10 return DateTime.strptime(value, '%Y-%m-%d %H:%M:%s %z') if value.present? && value.is_a?(String) value From 3bbd3e62a506540a5db2310093c6d8e4bd4e87cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Couton?= Date: Thu, 28 Jul 2022 18:17:28 +0200 Subject: [PATCH 15/37] fix n1ql --- lib/couchbase-orm/n1ql.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/couchbase-orm/n1ql.rb b/lib/couchbase-orm/n1ql.rb index a71a5d63..381253c9 100644 --- a/lib/couchbase-orm/n1ql.rb +++ b/lib/couchbase-orm/n1ql.rb @@ -83,8 +83,10 @@ def self.#{find_method}(#{attr}) private def convert_values(values) - Array.wrap(values).compact.map do |v| - if v.class == String + Array.wrap(values).map do |v| + if v.nil? + nil + elsif v.class == String "'#{N1ql.sanitize(v)}'" elsif v.class == Date || v.class == Time "'#{v.iso8601(3)}'" @@ -96,7 +98,7 @@ def convert_values(values) def build_where(keys, values) where = keys.each_with_index - .reject { |_key, i| i > values.count } + .select { |_key, i| i < values.count } .map { |key, i| values[i].nil? ? "(#{key} IS NULL OR #{key} IS MISSING)" : "#{key} = #{values[i]}" } .join(" AND ") "type=\"#{design_document}\" #{"AND " + where unless where.blank?}" From 6337bd18b04a11aceafe8ab8e376441ed3633be0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Couton?= Date: Thu, 28 Jul 2022 18:17:54 +0200 Subject: [PATCH 16/37] clean --- lib/couchbase-orm/railtie.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/couchbase-orm/railtie.rb b/lib/couchbase-orm/railtie.rb index 8c6257dd..192e8191 100644 --- a/lib/couchbase-orm/railtie.rb +++ b/lib/couchbase-orm/railtie.rb @@ -49,7 +49,6 @@ def self.rescue_responses config_file = Rails.root.join('config', 'couchbase.yml') if config_file.file? && config = YAML.load(ERB.new(File.read(config_file)).result)[Rails.env] - puts config ::CouchbaseOrm::Connection.options = config.deep_symbolize_keys end end From 95227c1847192ac91e0bfbcbc87e47c38ef8df07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Couton?= Date: Thu, 28 Jul 2022 18:25:44 +0200 Subject: [PATCH 17/37] fix test --- spec/base_spec.rb | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/spec/base_spec.rb b/spec/base_spec.rb index cfb45078..e9ad6c8e 100644 --- a/spec/base_spec.rb +++ b/spec/base_spec.rb @@ -3,7 +3,6 @@ require File.expand_path("../support", __FILE__) class BaseTest < CouchbaseOrm::Base - extend ActiveModel::Naming attribute :name, :job attribute(:prescribing_date, type: String, read_fn: proc { |value| encode_date(value) }) # timestamp without time zone, @@ -28,12 +27,7 @@ class TypeNamedTest < CouchbaseOrm::Base describe CouchbaseOrm::Base do it "should be comparable to other objects" do base = BaseTest.create!(name: 'joe', prescribing_date: Time.now) - - puts "base.prescribing_date #{base.prescribing_date} #{base.prescribing_date.class}" base.reload - - puts "base.prescribing_date #{base.prescribing_date} #{base.prescribing_date.class}" - base.update({ prescribing_date: '2022-07-01' }) end @@ -63,7 +57,7 @@ class TypeNamedTest < CouchbaseOrm::Base base = BaseTest.create!(name: 'joe') base_id = base.id - expect(base.to_json).to eq({ name: 'joe', job: nil, id: base_id }.to_json) + expect(base.to_json).to eq({ name: 'joe', job: nil, prescribing_date:nil, id: base_id }.to_json) expect(base.to_json(only: :name)).to eq({ name: 'joe' }.to_json) base.destroy From 08a139a63c7945f5ca6c39c32cac7f5c5faef802 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Couton?= Date: Thu, 28 Jul 2022 18:26:39 +0200 Subject: [PATCH 18/37] fix test --- spec/n1ql_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/n1ql_spec.rb b/spec/n1ql_spec.rb index 59f4e587..d0d72386 100644 --- a/spec/n1ql_spec.rb +++ b/spec/n1ql_spec.rb @@ -8,7 +8,7 @@ class N1QLTest < CouchbaseOrm::Base enum rating: [:awesome, :good, :okay, :bad], default: :okay n1ql :all - n1ql :by_custom_rating, query_fn: proc { |bucket, _values, cluster| + n1ql :by_custom_rating, emit_key: :rating, query_fn: proc { |bucket, _values, cluster| cluster.query("SELECT raw meta().id FROM `#{bucket.name}` WHERE rating IN [1, 2] ORDER BY name ASC") } n1ql :by_name, emit_key: [:name, :rating] From db72a7d242fa322142cfdc49dff8bf2e2c0ba248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Couton?= Date: Thu, 28 Jul 2022 18:31:36 +0200 Subject: [PATCH 19/37] fix test --- spec/n1ql_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/n1ql_spec.rb b/spec/n1ql_spec.rb index d0d72386..6e924a8f 100644 --- a/spec/n1ql_spec.rb +++ b/spec/n1ql_spec.rb @@ -8,7 +8,7 @@ class N1QLTest < CouchbaseOrm::Base enum rating: [:awesome, :good, :okay, :bad], default: :okay n1ql :all - n1ql :by_custom_rating, emit_key: :rating, query_fn: proc { |bucket, _values, cluster| + n1ql :by_custom_rating, emit_key: [:name, :rating], query_fn: proc { |bucket, _values, cluster| cluster.query("SELECT raw meta().id FROM `#{bucket.name}` WHERE rating IN [1, 2] ORDER BY name ASC") } n1ql :by_name, emit_key: [:name, :rating] From b2e111350b92e5038a1a667f43a3435d590b63bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Couton?= Date: Thu, 28 Jul 2022 18:41:09 +0200 Subject: [PATCH 20/37] try fix ci --- ci/run_couchbase.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci/run_couchbase.sh b/ci/run_couchbase.sh index 912938bf..7f460d11 100755 --- a/ci/run_couchbase.sh +++ b/ci/run_couchbase.sh @@ -18,3 +18,5 @@ sleep 5 sleep 1 /opt/couchbase/bin/couchbase-cli user-manage -c 127.0.0.1:8091 -u admin -p password --set --rbac-username $USER --rbac-password $PASSWORD --rbac-name "Auto Tester" --roles admin --auth-domain local curl http://admin:password@localhost:8093/query/service -d "statement=CREATE INDEX \`default_type\` ON \`$BUCKET\`(\`type\`)" +curl http://admin:password@localhost:8093/query/service -d "statement=CREATE INDEX \`default_type\` ON \`$BUCKET\`(\`rating\`)" +curl http://admin:password@localhost:8093/query/service -d "statement=CREATE INDEX \`default_type\` ON \`$BUCKET\`(\`name\`)" From fb59dae0720396b9ba0b7d5b3d804d199e744e7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Couton?= Date: Thu, 28 Jul 2022 18:45:16 +0200 Subject: [PATCH 21/37] try fix ci --- ci/run_couchbase.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/run_couchbase.sh b/ci/run_couchbase.sh index 7f460d11..870d0b32 100755 --- a/ci/run_couchbase.sh +++ b/ci/run_couchbase.sh @@ -18,5 +18,5 @@ sleep 5 sleep 1 /opt/couchbase/bin/couchbase-cli user-manage -c 127.0.0.1:8091 -u admin -p password --set --rbac-username $USER --rbac-password $PASSWORD --rbac-name "Auto Tester" --roles admin --auth-domain local curl http://admin:password@localhost:8093/query/service -d "statement=CREATE INDEX \`default_type\` ON \`$BUCKET\`(\`type\`)" -curl http://admin:password@localhost:8093/query/service -d "statement=CREATE INDEX \`default_type\` ON \`$BUCKET\`(\`rating\`)" -curl http://admin:password@localhost:8093/query/service -d "statement=CREATE INDEX \`default_type\` ON \`$BUCKET\`(\`name\`)" +curl http://admin:password@localhost:8093/query/service -d "statement=CREATE INDEX \`default_rating\` ON \`$BUCKET\`(\`rating\`)" +curl http://admin:password@localhost:8093/query/service -d "statement=CREATE INDEX \`default_name\` ON \`$BUCKET\`(\`name\`)" From d480a6b57d23be5b99dc87644ceb9def2a651ceb Mon Sep 17 00:00:00 2001 From: Gauthier Monserand Date: Fri, 9 Sep 2022 08:20:53 +0200 Subject: [PATCH 22/37] update .gitignore to ignore .rbenv-vars --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a0219977..92b0381f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.sw? +.rbenv-vars .DS_Store coverage rdoc From 3aa996ba8d76db719c97d710353cee45d1dbffb2 Mon Sep 17 00:00:00 2001 From: Damien Voreiter <78789202+DamienVoreiter@users.noreply.github.com> Date: Tue, 13 Sep 2022 09:34:20 +0200 Subject: [PATCH 23/37] Update lib/couchbase-orm/connection.rb --- lib/couchbase-orm/connection.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/couchbase-orm/connection.rb b/lib/couchbase-orm/connection.rb index 944f70e0..cda9dc76 100644 --- a/lib/couchbase-orm/connection.rb +++ b/lib/couchbase-orm/connection.rb @@ -1,4 +1,3 @@ - require 'couchbase' module CouchbaseOrm From 093ac904dda8c9230ff867ec23cbd19aefb8e86b Mon Sep 17 00:00:00 2001 From: xdm67x Date: Mon, 29 Aug 2022 15:02:33 +0200 Subject: [PATCH 24/37] Encryption for CBLite3 --- lib/couchbase-orm.rb | 1 + lib/couchbase-orm/base.rb | 3 +++ lib/couchbase-orm/encrypt.rb | 29 +++++++++++++++++++++++++++++ lib/couchbase-orm/persistence.rb | 7 +++++++ 4 files changed, 40 insertions(+) create mode 100644 lib/couchbase-orm/encrypt.rb diff --git a/lib/couchbase-orm.rb b/lib/couchbase-orm.rb index 4c6257a6..f33e215b 100644 --- a/lib/couchbase-orm.rb +++ b/lib/couchbase-orm.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true, encoding: ASCII-8BIT module CouchbaseOrm + autoload :Encrypt, 'couchbase-orm/encrypt' autoload :Error, 'couchbase-orm/error' autoload :Connection, 'couchbase-orm/connection' autoload :IdGenerator, 'couchbase-orm/id_generator' diff --git a/lib/couchbase-orm/base.rb b/lib/couchbase-orm/base.rb index 185d7ad6..93291470 100644 --- a/lib/couchbase-orm/base.rb +++ b/lib/couchbase-orm/base.rb @@ -33,6 +33,7 @@ class Base include Associations include Views include N1ql + include Encrypt extend Join extend Enum @@ -181,6 +182,8 @@ def initialize(model = nil, ignore_doc_type: false, **attributes) super(attributes) end + decrypted_attributes(@__attributes__) + yield self if block_given? run_callbacks :initialize diff --git a/lib/couchbase-orm/encrypt.rb b/lib/couchbase-orm/encrypt.rb new file mode 100644 index 00000000..492cdd8a --- /dev/null +++ b/lib/couchbase-orm/encrypt.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true, encoding: ASCII-8BIT + +module CouchbaseOrm + module Encrypt + TANKER_ENCRYPTED_PREFIX = 'tanker_encrypted_' + + def encrypted_attributes(attributes) + attributes.clone.each do |key, value| + if key.to_s.starts_with?(TANKER_ENCRYPTED_PREFIX) + attributes["encrypted$#{key}"] = { + alg: 'CB_MOBILE_CUSTOM', + ciphertext: value + } + attributes.delete(key) + end + end + end + + def decrypted_attributes(attributes) + attributes.clone.each do |key, value| + key = key.to_s + if key.starts_with?('encrypted$') + attributes.delete(key) + attributes[key.gsub('encrypted$', '')] = value[:ciphertext] + end + end + end + end +end \ No newline at end of file diff --git a/lib/couchbase-orm/persistence.rb b/lib/couchbase-orm/persistence.rb index 6e30e820..c06264a7 100644 --- a/lib/couchbase-orm/persistence.rb +++ b/lib/couchbase-orm/persistence.rb @@ -7,6 +7,7 @@ module CouchbaseOrm module Persistence extend ActiveSupport::Concern + include Encrypt module ClassMethods def create(attributes = nil, &block) @@ -209,6 +210,8 @@ def reload @__metadata__.key = key @__metadata__.cas = resp.cas + decrypted_attributes(@__attributes__) + reset_associations clear_changes_information self @@ -236,6 +239,8 @@ def _update_record(with_cas: false, **options) @__attributes__[:type] = self.class.design_document @__attributes__.delete(:id) + encrypted_attributes(@__attributes__) + _id = @__metadata__.key options[:cas] = @__metadata__.cas if with_cas CouchbaseOrm.logger.debug { "_update_record - replace #{_id} #{@__attributes__.to_s.truncate(200)}" } @@ -259,6 +264,8 @@ def _create_record(**options) @__attributes__[:type] = self.class.design_document @__attributes__.delete(:id) + encrypted_attributes(@__attributes__) + _id = @id || self.class.uuid_generator.next(self) CouchbaseOrm.logger.debug { "_create_record - Upsert #{_id} #{@__attributes__.to_s.truncate(200)}" } #resp = self.class.collection.add(_id, @__attributes__, **options) From 84d5785d479f14e52e7e8a63d490cdd6133f99f3 Mon Sep 17 00:00:00 2001 From: Adrien Jeser Date: Mon, 12 Sep 2022 10:24:50 +0200 Subject: [PATCH 25/37] Rename fn --- lib/couchbase-orm/base.rb | 2 +- lib/couchbase-orm/encrypt.rb | 6 +++--- lib/couchbase-orm/persistence.rb | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/couchbase-orm/base.rb b/lib/couchbase-orm/base.rb index 93291470..28a4552f 100644 --- a/lib/couchbase-orm/base.rb +++ b/lib/couchbase-orm/base.rb @@ -182,7 +182,7 @@ def initialize(model = nil, ignore_doc_type: false, **attributes) super(attributes) end - decrypted_attributes(@__attributes__) + decode_encrypted_attributes(@__attributes__) yield self if block_given? diff --git a/lib/couchbase-orm/encrypt.rb b/lib/couchbase-orm/encrypt.rb index 492cdd8a..d7c4a9f6 100644 --- a/lib/couchbase-orm/encrypt.rb +++ b/lib/couchbase-orm/encrypt.rb @@ -4,7 +4,7 @@ module CouchbaseOrm module Encrypt TANKER_ENCRYPTED_PREFIX = 'tanker_encrypted_' - def encrypted_attributes(attributes) + def encode_encrypted_attributes(attributes) attributes.clone.each do |key, value| if key.to_s.starts_with?(TANKER_ENCRYPTED_PREFIX) attributes["encrypted$#{key}"] = { @@ -16,7 +16,7 @@ def encrypted_attributes(attributes) end end - def decrypted_attributes(attributes) + def decode_encrypted_attributes(attributes) attributes.clone.each do |key, value| key = key.to_s if key.starts_with?('encrypted$') @@ -26,4 +26,4 @@ def decrypted_attributes(attributes) end end end -end \ No newline at end of file +end diff --git a/lib/couchbase-orm/persistence.rb b/lib/couchbase-orm/persistence.rb index c06264a7..5bcaa8a1 100644 --- a/lib/couchbase-orm/persistence.rb +++ b/lib/couchbase-orm/persistence.rb @@ -210,7 +210,7 @@ def reload @__metadata__.key = key @__metadata__.cas = resp.cas - decrypted_attributes(@__attributes__) + decode_encrypted_attributes(@__attributes__) reset_associations clear_changes_information @@ -239,7 +239,7 @@ def _update_record(with_cas: false, **options) @__attributes__[:type] = self.class.design_document @__attributes__.delete(:id) - encrypted_attributes(@__attributes__) + encode_encrypted_attributes(@__attributes__) _id = @__metadata__.key options[:cas] = @__metadata__.cas if with_cas @@ -264,7 +264,7 @@ def _create_record(**options) @__attributes__[:type] = self.class.design_document @__attributes__.delete(:id) - encrypted_attributes(@__attributes__) + encode_encrypted_attributes(@__attributes__) _id = @id || self.class.uuid_generator.next(self) CouchbaseOrm.logger.debug { "_create_record - Upsert #{_id} #{@__attributes__.to_s.truncate(200)}" } From 7595d2c70f20736a67333db0c48cd532e7dbf9d7 Mon Sep 17 00:00:00 2001 From: Damien Voreiter Date: Wed, 14 Sep 2022 18:33:49 +0200 Subject: [PATCH 26/37] try fix ci starts_with -> start_with --- lib/couchbase-orm/encrypt.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/couchbase-orm/encrypt.rb b/lib/couchbase-orm/encrypt.rb index d7c4a9f6..e842700b 100644 --- a/lib/couchbase-orm/encrypt.rb +++ b/lib/couchbase-orm/encrypt.rb @@ -6,7 +6,7 @@ module Encrypt def encode_encrypted_attributes(attributes) attributes.clone.each do |key, value| - if key.to_s.starts_with?(TANKER_ENCRYPTED_PREFIX) + if key.to_s.start_with?(TANKER_ENCRYPTED_PREFIX) attributes["encrypted$#{key}"] = { alg: 'CB_MOBILE_CUSTOM', ciphertext: value @@ -19,7 +19,7 @@ def encode_encrypted_attributes(attributes) def decode_encrypted_attributes(attributes) attributes.clone.each do |key, value| key = key.to_s - if key.starts_with?('encrypted$') + if key.start_with?('encrypted$') attributes.delete(key) attributes[key.gsub('encrypted$', '')] = value[:ciphertext] end From ab479ab38689a4e384360893d00ba6e570dcfb73 Mon Sep 17 00:00:00 2001 From: Damien Voreiter Date: Thu, 15 Sep 2022 16:34:17 +0200 Subject: [PATCH 27/37] remove select --- lib/couchbase-orm/n1ql.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/couchbase-orm/n1ql.rb b/lib/couchbase-orm/n1ql.rb index ee70aedc..1d3364c2 100644 --- a/lib/couchbase-orm/n1ql.rb +++ b/lib/couchbase-orm/n1ql.rb @@ -35,7 +35,7 @@ module ClassMethods # # ... # end # TODO: add range keys [:startkey, :endkey] - def n1ql(name, select: nil, query_fn: nil, emit_key: [], custom_order: nil, **options) + def n1ql(name, query_fn: nil, emit_key: [], custom_order: nil, **options) emit_key = Array.wrap(emit_key) emit_key.each do |key| raise "unknown emit_key attribute for n1ql :#{name}, emit_key: :#{key}" if key && !attribute_names.include?(key.to_s) @@ -50,7 +50,7 @@ def n1ql(name, select: nil, query_fn: nil, emit_key: [], custom_order: nil, **op singleton_class.__send__(:define_method, name) do |**opts, &result_modifier| opts = options.merge(opts).reverse_merge(scan_consistency: :request_plus) values = convert_values(method_opts[:emit_key], opts.delete(:key)) if opts[:key] - current_query = run_query(method_opts[:emit_key], values, query_fn, select: select, custom_order: custom_order, **opts.except(:include_docs)) + current_query = run_query(method_opts[:emit_key], values, query_fn, custom_order: custom_order, **opts.except(:include_docs)) if result_modifier opts[:include_docs] = true current_query.results &result_modifier @@ -121,7 +121,7 @@ def build_limit(limit) limit ? "limit #{limit}" : "" end - def run_query(keys, values, query_fn, select: nil, custom_order: nil, descending: false, limit: nil, **options) + def run_query(keys, values, query_fn, custom_order: nil, descending: false, limit: nil, **options) if query_fn result = query_fn.call(bucket, values, cluster, Couchbase::Options::Query.new(**options)) N1qlProxy.new(result) @@ -130,9 +130,8 @@ def run_query(keys, values, query_fn, select: nil, custom_order: nil, descending where = build_where(keys, values) order = custom_order || build_order(keys, descending) limit = build_limit(limit) - select ||= "raw meta().id" raise "select must be a string" unless select.is_a?(String) - n1ql_query = "select #{select} from `#{bucket_name}` where #{where} order by #{order} #{limit}" + n1ql_query = "select raw meta().id from `#{bucket_name}` where #{where} order by #{order} #{limit}" result = cluster.query(n1ql_query, Couchbase::Options::Query.new(**options)) CouchbaseOrm.logger.debug "N1QL query: #{n1ql_query} return #{result.rows.to_a.length} rows" N1qlProxy.new(result) From bdcd2073f03d6f2f5833b58c5803b5ad395b5c30 Mon Sep 17 00:00:00 2001 From: Damien Voreiter Date: Thu, 15 Sep 2022 16:36:20 +0200 Subject: [PATCH 28/37] revert useless --- lib/couchbase-orm/n1ql.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/couchbase-orm/n1ql.rb b/lib/couchbase-orm/n1ql.rb index 1d3364c2..c0e44fca 100644 --- a/lib/couchbase-orm/n1ql.rb +++ b/lib/couchbase-orm/n1ql.rb @@ -123,17 +123,15 @@ def build_limit(limit) def run_query(keys, values, query_fn, custom_order: nil, descending: false, limit: nil, **options) if query_fn - result = query_fn.call(bucket, values, cluster, Couchbase::Options::Query.new(**options)) - N1qlProxy.new(result) + N1qlProxy.new(query_fn.call(bucket, values, cluster, Couchbase::Options::Query.new(**options))) else bucket_name = bucket.name where = build_where(keys, values) order = custom_order || build_order(keys, descending) limit = build_limit(limit) - raise "select must be a string" unless select.is_a?(String) n1ql_query = "select raw meta().id from `#{bucket_name}` where #{where} order by #{order} #{limit}" result = cluster.query(n1ql_query, Couchbase::Options::Query.new(**options)) - CouchbaseOrm.logger.debug "N1QL query: #{n1ql_query} return #{result.rows.to_a.length} rows" + CouchbaseOrm.logger.debug { "N1QL query: #{n1ql_query} return #{result.rows.to_a.length} rows" } N1qlProxy.new(result) end end From 3f9c24e0fb172295f8648b04f7c9542ceb0568a5 Mon Sep 17 00:00:00 2001 From: Damien Voreiter <78789202+DamienVoreiter@users.noreply.github.com> Date: Fri, 16 Sep 2022 14:48:51 +0200 Subject: [PATCH 29/37] Update .gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8646a68a..63dba921 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ *.sw? -.rbenv-vars .DS_Store .rbenv-vars coverage From 67f81fb0453bf7bdb733dbccd88199b918053087 Mon Sep 17 00:00:00 2001 From: Damien Voreiter Date: Fri, 16 Sep 2022 16:45:11 +0200 Subject: [PATCH 30/37] revert a modify test --- spec/base_spec.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/spec/base_spec.rb b/spec/base_spec.rb index 52dc9100..a6c70c04 100644 --- a/spec/base_spec.rb +++ b/spec/base_spec.rb @@ -34,7 +34,21 @@ class TypeNamedTest < CouchbaseOrm::Base base = BaseTest.create!(name: 'joe', prescribing_date: Time.now) base.reload base.update({ prescribing_date: '2022-07-01' }) + base2 = BaseTest.create!(name: 'joe') + base3 = BaseTest.create!(ActiveSupport::HashWithIndifferentAccess.new(name: 'joe')) + expect(base).to eq(base) + expect(base).to be(base) + expect(base).not_to eq(base2) + + same_base = BaseTest.find(base.id) + expect(base).to eq(same_base) + expect(base).not_to be(same_base) + expect(base2).not_to eq(same_base) + + base.delete + base2.delete + base3.delete end it "should be inspectable" do From cbabc75c359ea29ea7eeece6390711d7310e5891 Mon Sep 17 00:00:00 2001 From: Damien Voreiter Date: Fri, 16 Sep 2022 16:50:44 +0200 Subject: [PATCH 31/37] 2 to 4 spaces --- spec/base_spec.rb | 313 +++++++++++++++++++++++----------------------- 1 file changed, 156 insertions(+), 157 deletions(-) diff --git a/spec/base_spec.rb b/spec/base_spec.rb index a6c70c04..daf3e623 100644 --- a/spec/base_spec.rb +++ b/spec/base_spec.rb @@ -3,21 +3,21 @@ require File.expand_path("../support", __FILE__) class BaseTest < CouchbaseOrm::Base - attribute :name, :string - attribute :job, :string - attribute(:prescribing_date, type: String, read_fn: proc { |value| encode_date(value) }) # timestamp without time zone, - - class << self - def encode_date(value) - return DateTime.strptime(value, '%Y-%m-%d') if value.present? && value.is_a?(String) && value.length == 10 - return DateTime.strptime(value, '%Y-%m-%d %H:%M:%s %z') if value.present? && value.is_a?(String) - value + attribute :name, :string + attribute :job, :string + attribute(:prescribing_date, type: String, read_fn: proc { |value| encode_date(value) }) # timestamp without time zone, + + class << self + def encode_date(value) + return DateTime.strptime(value, '%Y-%m-%d') if value.present? && value.is_a?(String) && value.length == 10 + return DateTime.strptime(value, '%Y-%m-%d %H:%M:%s %z') if value.present? && value.is_a?(String) + value + end end - end end class CompareTest < CouchbaseOrm::Base - attribute :age, :integer + attribute :age, :integer end class TimestampTest < CouchbaseOrm::Base @@ -25,161 +25,160 @@ class TimestampTest < CouchbaseOrm::Base end class TypeNamedTest < CouchbaseOrm::Base - attribute :count + attribute :count end - describe CouchbaseOrm::Base do - it "should be comparable to other objects" do - base = BaseTest.create!(name: 'joe', prescribing_date: Time.now) - base.reload - base.update({ prescribing_date: '2022-07-01' }) - base2 = BaseTest.create!(name: 'joe') - base3 = BaseTest.create!(ActiveSupport::HashWithIndifferentAccess.new(name: 'joe')) - - expect(base).to eq(base) - expect(base).to be(base) - expect(base).not_to eq(base2) - - same_base = BaseTest.find(base.id) - expect(base).to eq(same_base) - expect(base).not_to be(same_base) - expect(base2).not_to eq(same_base) - - base.delete - base2.delete - base3.delete - end - - it "should be inspectable" do - base = BaseTest.create!(name: 'joe') - expect(base.inspect).to eq("#") - end - - it "should load database responses" do - base = BaseTest.create!(name: 'joe') - resp = BaseTest.bucket.default_collection.get(base.id) - - base_loaded = BaseTest.new(resp, id: base.id) - - expect(base_loaded.id).to eq(base.id) - expect(base_loaded).to eq(base) - expect(base_loaded).not_to be(base) - - base.destroy - end - - it "should not load objects if there is a type mismatch" do - base = BaseTest.create!(name: 'joe') - - expect { CompareTest.find_by_id(base.id) }.to raise_error(CouchbaseOrm::Error::TypeMismatchError) - - base.destroy - end - - it "should support serialisation" do - base = BaseTest.create!(name: 'joe') - - base_id = base.id - expect(base.to_json).to eq({ id: base_id, name: 'joe', job: nil, prescribing_date:nil }.to_json) - expect(base.to_json(only: :name)).to eq({ name: 'joe' }.to_json) - - base.destroy - end - - it "should support dirty attributes" do - begin - base = BaseTest.new - expect(base.changes.empty?).to be(true) - expect(base.previous_changes.empty?).to be(true) - - base.name = 'change' - expect(base.changes.empty?).to be(false) - - # Attributes are set by key - base = BaseTest.new - base[:name] = 'bob' - expect(base.changes.empty?).to be(false) - - # Attributes are set by initializer from hash - base = BaseTest.new({ name: 'bob' }) - expect(base.changes.empty?).to be(false) - expect(base.previous_changes.empty?).to be(true) - - # A saved model should have no changes - base = BaseTest.create!(name: 'joe') - expect(base.changes.empty?).to be(true) - expect(base.previous_changes.empty?).to be(false) - - # Attributes are copied from the existing model - base = BaseTest.new(base) - expect(base.changes.empty?).to be(false) - expect(base.previous_changes.empty?).to be(true) - ensure - base.destroy if base.id + it "should be comparable to other objects" do + base = BaseTest.create!(name: 'joe', prescribing_date: Time.now) + base.reload + base.update({ prescribing_date: '2022-07-01' }) + base2 = BaseTest.create!(name: 'joe') + base3 = BaseTest.create!(ActiveSupport::HashWithIndifferentAccess.new(name: 'joe')) + + expect(base).to eq(base) + expect(base).to be(base) + expect(base).not_to eq(base2) + + same_base = BaseTest.find(base.id) + expect(base).to eq(same_base) + expect(base).not_to be(same_base) + expect(base2).not_to eq(same_base) + + base.delete + base2.delete + base3.delete end - end - it "should try to load a model with nothing but an ID" do - begin - base = BaseTest.create!(name: 'joe') - obj = CouchbaseOrm.try_load(base.id) - expect(obj).to eq(base) - ensure - base.destroy + it "should be inspectable" do + base = BaseTest.create!(name: 'joe') + expect(base.inspect).to eq("#") + end + + it "should load database responses" do + base = BaseTest.create!(name: 'joe') + resp = BaseTest.bucket.default_collection.get(base.id) + + base_loaded = BaseTest.new(resp, id: base.id) + + expect(base_loaded.id).to eq(base.id) + expect(base_loaded).to eq(base) + expect(base_loaded).not_to be(base) + + base.destroy + end + + it "should not load objects if there is a type mismatch" do + base = BaseTest.create!(name: 'joe') + + expect { CompareTest.find_by_id(base.id) }.to raise_error(CouchbaseOrm::Error::TypeMismatchError) + + base.destroy + end + + it "should support serialisation" do + base = BaseTest.create!(name: 'joe') + + base_id = base.id + expect(base.to_json).to eq({ id: base_id, name: 'joe', job: nil, prescribing_date: nil }.to_json) + expect(base.to_json(only: :name)).to eq({ name: 'joe' }.to_json) + + base.destroy end - end - it "should try to load a model with nothing but single-multiple ID" do - begin - bases = [BaseTest.create!(name: 'joe')] - objs = CouchbaseOrm.try_load(bases.map(&:id)) - expect(objs).to match_array(bases) + it "should support dirty attributes" do + begin + base = BaseTest.new + expect(base.changes.empty?).to be(true) + expect(base.previous_changes.empty?).to be(true) + + base.name = 'change' + expect(base.changes.empty?).to be(false) + + # Attributes are set by key + base = BaseTest.new + base[:name] = 'bob' + expect(base.changes.empty?).to be(false) + + # Attributes are set by initializer from hash + base = BaseTest.new({ name: 'bob' }) + expect(base.changes.empty?).to be(false) + expect(base.previous_changes.empty?).to be(true) + + # A saved model should have no changes + base = BaseTest.create!(name: 'joe') + expect(base.changes.empty?).to be(true) + expect(base.previous_changes.empty?).to be(false) + + # Attributes are copied from the existing model + base = BaseTest.new(base) + expect(base.changes.empty?).to be(false) + expect(base.previous_changes.empty?).to be(true) + ensure + base.destroy if base.id + end + end + + it "should try to load a model with nothing but an ID" do + begin + base = BaseTest.create!(name: 'joe') + obj = CouchbaseOrm.try_load(base.id) + expect(obj).to eq(base) + ensure + base.destroy + end + end + + it "should try to load a model with nothing but single-multiple ID" do + begin + bases = [BaseTest.create!(name: 'joe')] + objs = CouchbaseOrm.try_load(bases.map(&:id)) + expect(objs).to match_array(bases) + ensure + bases.each(&:destroy) + end + end + + it "should try to load a model with nothing but multiple ID" do + begin + bases = [BaseTest.create!(name: 'joe'), CompareTest.create!(age: 12)] + objs = CouchbaseOrm.try_load(bases.map(&:id)) + expect(objs).to match_array(bases) + ensure + bases.each(&:destroy) + end + end + + it "should set the attribute on creation" do + base = BaseTest.create!(name: 'joe') + expect(base.name).to eq('joe') ensure - bases.each(&:destroy) + base.destroy end - end - it "should try to load a model with nothing but multiple ID" do - begin - bases = [BaseTest.create!(name: 'joe'), CompareTest.create!(age: 12)] - objs = CouchbaseOrm.try_load(bases.map(&:id)) - expect(objs).to match_array(bases) + it "should support getting the attribute by key" do + base = BaseTest.create!(name: 'joe') + expect(base[:name]).to eq('joe') ensure - bases.each(&:destroy) - end - end - - it "should set the attribute on creation" do - base = BaseTest.create!(name: 'joe') - expect(base.name).to eq('joe') - ensure - base.destroy - end - - it "should support getting the attribute by key" do - base = BaseTest.create!(name: 'joe') - expect(base[:name]).to eq('joe') - ensure - base.destroy - end - - if ActiveModel::VERSION::MAJOR >= 6 - it "should have timestamp attributes for create in model" do - expect(TimestampTest.timestamp_attributes_for_create_in_model).to eq(["created_at"]) - end - end - - it "should generate a timestamp on creation" do - base = TimestampTest.create!() - expect(base.created_at).to be_a(Time) - end - - describe BaseTest do - it_behaves_like "ActiveModel" - end - - describe CompareTest do - it_behaves_like "ActiveModel" - end + base.destroy + end + + if ActiveModel::VERSION::MAJOR >= 6 + it "should have timestamp attributes for create in model" do + expect(TimestampTest.timestamp_attributes_for_create_in_model).to eq(["created_at"]) + end + end + + it "should generate a timestamp on creation" do + base = TimestampTest.create!() + expect(base.created_at).to be_a(Time) + end + + describe BaseTest do + it_behaves_like "ActiveModel" + end + + describe CompareTest do + it_behaves_like "ActiveModel" + end end From d876005dd2aa4156ef1b5411106647b9a15d1cbd Mon Sep 17 00:00:00 2001 From: Damien Voreiter Date: Fri, 16 Sep 2022 16:55:36 +0200 Subject: [PATCH 32/37] split tests --- spec/n1ql_spec.rb | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/spec/n1ql_spec.rb b/spec/n1ql_spec.rb index 2412fb7f..af75deb9 100644 --- a/spec/n1ql_spec.rb +++ b/spec/n1ql_spec.rb @@ -59,8 +59,8 @@ class N1QLTest < CouchbaseOrm::Base end it "should return matching results" do - inst_bob = N1QLTest.create! name: :bob, rating: :awesome - inst_jane = N1QLTest.create! name: :jane, rating: :awesome + N1QLTest.create! name: :bob, rating: :awesome + N1QLTest.create! name: :jane, rating: :awesome N1QLTest.create! name: :greg, rating: :bad N1QLTest.create! name: :mel, rating: :good @@ -70,18 +70,31 @@ class N1QLTest < CouchbaseOrm::Base expect(Set.new(docs)).to eq(Set.new(%w[bob jane])) - docs = N1QLTest.by_rating_reverse(key: 1).collect { |ob| + docs = N1QLTest.by_custom_rating().collect { |ob| ob.name } - expect(docs).to eq(%w[jane bob]) + expect(Set.new(docs)).to eq(Set.new(%w[bob jane mel])) + end - docs = N1QLTest.by_custom_rating().collect { |ob| + it "should return matching results with reverse order" do + N1QLTest.create! name: :bob, rating: :awesome + N1QLTest.create! name: :jane, rating: :awesome + N1QLTest.create! name: :greg, rating: :bad + N1QLTest.create! name: :mel, rating: :good + + docs = N1QLTest.by_rating_reverse(key: 1).collect { |ob| ob.name } - expect(Set.new(docs)).to eq(Set.new(%w[bob jane mel])) + expect(docs).to eq(%w[jane bob]) + end + it "should return matching results without full documents" do + inst_bob = N1QLTest.create! name: :bob, rating: :awesome + inst_jane = N1QLTest.create! name: :jane, rating: :awesome + N1QLTest.create! name: :greg, rating: :bad + N1QLTest.create! name: :mel, rating: :good docs = N1QLTest.by_rating_without_docs(key: 1) From 3905c5713acde2b3d1721f9f9776fd035566ce71 Mon Sep 17 00:00:00 2001 From: Damien Voreiter Date: Fri, 16 Sep 2022 17:04:56 +0200 Subject: [PATCH 33/37] remove useless code --- spec/base_spec.rb | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/spec/base_spec.rb b/spec/base_spec.rb index daf3e623..a88b5aff 100644 --- a/spec/base_spec.rb +++ b/spec/base_spec.rb @@ -5,15 +5,6 @@ class BaseTest < CouchbaseOrm::Base attribute :name, :string attribute :job, :string - attribute(:prescribing_date, type: String, read_fn: proc { |value| encode_date(value) }) # timestamp without time zone, - - class << self - def encode_date(value) - return DateTime.strptime(value, '%Y-%m-%d') if value.present? && value.is_a?(String) && value.length == 10 - return DateTime.strptime(value, '%Y-%m-%d %H:%M:%s %z') if value.present? && value.is_a?(String) - value - end - end end class CompareTest < CouchbaseOrm::Base @@ -24,15 +15,9 @@ class TimestampTest < CouchbaseOrm::Base attribute :created_at, :datetime end -class TypeNamedTest < CouchbaseOrm::Base - attribute :count -end - describe CouchbaseOrm::Base do it "should be comparable to other objects" do - base = BaseTest.create!(name: 'joe', prescribing_date: Time.now) - base.reload - base.update({ prescribing_date: '2022-07-01' }) + base = BaseTest.create!(name: 'joe') base2 = BaseTest.create!(name: 'joe') base3 = BaseTest.create!(ActiveSupport::HashWithIndifferentAccess.new(name: 'joe')) @@ -80,7 +65,7 @@ class TypeNamedTest < CouchbaseOrm::Base base = BaseTest.create!(name: 'joe') base_id = base.id - expect(base.to_json).to eq({ id: base_id, name: 'joe', job: nil, prescribing_date: nil }.to_json) + expect(base.to_json).to eq({ id: base_id, name: 'joe', job: nil }.to_json) expect(base.to_json(only: :name)).to eq({ name: 'joe' }.to_json) base.destroy From 39567d8f05bc2546bd5a3944638960de146c544e Mon Sep 17 00:00:00 2001 From: Damien Voreiter Date: Mon, 19 Sep 2022 10:51:49 +0200 Subject: [PATCH 34/37] fix master --- lib/couchbase-orm/base.rb | 2 +- lib/couchbase-orm/persistence.rb | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/couchbase-orm/base.rb b/lib/couchbase-orm/base.rb index b15a31e8..8f77c1a7 100644 --- a/lib/couchbase-orm/base.rb +++ b/lib/couchbase-orm/base.rb @@ -227,7 +227,7 @@ def initialize(model = nil, ignore_doc_type: false, **attributes) super(attributes) end - decode_encrypted_attributes(@__attributes__) + decode_encrypted_attributes(attributes) yield self if block_given? diff --git a/lib/couchbase-orm/persistence.rb b/lib/couchbase-orm/persistence.rb index 6a398fc2..fa0dbdc9 100644 --- a/lib/couchbase-orm/persistence.rb +++ b/lib/couchbase-orm/persistence.rb @@ -210,7 +210,7 @@ def reload assign_attributes(resp.content.except("id")) # API return a nil id @__metadata__.cas = resp.cas - decode_encrypted_attributes(@__attributes__) + decode_encrypted_attributes(attributes) reset_associations clear_changes_information @@ -240,7 +240,7 @@ def _update_record(*_args, with_cas: false, **options) run_callbacks :update do run_callbacks :save do - encode_encrypted_attributes(@__attributes__) + encode_encrypted_attributes(attributes) options[:cas] = @__metadata__.cas if with_cas CouchbaseOrm.logger.debug { "_update_record - replace #{id} #{serialized_attributes.to_s.truncate(200)}" } resp = self.class.collection.replace(id, serialized_attributes.except(:id).merge(type: self.class.design_document), Couchbase::Options::Replace.new(**options)) @@ -261,7 +261,7 @@ def _create_record(*_args, **options) assign_attributes(id: self.class.uuid_generator.next(self)) unless self.id CouchbaseOrm.logger.debug { "_create_record - Upsert #{id} #{serialized_attributes.to_s.truncate(200)}" } - encode_encrypted_attributes(@__attributes__) + encode_encrypted_attributes(attributes) resp = self.class.collection.upsert(self.id, serialized_attributes.except(:id).merge(type: self.class.design_document), Couchbase::Options::Upsert.new(**options)) # Ensure the model is up to date From 3e4162831f2dfeaa37604c180feda6bdc150c4a4 Mon Sep 17 00:00:00 2001 From: Damien Voreiter Date: Mon, 19 Sep 2022 11:19:06 +0200 Subject: [PATCH 35/37] oups revert encrypt part --- lib/couchbase-orm.rb | 1 - lib/couchbase-orm/base.rb | 4 ---- lib/couchbase-orm/encrypt.rb | 29 ----------------------------- lib/couchbase-orm/persistence.rb | 6 ------ 4 files changed, 40 deletions(-) delete mode 100644 lib/couchbase-orm/encrypt.rb diff --git a/lib/couchbase-orm.rb b/lib/couchbase-orm.rb index fcabde57..c91f87ec 100644 --- a/lib/couchbase-orm.rb +++ b/lib/couchbase-orm.rb @@ -7,7 +7,6 @@ end module CouchbaseOrm - autoload :Encrypt, 'couchbase-orm/encrypt' autoload :Error, 'couchbase-orm/error' autoload :Connection, 'couchbase-orm/connection' autoload :IdGenerator, 'couchbase-orm/id_generator' diff --git a/lib/couchbase-orm/base.rb b/lib/couchbase-orm/base.rb index 8f77c1a7..ea298952 100644 --- a/lib/couchbase-orm/base.rb +++ b/lib/couchbase-orm/base.rb @@ -120,7 +120,6 @@ class Base include Associations include Views include N1ql - include Encrypt extend Join extend Enum @@ -226,9 +225,6 @@ def initialize(model = nil, ignore_doc_type: false, **attributes) clear_changes_information super(attributes) end - - decode_encrypted_attributes(attributes) - yield self if block_given? run_callbacks :initialize diff --git a/lib/couchbase-orm/encrypt.rb b/lib/couchbase-orm/encrypt.rb deleted file mode 100644 index e842700b..00000000 --- a/lib/couchbase-orm/encrypt.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true, encoding: ASCII-8BIT - -module CouchbaseOrm - module Encrypt - TANKER_ENCRYPTED_PREFIX = 'tanker_encrypted_' - - def encode_encrypted_attributes(attributes) - attributes.clone.each do |key, value| - if key.to_s.start_with?(TANKER_ENCRYPTED_PREFIX) - attributes["encrypted$#{key}"] = { - alg: 'CB_MOBILE_CUSTOM', - ciphertext: value - } - attributes.delete(key) - end - end - end - - def decode_encrypted_attributes(attributes) - attributes.clone.each do |key, value| - key = key.to_s - if key.start_with?('encrypted$') - attributes.delete(key) - attributes[key.gsub('encrypted$', '')] = value[:ciphertext] - end - end - end - end -end diff --git a/lib/couchbase-orm/persistence.rb b/lib/couchbase-orm/persistence.rb index fa0dbdc9..10219c08 100644 --- a/lib/couchbase-orm/persistence.rb +++ b/lib/couchbase-orm/persistence.rb @@ -7,8 +7,6 @@ module CouchbaseOrm module Persistence extend ActiveSupport::Concern - include Encrypt - included do attribute :id, :string end @@ -210,8 +208,6 @@ def reload assign_attributes(resp.content.except("id")) # API return a nil id @__metadata__.cas = resp.cas - decode_encrypted_attributes(attributes) - reset_associations clear_changes_information self @@ -240,7 +236,6 @@ def _update_record(*_args, with_cas: false, **options) run_callbacks :update do run_callbacks :save do - encode_encrypted_attributes(attributes) options[:cas] = @__metadata__.cas if with_cas CouchbaseOrm.logger.debug { "_update_record - replace #{id} #{serialized_attributes.to_s.truncate(200)}" } resp = self.class.collection.replace(id, serialized_attributes.except(:id).merge(type: self.class.design_document), Couchbase::Options::Replace.new(**options)) @@ -261,7 +256,6 @@ def _create_record(*_args, **options) assign_attributes(id: self.class.uuid_generator.next(self)) unless self.id CouchbaseOrm.logger.debug { "_create_record - Upsert #{id} #{serialized_attributes.to_s.truncate(200)}" } - encode_encrypted_attributes(attributes) resp = self.class.collection.upsert(self.id, serialized_attributes.except(:id).merge(type: self.class.design_document), Couchbase::Options::Upsert.new(**options)) # Ensure the model is up to date From 149dc683e20022358ad4a67760ab577eba95ff09 Mon Sep 17 00:00:00 2001 From: Damien Voreiter Date: Mon, 19 Sep 2022 15:42:34 +0200 Subject: [PATCH 36/37] fix some tests --- spec/n1ql_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/n1ql_spec.rb b/spec/n1ql_spec.rb index 1d22cc7f..2b95adae 100644 --- a/spec/n1ql_spec.rb +++ b/spec/n1ql_spec.rb @@ -14,10 +14,10 @@ class N1QLTest < CouchbaseOrm::Base n1ql :by_name, emit_key: [:name, :rating] n1ql :by_lastname, emit_key: [:lastname] n1ql :by_rating, emit_key: :rating - n1ql :by_custom_rating, query_fn: proc { |bucket, _values, options| + n1ql :by_custom_rating, query_fn: proc { |bucket, _values, cluster, options| cluster.query("SELECT raw meta().id FROM `#{bucket.name}` where type = 'n1_ql_test' AND rating IN [1,2] ORDER BY name ASC", options) } - n1ql :by_custom_rating_values, emit_key: [:rating], query_fn: proc { |bucket, values, options| + n1ql :by_custom_rating_values, emit_key: [:rating], query_fn: proc { |bucket, values, cluster, options| cluster.query("SELECT raw meta().id FROM `#{bucket.name}` where type = 'n1_ql_test' AND rating IN #{values[0]} ORDER BY name ASC", options) } n1ql :by_rating_reverse, emit_key: :rating, custom_order: "name DESC" From 43862c6f76cd96bcacfc634544dad7ac363f311a Mon Sep 17 00:00:00 2001 From: Damien Voreiter Date: Mon, 19 Sep 2022 15:52:30 +0200 Subject: [PATCH 37/37] fix all tests --- lib/couchbase-orm/n1ql.rb | 2 +- spec/base_spec.rb | 2 +- spec/n1ql_spec.rb | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/couchbase-orm/n1ql.rb b/lib/couchbase-orm/n1ql.rb index 2d64bfab..eddb8fa2 100644 --- a/lib/couchbase-orm/n1ql.rb +++ b/lib/couchbase-orm/n1ql.rb @@ -141,7 +141,7 @@ def build_limit(limit) def run_query(keys, values, query_fn, custom_order: nil, descending: false, limit: nil, **options) if query_fn - N1qlProxy.new(query_fn.call(bucket, values, cluster, Couchbase::Options::Query.new(**options))) + N1qlProxy.new(query_fn.call(bucket, values, Couchbase::Options::Query.new(**options))) else bucket_name = bucket.name where = build_where(keys, values) diff --git a/spec/base_spec.rb b/spec/base_spec.rb index a88b5aff..3745b0e6 100644 --- a/spec/base_spec.rb +++ b/spec/base_spec.rb @@ -93,7 +93,7 @@ class TimestampTest < CouchbaseOrm::Base # A saved model should have no changes base = BaseTest.create!(name: 'joe') expect(base.changes.empty?).to be(true) - expect(base.previous_changes.empty?).to be(false) + expect(base.previous_changes.empty?).to be(true) # Attributes are copied from the existing model base = BaseTest.new(base) diff --git a/spec/n1ql_spec.rb b/spec/n1ql_spec.rb index 2b95adae..a2c904c9 100644 --- a/spec/n1ql_spec.rb +++ b/spec/n1ql_spec.rb @@ -8,16 +8,16 @@ class N1QLTest < CouchbaseOrm::Base enum rating: [:awesome, :good, :okay, :bad], default: :okay n1ql :all - n1ql :by_custom_rating, emit_key: [:name, :rating], query_fn: proc { |bucket, _values, cluster| + n1ql :by_custom_rating, emit_key: [:name, :rating], query_fn: proc { |bucket, _values| cluster.query("SELECT raw meta().id FROM `#{bucket.name}` WHERE rating IN [1, 2] ORDER BY name ASC") } - n1ql :by_name, emit_key: [:name, :rating] + n1ql :by_name, emit_key: [:name] n1ql :by_lastname, emit_key: [:lastname] n1ql :by_rating, emit_key: :rating - n1ql :by_custom_rating, query_fn: proc { |bucket, _values, cluster, options| + n1ql :by_custom_rating, query_fn: proc { |bucket, _values, options| cluster.query("SELECT raw meta().id FROM `#{bucket.name}` where type = 'n1_ql_test' AND rating IN [1,2] ORDER BY name ASC", options) } - n1ql :by_custom_rating_values, emit_key: [:rating], query_fn: proc { |bucket, values, cluster, options| + n1ql :by_custom_rating_values, emit_key: [:rating], query_fn: proc { |bucket, values, options| cluster.query("SELECT raw meta().id FROM `#{bucket.name}` where type = 'n1_ql_test' AND rating IN #{values[0]} ORDER BY name ASC", options) } n1ql :by_rating_reverse, emit_key: :rating, custom_order: "name DESC"