Skip to content

docs(data-ops): insertion discipline, update-data how-to, master-part & make-transaction fixes#226

Merged
dimitri-yatsenko merged 6 commits into
mainfrom
docs/data-ops-crossrefs
Jul 20, 2026
Merged

docs(data-ops): insertion discipline, update-data how-to, master-part & make-transaction fixes#226
dimitri-yatsenko merged 6 commits into
mainfrom
docs/data-ops-crossrefs

Conversation

@dimitri-yatsenko

Copy link
Copy Markdown
Member

Data-operation how-to and spec improvements from the book → docs coverage review. Closes #221, #222, #223, #224, and adds the delete → garbage-collection cross-reference.

What's here

Draft for review on the docs server. No dependency on the v2.3.x code work.

… storage

Deleting rows leaves in-store objects (<blob@>/<attach@>/<object@>/<npy@>) in
place by design; add a 'Reclaiming Object Storage' note + See-also link to the
garbage-collection how-to so readers know deletes don't free external storage.
…ke-transaction fixes

- insert-data: add a 'What Not to Insert' section — don't hand-insert into
  Computed/Imported (rows come from make()/populate()); Lookup rows come from
  contents; insert parents before children; no transaction inside make(). (#221)
- add how-to/update-data.md — updates are rare/surgical; prefer delete+reinsert+
  recompute; update1() for single-row corrections. (#223)
- master-part spec: state transitive completeness — a dependency on the master is
  a dependency on all its parts. (#222)
- autopopulate spec §5.5: fix contradiction — was showing a transaction opened
  inside make(); make() is already transactional (nested raises). (#224)
- delete-data: cross-link update-data.

Closes #221, #222, #223, #224.
@dimitri-yatsenko dimitri-yatsenko added the documentation Improvements or additions to documentation label Jul 18, 2026
@dimitri-yatsenko
dimitri-yatsenko marked this pull request as ready for review July 18, 2026 19:05

@MilagrosMarin MilagrosMarin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks — most of this is solid and verified:

  • §5.5 make-transaction fix (#224) is exactly right; connection.py:523 explicitly raises "Nested connections are not supported" if start_transaction() fires during an active transaction, and _populate_one (autopopulate.py:664) opens one before make(). So the old §5.5 example would raise.
  • insert-data.md "What Not to Insert" claims all accurate (Computed/Imported reject direct inserts via _allow_insert; Lookup rows via contents; parents-before-children; no-transactions-in-make()).
  • update-data.md reads cleanly; delete+reinsert vs update1() distinction is correct, and the primary-key immutability + no-recompute caveats are right.
  • delete-data.md GC cross-reference lands accurately.
  • All CI green; all internal links resolve.

One blocker on the master-part.md §2.1 addition:

The new sentence — "Downstream tables therefore reference the master alone and can rely on the whole composite being present — they do not (and cannot) depend on the parts individually." — the (and cannot) is too strong and contradicts standard DataJoint practice:

  • The framework's own tests use downstream FK references to Part tables:
    • tests/schema_simple.py:126-> B.C
    • tests/schema_simple.py:148-> E.H
    • tests/integration/test_schema.py:251-> Schema_A.Subject
    • tests/integration/test_cascade_delete.py:326-> Master.PartA
    • tests/integration/test_cascade_delete.py:373-> Master.PartA.proj(...) (renamed-FK case)
  • The Elements ecosystem uses the same pattern widely (e.g., -> Segmentation.Mask in element-calcium-imaging).

If the intent is "you don't need to reference the parts individually because a master reference reaches the whole composite," that's a useful design guideline — but "cannot" reads as a hard rule and contradicts a legal, common, and framework-tested pattern. Would you soften along the lines of "typically reference the master alone; a foreign key to a specific Part is legal but often unnecessary when the composite is what matters" or equivalent?

Related, smaller clarification on the same paragraph:

"Because the master and its parts are inserted and deleted as one unit" — deletion is FK-CASCADE enforced, but insertion atomicity is only enforced when make() inserts both (Computed/Imported via populate()'s wrapping transaction). For Manual master-part, users can insert Master.insert1(...) without any Part rows and the RDBMS accepts it; atomic insertion is convention (with dj.conn().transaction: Master.insert1(...); Master.Part.insert(...)), not enforcement. Reads as a mechanical guarantee today — worth a brief clarification either way.

Happy to re-review once §2.1 is adjusted.

…ertion atomicity

Per review on #226: a downstream FK to a specific Part is legal and common
(framework-tested), so drop the '(and cannot)' framing. Also distinguish
make()-enforced insertion atomicity (Computed/Imported) from the convention
used for Manual master-part sets.
@dimitri-yatsenko

Copy link
Copy Markdown
Member Author

Thanks @MilagrosMarin — addressed both points in `master-part.md` §2.1 (68bf9d9):

  • Blocker: dropped the "(and cannot) depend on the parts individually" framing. The paragraph now states downstream tables typically reference the master alone, and explicitly notes a foreign key to a specific Part is legal and common in practice — just often unnecessary when the composite as a whole is what matters.
  • Clarification: insertion atomicity is now distinguished by tier — enforced for Computed/Imported (populate() wraps each make() in a transaction), convention for Manual master-part sets (with dj.conn().transaction:). Deletion cascade noted as holding in either case.

Ready for re-review.

MilagrosMarin
MilagrosMarin previously approved these changes Jul 20, 2026

@MilagrosMarin MilagrosMarin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks — both changes read exactly right. The new "typically … a foreign key to a specific part is still legal and common in practice, but often unnecessary" framing acknowledges the pattern DJ's own tests use, and the tier-split on insertion atomicity (make()-enforced for Computed/Imported vs convention for Manual) correctly separates the two cases while keeping the deletion-cascade universality intact. Approving.

Manual tables are the tier whose rows are inserted directly from outside the
pipeline — whether entered by a person (form/GUI) or loaded by an automated
ingestion tool — not 'entered by hand'. The defining property is direct
insertion vs. production by make(), not human authorship.
@dimitri-yatsenko

Copy link
Copy Markdown
Member Author

Additional fix pushed (aa4a1bc): corrected the Manual-tier definition in insert-data.md — "the tier whose rows are entered by hand" → "the tier whose rows are inserted directly, from outside the DataJoint pipeline (whether entered by hand through a form or GUI, or loaded by an automated ingestion tool)". A broader tier-definition consistency sweep across the tutorials and quick-reference tables is in #230.

MilagrosMarin
MilagrosMarin previously approved these changes Jul 20, 2026

@MilagrosMarin MilagrosMarin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Convert transaction examples and mentions in this PR's pages from the global
dj.conn().transaction to schema.connection.transaction, matching the docs-wide
sweep (#231), so the pages read consistently.
@dimitri-yatsenko

Copy link
Copy Markdown
Member Author

Converted the transaction examples/mentions in this PR's pages to the instance-based idiom (schema.connection.transaction), matching the docs-wide sweep in #231, so the pages are internally consistent. (992e44c)

MilagrosMarin
MilagrosMarin previously approved these changes Jul 20, 2026
Resolve autopopulate.md §5.5 conflict: keep this branch's fix (no explicit
transaction inside make(); populate() already wraps one), matching the section
'No Manual Transactions Inside make()'.
@dimitri-yatsenko
dimitri-yatsenko merged commit e0d7201 into main Jul 20, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants