Files
simply_based/lib/simply_based/class_methods_base.rb
GregandClaude Opus 4.8 86299b8827 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>
2026-06-20 13:58:47 -05:00

78 lines
2.5 KiB
Ruby

module SimplyBased
module ClassMethods
module Base
def get_class_from_name(klass_name)
# Try to find class from property definition
if property = _find_property(klass_name) and property.respond_to?(:options) and property.options[:class_name].present?
property.options[:class_name].constantize
else # Fall back to name guessing
base = klass_name.to_s.gsub('__','/')
base = base.classify unless base[0,1] =~ /[A-Z]/
base.constantize
end
end
def foreign_key
name.underscore.gsub('/','__').gsub('::','__') + "_id"
end
def foreign_property
name.underscore.gsub('/','__').gsub('::','__')
end
def attr_protected(*args)
@_protected_attributes ||= []
@_protected_attributes += args.to_a
end
def attr_accessible(*args)
@_accessible_attributes ||= []
@_accessible_attributes += args.to_a
end
def _find_property(name)
properties.find{|property| property.name == name}
end
# Namespace aware method of creating proper class names
def find_association_class_name(association_name)
(name.split('::')[0..-2] + [association_name.to_s.singularize.camelize]).join('::')
end
# More compatibility with active record plugins
def primary_key
'id'
end
def view(view_name, options)
# SimplyBased serves associations and lookups with N1QL, not CouchDB
# JavaScript views. Hand-written map/reduce registrations
# (:map_function / :reduce_function / :type => :custom|:raw) are no-ops —
# the association layer queries the Store directly. Structured model
# views (all_documents, find_by_*; no :map_function) still register.
return if options[:map_function] || options[:reduce_function] ||
[:custom, :raw].include?(options[:type])
super(view_name, options)
end
# Fix for paperclip > 3.5.2
def after_commit(*); end
# Get documents by ids and bulk update attributes
def bulk_update(ids, pairs)
# Bulk load documents
# Map to doc
# Filter out errors, or none founds (compact)
# Select the Couch objects
docs = database.bulk_load(ids).select{|d| d.is_a?(SimplyBased::Model)}
for doc in docs
pairs.each_pair do |k, v|
doc.send("#{k}=", v) if doc.respond_to?("#{k}=")
end
doc.save # Should become a bulk update in the future
end
end
end
end
end