Class: Textus::Store::Writer
- Inherits:
-
Object
- Object
- Textus::Store::Writer
- Defined in:
- lib/textus/store/writer.rb
Defined Under Namespace
Classes: Payload
Instance Method Summary collapse
-
#delete_envelope_from_disk(key, ctx:, if_etag: nil) ⇒ Object
Pure I/O: resolve path, validate etag, delete from disk, audit.
- #enforce_name_match!(path, meta, format) ⇒ Object
- #ensure_uid(format, meta, content, existing_uid) ⇒ Object
- #existing_uid_for(mentry, path) ⇒ Object
-
#initialize(store) ⇒ Writer
constructor
A new instance of Writer.
- #serialize_for_put(mentry:, path:, strategy:, meta:, body:, content:) ⇒ Object
-
#write_envelope_to_disk(key, mentry:, payload:, ctx:, if_etag: nil) ⇒ Object
Pure I/O: validate, serialize, etag-check, write to disk, audit.
Constructor Details
#initialize(store) ⇒ Writer
Returns a new instance of Writer.
8 9 10 11 12 |
# File 'lib/textus/store/writer.rb', line 8 def initialize(store) @store = store @manifest = store.manifest @reader = store.reader end |
Instance Method Details
#delete_envelope_from_disk(key, ctx:, if_etag: nil) ⇒ Object
Pure I/O: resolve path, validate etag, delete from disk, audit. No permission check and no event firing — those are handled by the caller (Application::Writes::Delete).
86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/textus/store/writer.rb', line 86 def delete_envelope_from_disk(key, ctx:, if_etag: nil) _, path, = @manifest.resolve(key) raise UnknownKey.new(key, suggestions: @manifest.suggestions_for(key)) unless File.exist?(path) etag_before = Etag.for_file(path) raise EtagMismatch.new(key, if_etag, etag_before) if if_etag && if_etag != etag_before File.delete(path) @store.audit_log.append( role: ctx.role, verb: "delete", key: key, etag_before: etag_before, etag_after: nil, extras: ctx.correlation_id ? { "correlation_id" => ctx.correlation_id } : nil ) end |
#enforce_name_match!(path, meta, format) ⇒ Object
72 73 74 |
# File 'lib/textus/store/writer.rb', line 72 def enforce_name_match!(path, , format) Textus::Entry.for_format(format).enforce_name_match!(path, ) end |
#ensure_uid(format, meta, content, existing_uid) ⇒ Object
68 69 70 |
# File 'lib/textus/store/writer.rb', line 68 def ensure_uid(format, , content, existing_uid) Textus::Entry.for_format(format).inject_uid(, content, existing_uid) end |
#existing_uid_for(mentry, path) ⇒ Object
58 59 60 61 62 63 64 65 66 |
# File 'lib/textus/store/writer.rb', line 58 def existing_uid_for(mentry, path) return nil unless File.exist?(path) raw = File.binread(path) parsed = Entry.for_format(mentry.format).parse(raw, path: path) Envelope.extract_uid(parsed["_meta"]) rescue StandardError nil end |
#serialize_for_put(mentry:, path:, strategy:, meta:, body:, content:) ⇒ Object
76 77 78 79 80 81 |
# File 'lib/textus/store/writer.rb', line 76 def serialize_for_put(mentry:, path:, strategy:, meta:, body:, content:) _ = strategy Textus::Entry.for_format(mentry.format).serialize_for_put( meta: , body: body, content: content, path: path, ) end |
#write_envelope_to_disk(key, mentry:, payload:, ctx:, if_etag: nil) ⇒ Object
Pure I/O: validate, serialize, etag-check, write to disk, audit. No permission check and no event firing — those are handled by the caller (Application::Writes::Put).
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/textus/store/writer.rb', line 17 def write_envelope_to_disk(key, mentry:, payload:, ctx:, if_etag: nil) _, path, = @manifest.resolve(key) = payload. || {} strategy = Entry.for_format(mentry.format) existing_uid = existing_uid_for(mentry, path) , content = ensure_uid(mentry.format, , payload.content, existing_uid) bytes, , eff_body, eff_content = serialize_for_put( mentry: mentry, path: path, strategy: strategy, meta: , body: payload.body, content: content ) enforce_name_match!(path, , mentry.format) schema = @store.schema_for(mentry.schema) if schema Entry.for_format(mentry.format).validate_against( schema, { "_meta" => , "content" => eff_content }, ) end etag_before = File.exist?(path) ? Etag.for_file(path) : nil raise EtagMismatch.new(key, if_etag, etag_before) if if_etag && (etag_before != if_etag) FileUtils.mkdir_p(File.dirname(path)) File.binwrite(path, bytes) etag_after = Etag.for_bytes(bytes) @store.audit_log.append( role: ctx.role, verb: "put", key: key, etag_before: etag_before, etag_after: etag_after, extras: ctx.correlation_id ? { "correlation_id" => ctx.correlation_id } : nil ) Envelope.build( key: key, mentry: mentry, path: path, meta: , body: eff_body, etag: etag_after, content: eff_content ) end |