forked from Mapotempo/couchbase-orm
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request Mapotempo#51 from doctolib/add_basic_relation
Add basic relation
- Loading branch information
Showing
14 changed files
with
478 additions
and
93 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
module CouchbaseOrm | ||
module Relation | ||
extend ActiveSupport::Concern | ||
|
||
class CouchbaseOrm_Relation | ||
def initialize(model:, where: where = nil, order: order = nil, limit: limit = nil, _not: _not = false) | ||
CouchbaseOrm::logger.debug "CouchbaseOrm_Relation init: #{model} where:#{where.inspect} not:#{_not.inspect} order:#{order.inspect} limit: #{limit}" | ||
@model = model | ||
@limit = limit | ||
@where = [] | ||
@order = {} | ||
@order = merge_order(**order) if order | ||
@where = merge_where(where, _not) if where | ||
CouchbaseOrm::logger.debug "- #{to_s}" | ||
end | ||
|
||
def to_s | ||
"CouchbaseOrm_Relation: #{@model} where:#{@where.inspect} order:#{@order.inspect} limit: #{@limit}" | ||
end | ||
|
||
def to_n1ql | ||
bucket_name = @model.bucket.name | ||
where = build_where | ||
order = build_order | ||
limit = build_limit | ||
"select raw meta().id from `#{bucket_name}` where #{where} order by #{order} #{limit}" | ||
end | ||
|
||
def query | ||
CouchbaseOrm::logger.debug("Query: #{self}") | ||
n1ql_query = to_n1ql | ||
result = @model.cluster.query(n1ql_query, Couchbase::Options::Query.new(scan_consistency: :request_plus)) | ||
CouchbaseOrm.logger.debug { "Relation query: #{n1ql_query} return #{result.rows.to_a.length} rows" } | ||
N1qlProxy.new(result) | ||
end | ||
|
||
def ids | ||
query.to_a | ||
end | ||
|
||
def count | ||
query.count | ||
end | ||
|
||
def to_ary | ||
query.results { |res| @model.find(res) }.to_ary | ||
end | ||
|
||
alias :to_a :to_ary | ||
|
||
delegate :each, :map, :collect, :to => :to_ary | ||
|
||
def delete_all | ||
CouchbaseOrm::logger.debug{ "Delete all: #{self}" } | ||
ids = query.to_a | ||
CouchbaseOrm::Connection.bucket.default_collection.remove_multi(ids) unless ids.empty? | ||
end | ||
|
||
def where(**conds) | ||
CouchbaseOrm_Relation.new(**initializer_arguments.merge(where: merge_where(conds))) | ||
end | ||
|
||
def not(**conds) | ||
CouchbaseOrm_Relation.new(**initializer_arguments.merge(where: merge_where(conds, _not: true))) | ||
end | ||
|
||
def order(*lorder, **horder) | ||
CouchbaseOrm_Relation.new(**initializer_arguments.merge(order: merge_order(*lorder, **horder))) | ||
end | ||
|
||
def limit(limit) | ||
CouchbaseOrm_Relation.new(**initializer_arguments.merge(limit: limit)) | ||
end | ||
|
||
def all | ||
CouchbaseOrm_Relation.new(**initializer_arguments) | ||
end | ||
|
||
private | ||
|
||
def build_limit | ||
@limit ? "limit #{@limit}" : "" | ||
end | ||
|
||
def initializer_arguments | ||
{ model: @model, order: @order, where: @where, limit: @limit } | ||
end | ||
|
||
def merge_order(*lorder, **horder) | ||
raise ArgumentError, "invalid order passed by list: #{lorder.inspect}, must be symbols" unless lorder.all? { |o| o.is_a? Symbol } | ||
raise ArgumentError, "Invalid order passed by hash: #{horder.inspect}, must be symbol -> :asc|:desc" unless horder.all? { |k, v| k.is_a?(Symbol) && [:asc, :desc].include?(v) } | ||
@order | ||
.merge(Array.wrap(lorder).map{ |o| [o, :asc] }.to_h) | ||
.merge(horder) | ||
end | ||
|
||
def merge_where(conds, _not = false) | ||
@where + (_not ? conds.to_a.map{|k,v|[k,v,:not]} : conds.to_a) | ||
end | ||
|
||
def build_order | ||
order = @order.map do |key, value| | ||
"#{key} #{value}" | ||
end.join(", ") | ||
order.empty? ? "meta().id" : order | ||
end | ||
|
||
def build_where | ||
([[:type, @model.design_document]] + @where).map do |key, value, opt| | ||
opt == :not ? | ||
@model.build_not_match(key, value) : | ||
@model.build_match(key, value) | ||
end.join(" AND ") | ||
end | ||
end | ||
|
||
module ClassMethods | ||
def where(**conds) | ||
CouchbaseOrm_Relation.new(model: self, where: conds) | ||
end | ||
|
||
def not(**conds) | ||
CouchbaseOrm_Relation.new(model: self, where: conds, _not: true) | ||
end | ||
|
||
def order(*ordersl, **ordersh) | ||
order = ordersh.reverse_merge(ordersl.map{ |o| [o, :asc] }.to_h) | ||
CouchbaseOrm_Relation.new(model: self, order: order) | ||
end | ||
|
||
def limit(limit) | ||
CouchbaseOrm_Relation.new(model: self, limit: limit) | ||
end | ||
|
||
def all | ||
CouchbaseOrm_Relation.new(model: self) | ||
end | ||
|
||
delegate :ids, :delete_all, :count, to: :all | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
module CouchbaseOrm | ||
module QueryHelper | ||
extend ActiveSupport::Concern | ||
|
||
module ClassMethods | ||
|
||
def build_match(key, value) | ||
case | ||
when value.nil? | ||
"#{key} IS NOT VALUED" | ||
when value.is_a?(Array) && value.include?(nil) | ||
"(#{build_match(key, nil)} OR #{build_match(key, value.compact)})" | ||
when value.is_a?(Array) | ||
"#{key} IN #{quote(value)}" | ||
else | ||
"#{key} = #{quote(value)}" | ||
end | ||
end | ||
|
||
def build_not_match(key, value) | ||
case | ||
when value.nil? | ||
"#{key} IS VALUED" | ||
when value.is_a?(Array) && value.include?(nil) | ||
"(#{build_not_match(key, nil)} AND #{build_not_match(key, value.compact)})" | ||
when value.is_a?(Array) | ||
"#{key} NOT IN #{quote(value)}" | ||
else | ||
"#{key} != #{quote(value)}" | ||
end | ||
end | ||
|
||
def serialize_value(key, value_before_type_cast) | ||
value = | ||
if value_before_type_cast.is_a?(Array) | ||
value_before_type_cast.map do |v| | ||
attribute_types[key.to_s].serialize(attribute_types[key.to_s].cast(v)) | ||
end | ||
else | ||
attribute_types[key.to_s].serialize(attribute_types[key.to_s].cast(value_before_type_cast)) | ||
end | ||
CouchbaseOrm.logger.debug { "convert_values: #{key} => #{value_before_type_cast.inspect} => #{value.inspect} #{value.class} #{attribute_types[key.to_s]}" } | ||
value | ||
end | ||
|
||
def quote(value) | ||
if value.is_a? String | ||
"'#{N1ql.sanitize(value)}'" | ||
elsif value.is_a? Array | ||
"[#{value.map{|v|quote(v)}.join(', ')}]" | ||
elsif value.nil? | ||
nil | ||
else | ||
N1ql.sanitize(value).to_s | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.