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>
113 lines
3.2 KiB
Ruby
113 lines
3.2 KiB
Ruby
require 'spec_helper'
|
|
|
|
class CouchAttachmentDoc
|
|
include SimplyBased::Model
|
|
property :title
|
|
has_couch_attached :receipt
|
|
end
|
|
|
|
describe 'CouchDB attachments', :couchdb_only do
|
|
describe 'low-level API' do
|
|
it 'puts and fetches an attachment' do
|
|
doc = CouchAttachmentDoc.create(title: 'test')
|
|
doc.put_couch_attachment('file.txt', 'hello world', content_type: 'text/plain')
|
|
expect(doc.fetch_couch_attachment('file.txt')).to eq 'hello world'
|
|
end
|
|
|
|
it 'lists attachment names' do
|
|
doc = CouchAttachmentDoc.create(title: 'test')
|
|
doc.put_couch_attachment('a.txt', 'a')
|
|
doc.put_couch_attachment('b.txt', 'b')
|
|
expect(doc.couch_attachment_names).to contain_exactly('a.txt', 'b.txt')
|
|
end
|
|
|
|
it 'deletes an attachment' do
|
|
doc = CouchAttachmentDoc.create(title: 'test')
|
|
doc.put_couch_attachment('file.txt', 'data')
|
|
doc.delete_couch_attachment('file.txt')
|
|
expect(doc.couch_attachment?('file.txt')).to be false
|
|
end
|
|
|
|
it 'returns nil for missing attachment' do
|
|
doc = CouchAttachmentDoc.create(title: 'test')
|
|
expect(doc.fetch_couch_attachment('missing.txt')).to be_nil
|
|
end
|
|
end
|
|
|
|
describe 'has_couch_attached macro' do
|
|
it 'defines getter and setter' do
|
|
doc = CouchAttachmentDoc.new
|
|
expect(doc).to respond_to(:receipt)
|
|
expect(doc).to respond_to(:receipt=)
|
|
end
|
|
|
|
it 'defines URL helper' do
|
|
doc = CouchAttachmentDoc.new
|
|
expect(doc).to respond_to(:receipt_url)
|
|
end
|
|
|
|
it 'defines metadata properties' do
|
|
doc = CouchAttachmentDoc.new
|
|
expect(doc).to respond_to(:receipt_content_type)
|
|
expect(doc).to respond_to(:receipt_content_type=)
|
|
expect(doc).to respond_to(:receipt_size)
|
|
expect(doc).to respond_to(:receipt_size=)
|
|
end
|
|
|
|
it 'stores and retrieves data through the setter/getter' do
|
|
doc = CouchAttachmentDoc.create(title: 'test')
|
|
doc.receipt = 'binary data here'
|
|
doc.save
|
|
|
|
reloaded = CouchAttachmentDoc.find(doc.id)
|
|
expect(reloaded.receipt).to eq 'binary data here'
|
|
end
|
|
|
|
it 'tracks content type' do
|
|
doc = CouchAttachmentDoc.create(title: 'test')
|
|
doc.receipt = 'data'
|
|
doc.save
|
|
expect(doc.receipt_content_type).to eq 'binary/octet-stream'
|
|
end
|
|
|
|
it 'tracks size' do
|
|
doc = CouchAttachmentDoc.create(title: 'test')
|
|
doc.receipt = '12345'
|
|
doc.save
|
|
expect(doc.receipt_size).to eq 5
|
|
end
|
|
|
|
it 'handles non-persisted records via pending queue' do
|
|
doc = CouchAttachmentDoc.new(title: 'draft')
|
|
doc.receipt = 'pending data'
|
|
result = doc.save
|
|
|
|
expect(result).to be_truthy
|
|
reloaded = CouchAttachmentDoc.find(doc.id)
|
|
expect(reloaded.receipt).to eq 'pending data'
|
|
end
|
|
|
|
it 'updates attachment on second assignment' do
|
|
doc = CouchAttachmentDoc.create(title: 'test')
|
|
doc.receipt = 'v1'
|
|
doc.save
|
|
|
|
doc.receipt = 'v2'
|
|
doc.save
|
|
|
|
reloaded = CouchAttachmentDoc.find(doc.id)
|
|
expect(reloaded.receipt).to eq 'v2'
|
|
end
|
|
|
|
it 'generates a URL' do
|
|
doc = CouchAttachmentDoc.create(title: 'test')
|
|
doc.receipt = 'data'
|
|
doc.save
|
|
|
|
url = doc.receipt_url
|
|
expect(url).to include(doc._id)
|
|
expect(url).to include('receipt')
|
|
end
|
|
end
|
|
end
|