Items
An item is a row in items with one item_references row per place its bytes live. The bytes
themselves stay in the resource they came from.
app/models/item.rb · app/models/reference.rb
kind |
what it is — pdf, email, image… Required |
title |
display name, usually the basename of the locator key |
parent_id |
set on an item extracted from another, such as an email attachment |
Item#analyzed_at is the maximum analyzed_at across its references, not a column.
Reference
Section titled “Reference”resource_id |
which resource holds this copy |
locator_key |
the key within it — unique per (tenant_id, resource_id) |
locator |
the type-specific address, as JSON |
version |
what the resource last reported, usually an ETag |
changed_at |
set when version changes, which also clears analyzed_at |
analysis |
the step machine’s record — see Analysis |
Reference.discover! is the sync path: it finds or creates the reference, creates an item if
there is not one yet, and calls note_version!. A changed version re-opens analysis.
Reference.record! is the export path: it attaches a reference to an item you already have,
and records source_version so stale_against? can tell whether the copy has fallen behind.
Assigned from the file extension by Kind.for_filename (app/models/kind.rb), defaulting to
file.
| kind | extensions |
|---|---|
pdf |
|
image |
png, jpg, jpeg, gif, webp, heic, tif, tiff |
text |
txt, md, rtf |
data |
csv, tsv, json, xml |
xlsx |
xlsx, xls, ods |
doc |
doc, docx, odt |
calendar |
ics |
contact |
vcf, vcard |
pkpass |
pkpass |
email |
eml |
file |
anything else |
Kind is not resource type. pdf is a kind; s3 is a type.
Children
Section titled “Children”An analyzer that declares has_children? returns child bodies from children_of, and
Analyzer::Base writes them into a Resource::Database resource keyed children before analyzing
the parent. Item::DEPTH caps the chain at 4.
Item#body_text is the union of the strings extracted from an item’s own references and its
children’s, so an email matches on a word that only appears in an attached PDF.
Item#children_ready? is true when every child has an analyzed_at. A parent that found children
returns without analyzing; the last child to finish re-enqueues it (AnalyzeItemJob#wake_parent).
Merging
Section titled “Merging”Item#merge! moves every reference off another item onto this one.
Blocking groups candidates, ProposeMergesJob writes MergeProposal rows, and the GraphQL
mutations mergeItems, settleMergeProposal and splitReference act on them.
Deletion
Section titled “Deletion”Deleting an item and deleting the bytes it points at are separate operations.
| Does | Reversible by | |
|---|---|---|
| destroy the item | drops the row, its references and its analysis | re-syncing the resource |
| delete the object | removes the bytes from the resource | nothing |
Item dependent: :destroy cascades to references and children. Nothing in the catalog deletes a
resource’s objects.
One table, cursor pagination through Page.of, OpenSearch as the query path. count(*) is avoided
on catalog-sized scopes.