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>
69 lines
2.1 KiB
Ruby
69 lines
2.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'active_support/core_ext/module/attribute_accessors'
|
|
|
|
module SimplyBased
|
|
# Global Couchbase configuration.
|
|
#
|
|
# Set once at boot:
|
|
# SimplyBased.database_url =
|
|
# "couchbase://user:pass@localhost/my_bucket?scope=_default&collection=_default"
|
|
#
|
|
# Per-request override (multi-tenant): define a top-level Current class with a
|
|
# `couch_database` attribute and set `Current.couch_database =
|
|
# SimplyBased.database_for(...)`. Block-scoped: SimplyBased.with_database(db){}.
|
|
#
|
|
# Fallback chain for Model#database:
|
|
# 1. Model's own use_database URL
|
|
# 2. Current.couch_database (request-scoped)
|
|
# 3. SimplyBased.database_url (global default)
|
|
|
|
mattr_accessor :database_url
|
|
mattr_accessor :s3_defaults
|
|
|
|
# Load S3 defaults from a YAML config file with ERB support.
|
|
def self.load_s3_config(path, env = nil)
|
|
env ||= defined?(Rails) ? Rails.env : 'development'
|
|
raw = File.read(path.to_s)
|
|
yaml = defined?(ERB) ? ERB.new(raw).result : raw
|
|
config = YAML.safe_load(yaml, permitted_classes: [], permitted_symbols: [], aliases: true) || {}
|
|
self.s3_defaults = (config[env] || {}).deep_symbolize_keys
|
|
end
|
|
|
|
# Returns a Store for the given Couchbase connection URL, cached by URL.
|
|
def self.database_for(url)
|
|
return nil unless url
|
|
databases[url] ||= Store.new(url)
|
|
end
|
|
|
|
def self.database
|
|
current_database || database_for(database_url) || fallback_database
|
|
end
|
|
|
|
def self.with_database(database)
|
|
previous = current_database
|
|
self.current_database = database
|
|
yield
|
|
ensure
|
|
self.current_database = previous
|
|
end
|
|
|
|
def self.current_database
|
|
defined?(::Current) && ::Current.respond_to?(:couch_database) ? ::Current.couch_database : nil
|
|
end
|
|
|
|
def self.current_database=(db)
|
|
::Current.couch_database = db if defined?(::Current) && ::Current.respond_to?(:couch_database=)
|
|
end
|
|
|
|
private
|
|
|
|
def self.databases
|
|
@_databases ||= {}
|
|
end
|
|
|
|
def self.fallback_database
|
|
database_for(ENV['COUCHBASE_URL'] || 'couchbase://Administrator:password@localhost/simply_based')
|
|
end
|
|
end
|