SimplyBased 0.1.0 — Couchbase-native ActiveModel ORM
A from-scratch fork of simply_couch's model layer that runs on Couchbase natively: `include SimplyBased::Model` instead of `include SimplyCouch::Model`. - SimplyBased::Store replaces the CouchDB layer: KV documents, N1QL/SQL++ finders + lazily-created GSIs, CAS mapped onto _rev. No design documents or JavaScript map/reduce — the hand-written association views become N1QL (belongs_to/has_many/has_one scalar FK; habtm via ANY ... SATISFIES + array index, or KV multi-get on the storing side). - Redis replacements on the same cluster: Counter (atomic increment/decrement), Cache (ActiveSupport::Cache::Store over KV+TTL, drop-in Rails.cache/ActiveJob), Lock (insert-if-absent + TTL + CAS-checked release). - Runs the simply_couch test suite against live Couchbase: 378/432 applicable examples green (CouchDB-mechanic specs tagged :couchdb_only and excluded). - Remaining: ancestry (tree) + embedded_in reverse-lookups (recursive/embedded N1QL) and a few pagination/lifecycle edges. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
commit
86299b8827
84 files changed
+9904
No files matched your search
@@ -0,0 +1,106 @@
|
||||
module SimplyBased
|
||||
module Model
|
||||
module View
|
||||
# A view to return model instances by searching its properties.
|
||||
# If you pass reduce => true will count instead
|
||||
#
|
||||
# example:
|
||||
# view :my_view, :key => :name
|
||||
#
|
||||
# in addition you can pass in conditions as a javascript string
|
||||
# view :my_view_only_completed, :key => :name, :conditions => 'doc.completed = true'
|
||||
# and also a results filter (the results will be run through the given proc):
|
||||
# view :my_view, :key => :name, :results_filter => lambda{|results| results.size}
|
||||
class ModelViewSpec < BaseViewSpec
|
||||
# The key simply_couch uses for class identification in CouchDB documents
|
||||
RUBY_CLASS_KEY = 'ruby_class'
|
||||
|
||||
class JavascriptGenerator
|
||||
def initialize(options, klass)
|
||||
@options = options
|
||||
@klass = klass
|
||||
end
|
||||
|
||||
def map_body(&block)
|
||||
<<-JS
|
||||
function(doc) {
|
||||
if(doc.#{RUBY_CLASS_KEY} && doc.#{RUBY_CLASS_KEY} == '#{@klass.name}'#{conditions}) {
|
||||
#{yield}
|
||||
}
|
||||
}
|
||||
JS
|
||||
end
|
||||
|
||||
def map_function
|
||||
map_body do
|
||||
"emit(#{formatted_key}, #{emit_value});"
|
||||
end
|
||||
end
|
||||
|
||||
def formatted_key(_key = nil)
|
||||
_key ||= @options[:key]
|
||||
if _key.is_a? Array
|
||||
'[' + _key.map{|key_part| formatted_key(key_part)}.join(', ') + ']'
|
||||
else
|
||||
"doc['#{_key}']"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Allow custom emit values. Raise when the specified argument is not recognized
|
||||
def emit_value
|
||||
case @options[:emit_value]
|
||||
when Symbol then "doc['#{@options[:emit_value]}']"
|
||||
when String then @options[:emit_value]
|
||||
when Numeric then @options[:emit_value]
|
||||
when NilClass then 1
|
||||
else
|
||||
raise "The emit value specified is not recognized"
|
||||
end
|
||||
end
|
||||
|
||||
def conditions
|
||||
" && (#{@options[:conditions]})" if @options[:conditions]
|
||||
end
|
||||
end
|
||||
|
||||
delegate :map_function, :map_body, :formatted_key, :to => :generator
|
||||
|
||||
def view_parameters
|
||||
_super = super
|
||||
if _super[:reduce]
|
||||
_super
|
||||
else
|
||||
{:include_docs => true, :reduce => false}.merge(_super)
|
||||
end
|
||||
end
|
||||
|
||||
def reduce_function
|
||||
"_sum"
|
||||
end
|
||||
|
||||
def process_results(results)
|
||||
processed = if count?
|
||||
results['rows'].first.try(:[], 'value') || 0
|
||||
else
|
||||
results['rows'].map {|row|
|
||||
row['doc'] || (row['id'] unless view_parameters[:include_docs])
|
||||
}.compact
|
||||
end
|
||||
super processed
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def generator
|
||||
@generator ||= JavascriptGenerator.new(@options, @klass)
|
||||
end
|
||||
|
||||
def count?
|
||||
view_parameters[:reduce]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in new issue
Block a user