Files
simply_based/spec/belongs_to_spec.rb
T
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

218 lines
6.6 KiB
Ruby

require 'spec_helper'
describe "BelongsTo" do
context "with associations" do
context "with belongs_to" do
it "generate a view for the association" do
#Post.respond_to?(:association_post_belongs_to_user).should be_present
Post.should respond_to :association_post_belongs_to_user
end
it "raise an error if another property with the same name already exists" do
expect {
class ::DoubleBelongsToUser
include SimplyBased::Model
property :user
belongs_to :user
end
}.to raise_error RuntimeError
end
it "add the foreign key id to the referencing object" do
user = User.create(:title => "Mr.")
post = Post.create(:user => user)
post = Post.find(post.id)
post.user_id.should eq user.id
end
it "create a property for the foreign key attribute" do
Post.properties.any?{|p| p.name.to_s == 'user_id'}.should be true
end
it "notice a change to the foreign key attribute in dirty checks" do
user = User.create!(:title => 'Prof')
post = Post.create!
post.user = user
post.should be_user_id_changed
end
it "set also the foreign key id to nil if setting the referencing object to nil" do
user = User.create(:title => "Mr.")
post = Post.create(:user => user)
post.user = nil
post.save!
post.reload.user.should be nil
post.reload.user_id.should be nil
end
it "fetch the object from the database when requested through the getter" do
user = User.create(:title => "Mr.")
post = Post.create(:user => user)
post = Post.find(post.id)
post.user.should eq user
end
it "mark the referencing object as dirty" do
user = User.create(:title => "Mr.")
post = Post.create
post.user = user
post.should be_dirty
end
it "allow assigning a different object and store the id accordingly" do
user = User.create(:title => "Mr.")
user2 = User.create(:title => "Mrs.")
post = Post.create(:user => user)
post.user = user2
post.save
post = Post.find(post.id)
post.user.id.should eq user2.id
end
it "check the class and raise an error if not matching in belongs_to setter" do
post = Post.create
expect{ post.user = 'foo' }.to raise_error(ArgumentError, 'expected User got String')
end
it 'not query for the object twice in getter' do
user = User.create(:title => "Mr.")
post = Post.create(:user => user)
post = Post.find(post.id)
expect( User ).to receive(:find).and_return "user"
post.user
expect( User ).not_to receive(:find)
post.user
end
it 'use cache in getter' do
post = Post.create
post.instance_variable_set("@user", 'foo')
post.user.should eq 'foo'
end
it "ignore the cache if force_reload is given as an option" do
user = User.create(:name => 'Dude', :title => 'Mr.')
post = Post.create(:user => user)
post.reload
post.instance_variable_set("@user", 'foo')
post.user(:force_reload => true).should_not eq 'foo'
end
it 'set cache in setter' do
post = Post.create
user = User.create :title => 'Mr.'
post.instance_variable_get("@user").should be nil
post.user = user
post.instance_variable_get("@user").should eq user
end
it "not hit the database when the id column is empty" do
expect( User ).not_to receive(:find)
post = Post.create
post.user
end
it "know when the associated object changed" do
post = Post.create(:user => User.create(:title => "Mr."))
user2 = User.create(:title => "Mr.")
post.user = user2
post.should be_user_id_changed
end
it "not be changed when an association has not changed" do
post = Post.create(:user => User.create(:title => "Mr."))
post.should_not be_user_id_changed
end
it "not be changed when assigned the same object" do
user = User.create(:title => "Mr.")
post = Post.create(:user => user)
post.user = user
post.should_not be_user_changed
end
it "not be changed after saving" do
user = User.create(:title => "Mr.")
post = Post.new
post.user = user
post.should be_user_id_changed
post.save!
post.should_not be_user_id_changed
end
it "have a proper _was value" do
user = User.create(:title => "Mr.")
user2 = User.create(:title => "Mrs.")
post = Post.new
post.save
post.user.should be nil
post.user_id.should be nil
post.user = user
#post.user_was.should be nil
post.user_id_was.should be nil
post.save
post.user = user2
#post.user_was.should eq user
post.user_id_was.should eq user.id
end
it "set the parent object on has_many association" do
# Copy from has_many, but belongs here as well
expect( User ).not_to receive(:find)
user = User.create(:title => "Mr.")
3.times {
post = Post.new
post.user = user
post.save!
}
post = user.posts.first
user.posts.first.user.should eq user
end
it "set the parent object on has_one association" do
# Taken from has_one, but belongs here as well
expect( Instance ).not_to receive(:find)
instance = Instance.create
identity = Identity.create(:instance => instance)
instance.identity.instance.should eq instance
end
it "handle a foreign_key of '' as nil" do
post = Post.create
post.user_id = ''
post.user.should be nil
end
context "with aliased associations" do
it "allow different names for the same class" do
editor = User.create(:name => 'Editor', :title => 'Dr.')
author = User.create(:name => 'author', :title => 'Dr.')
editor.id.should_not be nil
author.id.should_not be nil
doc = Document.create(:editor => editor, :author => author)
doc.save!
doc.editor_id.should eq editor.id
doc.author_id.should eq author.id
doc = Document.find(doc.id)
doc.editor.should_not be nil
doc.author.should_not be nil
doc.editor.id.should eq editor.id
doc.author.id.should eq author.id
end
end
end
end
end