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:
GregandClaude Opus 4.8 committed 2026-06-20 13:58:47 -05:00
commit 86299b8827
84 files changed
+9904

No files matched your search

+146
View File
@@ -0,0 +1,146 @@
require 'spec_helper'
describe 'validations' do
context "with additional validations" do
context "with validates_inclusion_of" do
it "validate inclusion of an attribute in an array" do
category = Category.new(name: "other")
category.save.should be false
end
it "add an error message" do
category = Category.new(name: "other")
category.valid?
category.errors.full_messages.first.should match /is not included in the list/
end
it "allow blank" do
category = Category.new(name: nil)
category.should be_valid
end
end
context "with validates_format_of" do
class ValidatedUser
include SimplyBased::Model
property :name
validates_format_of :name, with: /Paul/
end
it 'validate the format and fail when not matched' do
user = ValidatedUser.new(name: "John")
user.should_not be_valid
end
it 'succeed when matched' do
user = ValidatedUser.new(name: "Paul")
user.should be_valid
end
it 'fail when empty' do
user = ValidatedUser.new(name: nil)
user.should_not be_valid
end
context "with allow_blank" do
class ValidatedBlankUser
include SimplyBased::Model
property :name
validates_format_of :name, with: /Paul/, allow_blank: true
end
it 'not fail when nil' do
user = ValidatedBlankUser.new(name: nil)
user.should be_valid
end
it 'not fail when empty string' do
user = ValidatedBlankUser.new(name: '')
user.should be_valid
end
it 'fail when not matching' do
user = ValidatedBlankUser.new(name: 'John')
user.should_not be_valid
end
it 'not fail when matching' do
user = ValidatedBlankUser.new(name: 'Paul')
user.should be_valid
end
end
end
context "with validates_uniqueness_of" do
#it "add a view on the unique attribute" do
#UniqueUser.by_name
#end
it "set an error when a different with the same instance exists" do
UniqueUser.create(name: "Host Master")
user = nil
expect{ user = UniqueUser.create(name: "Host Master") }.not_to change{ UniqueUser.count }
user.should_not be_valid
end
it "not have an error when we're the only one around" do
user = UniqueUser.create(name: "Host Master")
user.should_not be_new_record
end
it "not have an error when it's the same instance" do
user = UniqueUser.create(name: "Host Master")
user = UniqueUser.find(user.id)
user.should be_valid
end
it 'have a nice error message' do
UniqueUser.create(name: "Host Master")
user = nil
expect{ user = UniqueUser.create(name: "Host Master") }.not_to change{ UniqueUser.count }
user.errors[:name].should eq ["is already taken"]
end
it 'create a view to check with' do
UniqueUser.should respond_to :by_name
UniqueUser.by_name.send(:options)[:key].should eq :name
end
it 'not overwrite the view when a custom one already exists' do
UniqueUserWithAView.by_name.send(:options)[:key].should eq :email
end
end
context "equality" do
it "know when two objects are equal" do
user = UniqueUser.create(name: "Host Master")
other_user = UniqueUser.create(name: "The other one")
user.should_not eq other_user
end
it "not bail when comparing with non-SimplyBased objects" do
user = UniqueUser.create(name: "Host Master")
5.should_not eq user
user.should_not eq 5
end
end
context "containment" do
it "not raise an error when no name is set" do
expect{ Page.new.save }.not_to raise_error
end
it "be valid when argument is contained in specification" do
page = Page.new(categories: %w[one three])
page.should be_valid
end
it "not be valid when attribute containes value not withing specified containment" do
page = Page.new(categories: %w[one four])
page.should_not be_valid
end
end
end
end