Module: Textus::Protocol::StoreEngine::Put

Defined in:
lib/textus/protocol/store_engine/put.rb

Class Method Summary collapse

Class Method Details

.append_audit(key, etag_before, envelope, deps) ⇒ Object



86
87
88
89
90
91
92
# File 'lib/textus/protocol/store_engine/put.rb', line 86

def append_audit(key, etag_before, envelope, deps)
  deps.audit_log.append(
    role: deps.call.role, verb: "put", key:,
    etag_before:, etag_after: envelope.etag,
    correlation_id: deps.call.correlation_id
  )
end

.call(key, mentry:, path:, payload:, deps:, if_etag: nil, fmt: nil) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/textus/protocol/store_engine/put.rb', line 7

def call(key, mentry:, path:, payload:, deps:, if_etag: nil, fmt: nil)
  format = fmt || mentry.format

  validate_input(key, payload, format, mentry, path)
  validate_schema(payload, mentry, deps)

  existing_env = read_existing(key, mentry, path, format, deps)
  meta, content = inject_meta(payload, existing_env, format, deps)
  bytes, eff_meta, eff_body, eff_content = serialize(payload, meta, content, path, format)

  etag_before = Pipeline.check_etag(key, path, if_etag, deps.file_system)
  deps.file_system.write(path, bytes)
  envelope = Envelope.build(
    key:, mentry:, path:,
    meta: eff_meta, body: eff_body,
    etag: Value::Etag.for_bytes(bytes),
    content: eff_content
  )

  append_audit(key, etag_before, envelope, deps)
  index_entry(key, mentry, format, eff_body, eff_content, deps)
  Pipeline.emit_event(deps, event_type: "entry.written",
                            pending_key: key, emit_key: key,
                            emit_lane: mentry.lane)
  envelope
end

.etag_for_key(deps, key) ⇒ Object



71
72
73
74
75
76
77
78
# File 'lib/textus/protocol/store_engine/put.rb', line 71

def etag_for_key(deps, key)
  path = deps.manifest.resolver.resolve(key).path
  return nil unless deps.file_system.exists?(path)

  Value::Etag.for_file(path)
rescue Textus::Error
  nil
end

.index_entry(key, mentry, format, eff_body, eff_content, deps) ⇒ Object



94
95
96
97
98
99
100
# File 'lib/textus/protocol/store_engine/put.rb', line 94

def index_entry(key, mentry, format, eff_body, eff_content, deps)
  content = eff_content ? eff_content.to_json : eff_body
  deps.entry_index.record(
    key:, lane: mentry.lane, format:,
    schema: mentry.schema, content:
  )
end

.inject_meta(payload, existing_env, format, deps) ⇒ Object



62
63
64
65
66
67
68
69
# File 'lib/textus/protocol/store_engine/put.rb', line 62

def inject_meta(payload, existing_env, format, deps)
  existing_meta = existing_env ? existing_env.meta : {}
  Infra::Store::Envelope::Meta.inject_all(
    payload.meta || {}, payload.content, existing_meta,
    format:,
    etag_for: method(:etag_for_key).curry.call(deps)
  )
end

.read_existing(key, mentry, path, format, deps) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/textus/protocol/store_engine/put.rb', line 48

def read_existing(key, mentry, path, format, deps)
  return nil unless path && deps.file_system.exists?(path)

  raw = deps.file_system.read(path)
  parsed = Format.for(format).parse(raw, path:)
  Envelope.build(
    key:, mentry:, path:,
    meta: parsed["_meta"] || {},
    body: parsed["body"] || "",
    content: parsed["content"],
    etag: Value::Etag.for_file(path)
  )
end

.serialize(payload, meta, content, path, format) ⇒ Object



80
81
82
83
84
# File 'lib/textus/protocol/store_engine/put.rb', line 80

def serialize(payload, meta, content, path, format)
  Format.for(format).serialize_for_put(
    meta:, body: payload.body, content:, path:,
  )
end

.validate_input(key, payload, format, mentry, path) ⇒ Object



34
35
36
37
38
39
40
41
42
# File 'lib/textus/protocol/store_engine/put.rb', line 34

def validate_input(key, payload, format, mentry, path)
  EntryConstraint.validate_naming!(key, mentry)
  fmt = Format.for(format)
  fmt.enforce_name_match!(path, payload.meta)
  fmt.validate_raw_entry!(
    { "_meta" => payload.meta, "content" => payload.content },
    mentry.lane,
  )
end

.validate_schema(payload, mentry, deps) ⇒ Object



44
45
46
# File 'lib/textus/protocol/store_engine/put.rb', line 44

def validate_schema(payload, mentry, deps)
  EntryConstraint.validate_schema!(payload, mentry, schemas: deps.schemas)
end