typed_eav 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +207 -0
- data/README.md +271 -61
- data/app/models/typed_eav/field/base.rb +90 -33
- data/app/models/typed_eav/field/currency.rb +43 -0
- data/app/models/typed_eav/field/file.rb +1 -1
- data/app/models/typed_eav/field/image.rb +1 -1
- data/app/models/typed_eav/field/reference.rb +11 -0
- data/app/models/typed_eav/option.rb +0 -8
- data/app/models/typed_eav/section.rb +11 -5
- data/app/models/typed_eav/value.rb +95 -32
- data/db/migrate/20260430000000_add_parent_scope_to_typed_eav_partitions.rb +1 -1
- data/db/migrate/20260712000000_enforce_parent_scope_invariant.rb +54 -0
- data/db/migrate/20260816000000_use_partial_covering_scalar_indexes.rb +198 -0
- data/lib/generators/typed_eav/scaffold/templates/controllers/typed_eav_controller.rb +1 -9
- data/lib/typed_eav/bulk_read.rb +41 -9
- data/lib/typed_eav/bulk_upsert.rb +141 -0
- data/lib/typed_eav/bulk_write.rb +65 -39
- data/lib/typed_eav/config.rb +19 -21
- data/lib/typed_eav/csv_mapper.rb +1 -1
- data/lib/typed_eav/engine.rb +16 -27
- data/lib/typed_eav/entity_query.rb +42 -8
- data/lib/typed_eav/event_dispatcher.rb +21 -30
- data/lib/typed_eav/field/typed_storage.rb +48 -0
- data/lib/typed_eav/field_deletion.rb +75 -0
- data/lib/typed_eav/filter_query.rb +9 -7
- data/lib/typed_eav/has_typed_eav/instance_methods.rb +11 -8
- data/lib/typed_eav/partition.rb +8 -3
- data/lib/typed_eav/query_builder.rb +17 -27
- data/lib/typed_eav/registry.rb +7 -8
- data/lib/typed_eav/schema_portability/import_index.rb +58 -0
- data/lib/typed_eav/schema_portability.rb +22 -25
- data/lib/typed_eav/version.rb +1 -1
- data/lib/typed_eav/versioning/subscriber.rb +25 -29
- data/lib/typed_eav/versioning.rb +59 -41
- data/lib/typed_eav.rb +2 -0
- metadata +19 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 37b913418c998e4620c90efb72a0be8c93b838a2977db0347c9198b743ced2f3
|
|
4
|
+
data.tar.gz: 0a8a7f3a622712cc29b5738b8b0f4a54e3df3ffc56657277a69ebb956d3c46bf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c5bdc06300d8bb92538c93cfe23ac3afb6bed9719a29f6f7590740e6d4f56ac14998e21b4230c58fa2eed10e89dfe053af86144f3cbcf9637049c3d5b811d90b
|
|
7
|
+
data.tar.gz: 4760251616a62f91b7ed931dafc8b92a25653047cab8fcbd21dd027fe6353fdd2e7209a0629233306c69f77ec8eec08459854e8cc81443595d0b68e0503f4e8b
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,197 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
No unreleased changes.
|
|
11
|
+
|
|
12
|
+
## [0.7.0] - 2026-08-18
|
|
13
|
+
|
|
14
|
+
This release hardens TypedEAV's correctness and operational behavior, replaces
|
|
15
|
+
the highest-impact read N+1 path, and adds explicitly bounded bulk-maintenance
|
|
16
|
+
APIs. It keeps the typed-column architecture and existing semantic write path;
|
|
17
|
+
it does not claim that one storage design or batch size wins every workload.
|
|
18
|
+
|
|
19
|
+
### Highlights
|
|
20
|
+
|
|
21
|
+
- Batch partition resolution in `typed_eav_hash_for(records)` so the accepted
|
|
22
|
+
1,000-scope BulkRead shape executes three SQL statements instead of 1,002.
|
|
23
|
+
- Replace the six scalar value indexes with smaller partial-covering indexes
|
|
24
|
+
that omit irrelevant NULL cells while preserving index-only entity reads.
|
|
25
|
+
- Add an explicit reduced-semantics PostgreSQL bulk-upsert API and opt-in
|
|
26
|
+
chunked transactions for applications that knowingly prefer throughput or
|
|
27
|
+
bounded commits over the full semantic write envelope.
|
|
28
|
+
- Write `ValueVersion` audit rows in the same source transaction as each
|
|
29
|
+
`Value`, so either both persist or both roll back.
|
|
30
|
+
- Add SQL-narrowed default backfills and resumable, callback-preserving,
|
|
31
|
+
keyset-batched field deletion.
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
- Query operands are normalized and validated by the owning Field before SQL is
|
|
36
|
+
built. This keeps scalar, range, array, Currency, Reference, and text-search
|
|
37
|
+
operands aligned with write semantics; Active Record remains responsible for
|
|
38
|
+
SQL bind plumbing.
|
|
39
|
+
- `typed_eav_hash_for(records)` resolves all effective partition definitions in
|
|
40
|
+
one batched query, loads values once, and preloads field associations once.
|
|
41
|
+
Its public return shape, logical-missing behavior, partition precedence, and
|
|
42
|
+
orphan filtering are unchanged.
|
|
43
|
+
- Versioning now installs synchronous `Value` lifecycle callbacks instead of
|
|
44
|
+
writing audit rows from an internal after-commit subscriber. A failed audit
|
|
45
|
+
insert now rolls back the source mutation instead of leaving an unversioned
|
|
46
|
+
committed `Value`.
|
|
47
|
+
- The six scalar indexes now use `(field_id, value) INCLUDE (entity_id) WHERE
|
|
48
|
+
value IS NOT NULL`. The migration creates every replacement concurrently
|
|
49
|
+
before dropping its legacy index; rollback recreates legacy indexes before
|
|
50
|
+
removing replacements.
|
|
51
|
+
- Field and Section partition mutations validate their own pending tuple rather
|
|
52
|
+
than leaking scope changes through shared lookup state. Value pending state is
|
|
53
|
+
also preserved across validation and lifecycle boundaries.
|
|
54
|
+
- JSONB and TypedEAV are documented as workload-dependent storage choices.
|
|
55
|
+
Applications can own expression B-tree indexes for stable JSONB paths and GIN
|
|
56
|
+
indexes for containment; TypedEAV supplies stable typed columns and ordinary
|
|
57
|
+
per-type indexes. No final storage winner is claimed without representative
|
|
58
|
+
workload evidence.
|
|
59
|
+
|
|
60
|
+
### Added
|
|
61
|
+
|
|
62
|
+
- SQL-narrowed default backfills through an exact-host relation, while retaining
|
|
63
|
+
partition checks, batching, callbacks, validations, idempotence, versions,
|
|
64
|
+
error reporting, and Field-owned logical-missing detection across multi-cell
|
|
65
|
+
storage.
|
|
66
|
+
- `Field::Base#destroy_with_values_in_batches!`, a callback-preserving,
|
|
67
|
+
keyset-batched exact-field deletion path with locked bounded finalization. A
|
|
68
|
+
failed batch leaves the Field available for inspection and retry.
|
|
69
|
+
- `bulk_upsert_typed_eav_values`, an explicitly reduced-semantics PostgreSQL
|
|
70
|
+
upsert. Callers must pass `acknowledge_reduced_semantics: true`; values are
|
|
71
|
+
cast and validated before SQL, while host saves, persistence callbacks,
|
|
72
|
+
versioning, delete shorthand, and per-record savepoints are intentionally
|
|
73
|
+
skipped.
|
|
74
|
+
- `transaction: :chunks, chunk_size: N` for both semantic BulkWrite and the
|
|
75
|
+
reduced upsert. Completed chunks remain committed if a later chunk fails;
|
|
76
|
+
`transaction: :all` remains the default.
|
|
77
|
+
|
|
78
|
+
### Fixed
|
|
79
|
+
|
|
80
|
+
- Validate Field defaults through the same typed domain rules used by ordinary
|
|
81
|
+
writes, including range, option, reference, array, Currency, and multi-cell
|
|
82
|
+
logical-missing semantics.
|
|
83
|
+
- Fail closed when versioning callbacks are missing, duplicated, installed on
|
|
84
|
+
the wrong lifecycle kind, or configured across different connection pools.
|
|
85
|
+
- Lock and drain only the exact Field's remaining Values during deletion,
|
|
86
|
+
preserving callback/version ordering across retry and race boundaries.
|
|
87
|
+
- Keep Strong Migrations-compatible constraint validation outside a migration
|
|
88
|
+
transaction while preserving the generated-consumer migration path.
|
|
89
|
+
- Reject normalized duplicate bulk-upsert keys such as `:age` and `"age"`
|
|
90
|
+
before issuing SQL.
|
|
91
|
+
|
|
92
|
+
### Performance
|
|
93
|
+
|
|
94
|
+
- BulkRead characterization reduced the 1,002 statements observed across 1,000
|
|
95
|
+
scopes to three for the same shape. This is a statement-count result, not a
|
|
96
|
+
representative throughput claim.
|
|
97
|
+
- BulkWrite evidence remains bounded to the exercised 100- and 1,000-host
|
|
98
|
+
lanes; no 10k/100k throughput or universal batch-size claim is made.
|
|
99
|
+
- Representative PostgreSQL 15, 16, and 18 migration/catalog checks passed for
|
|
100
|
+
the partial-covering indexes. PostgreSQL 17 planner and benchmark timings are
|
|
101
|
+
retained as co-tenant diagnostic evidence rather than portable latency
|
|
102
|
+
promises.
|
|
103
|
+
|
|
104
|
+
### Reliability
|
|
105
|
+
|
|
106
|
+
- ValueVersion rows are written in the source transaction, preserving atomic
|
|
107
|
+
rollback with the Value mutation and avoiding a false after-commit rollback
|
|
108
|
+
assumption.
|
|
109
|
+
- The parent-scope check-constraint migration validates existing rows before
|
|
110
|
+
adding constraints with Strong Migrations-compatible nontransactional DDL;
|
|
111
|
+
the unchanged consumer migration canary passed.
|
|
112
|
+
|
|
113
|
+
### Upgrade notes
|
|
114
|
+
|
|
115
|
+
- Copy/install the latest engine migrations and run the application's normal
|
|
116
|
+
migration command. The parent-scope validation and scalar-index migrations
|
|
117
|
+
use `disable_ddl_transaction!`; do not wrap them in an application-level
|
|
118
|
+
transaction. Concurrent create-before-drop ordering avoids an index-coverage
|
|
119
|
+
gap during normal PostgreSQL deployment.
|
|
120
|
+
- Versioned applications should expect an audit-write failure to abort the
|
|
121
|
+
`Value` mutation. `Value` and `ValueVersion` must share one connection pool;
|
|
122
|
+
versioning fails closed when they do not.
|
|
123
|
+
- Semantic BulkWrite still runs host validations/callbacks, Value persistence
|
|
124
|
+
callbacks, and versioning. Under the default `transaction: :all`, individual
|
|
125
|
+
validation/save failures are isolated by savepoints and successful records
|
|
126
|
+
may commit, while an uncaught exception rolls back the outer transaction.
|
|
127
|
+
`transaction: :chunks` deliberately permits earlier chunks to remain
|
|
128
|
+
committed after a later failure.
|
|
129
|
+
- `bulk_set_typed_eav_values_per_record` uses records as Hash keys; duplicate
|
|
130
|
+
Active Record instances for the same persisted row collapse to one entry.
|
|
131
|
+
Use ordered separate calls when two updates to the same row must both occur.
|
|
132
|
+
- The reduced bulk upsert accepts persisted, unique records and one uniform
|
|
133
|
+
values Hash, returns the number of upserted value rows, and intentionally does
|
|
134
|
+
not provide semantic successes/errors or callback/version guarantees.
|
|
135
|
+
- The supported runtime contract remains Ruby 3.3–4.0, Rails 7.2–8.1, and
|
|
136
|
+
PostgreSQL 15–18.
|
|
137
|
+
|
|
138
|
+
### Evidence boundaries
|
|
139
|
+
|
|
140
|
+
- The BulkRead result is an exact SQL-statement-count improvement for the
|
|
141
|
+
characterized public path, not a universal throughput or latency guarantee.
|
|
142
|
+
- BulkWrite measurements cover 100- and 1,000-host lanes only. Applications
|
|
143
|
+
should choose chunk sizes from their own callback cost, transaction duration,
|
|
144
|
+
lock contention, and failure-recovery needs.
|
|
145
|
+
- Public chained-IN multi-filter SQL remains the supported strategy. Optional
|
|
146
|
+
`pg_trgm` and dependency statistics stay application-owned and measured;
|
|
147
|
+
TypedEAV does not automatically install extensions, specialized indexes, or
|
|
148
|
+
extended statistics.
|
|
149
|
+
- No representative storage tournament selected TypedEAV, JSONB, per-type EAV,
|
|
150
|
+
or conventional columns as a universal winner.
|
|
151
|
+
|
|
152
|
+
## [0.6.0] - 2026-07-13
|
|
153
|
+
|
|
154
|
+
Hardens correctness, query efficiency, installation confidence, and release
|
|
155
|
+
safety while defining the supported runtime window. Existing public method
|
|
156
|
+
signatures and valid-record behavior remain unchanged. The compatibility floor
|
|
157
|
+
is intentionally raised to the release lines exercised by CI.
|
|
158
|
+
|
|
159
|
+
### Changed
|
|
160
|
+
|
|
161
|
+
- Define the supported runtime contract as Ruby 3.3–4.0, Rails 7.2–8.1, and
|
|
162
|
+
PostgreSQL 15–18. Runtime dependency bounds now reject unverified future
|
|
163
|
+
Ruby and Rails release lines; prereleases remain outside the support
|
|
164
|
+
guarantee. Issue #26.
|
|
165
|
+
|
|
166
|
+
### Fixed
|
|
167
|
+
|
|
168
|
+
- Prevent single-value reads from returning a stale value from a losing
|
|
169
|
+
partition, and enforce the parent-scope partition invariant in PostgreSQL.
|
|
170
|
+
Issues #22 and #23.
|
|
171
|
+
- Exercise packaged migrations in a generated Rails consumer application so
|
|
172
|
+
missing or non-idempotent installation paths fail before release. Issue #25.
|
|
173
|
+
|
|
174
|
+
### Performance
|
|
175
|
+
|
|
176
|
+
- Remove obsolete option-cache invalidation and batch-load fields for already
|
|
177
|
+
loaded typed values. Issues #28 and #29.
|
|
178
|
+
- Bound scaffold visibility queries and preload existing values during default
|
|
179
|
+
backfills. Issues #30 and #31.
|
|
180
|
+
- Keep all-partitions filter unions inside SQL and batch schema-import lookups
|
|
181
|
+
and option writes. Issues #32 and #33.
|
|
182
|
+
|
|
183
|
+
### Documentation
|
|
184
|
+
|
|
185
|
+
- Refresh maintainer, schema, and architecture guidance for the 0.5+ behavior
|
|
186
|
+
and current database invariants. Issue #34.
|
|
187
|
+
|
|
188
|
+
### Release engineering
|
|
189
|
+
|
|
190
|
+
- Gate trusted publishing on the exact dereferenced tag commit, the complete
|
|
191
|
+
supported compatibility matrix, lint, package-content inspection, and a
|
|
192
|
+
real-host migration installation using the same checksummed gem artifact
|
|
193
|
+
that is sent to RubyGems. Issue #27.
|
|
194
|
+
|
|
195
|
+
### References
|
|
196
|
+
|
|
197
|
+
- Issues #22, #23, and #25–#34.
|
|
198
|
+
|
|
8
199
|
## [0.5.0] - 2026-06-01
|
|
9
200
|
|
|
10
201
|
Adds a human display label for fields, distinct from the immutable machine
|
|
@@ -258,6 +449,17 @@ internal helper relocation (see "Changed" below). Anchored by ADRs
|
|
|
258
449
|
|
|
259
450
|
### Internal
|
|
260
451
|
|
|
452
|
+
- Added the opt-in `Field#destroy_with_values_in_batches!` API for exact-field,
|
|
453
|
+
callback-preserving keyset deletion. It commits bounded Value destroy batches,
|
|
454
|
+
retains the Field across failure, and performs locked bounded finalization;
|
|
455
|
+
ordinary Field destruction and dependency policies remain unchanged.
|
|
456
|
+
|
|
457
|
+
- Atomic ValueVersion writes are installed from the Value callback chains at
|
|
458
|
+
boot, with an identical-pool guard and idempotent recovery if a callback is
|
|
459
|
+
removed. BulkWrite keeps caller context unchanged while correlating version
|
|
460
|
+
groups through its pending marker; EventDispatcher remains a public and
|
|
461
|
+
generic observer broker.
|
|
462
|
+
|
|
261
463
|
- `TypedEAV::EventDispatcher` is retained as the synchronous broker
|
|
262
464
|
between `TypedEAV::Hooks` and `ActiveSupport::Notifications`. The
|
|
263
465
|
cleanup arc explicitly considered collapsing it and rejected that:
|
|
@@ -378,6 +580,11 @@ worked examples.
|
|
|
378
580
|
|
|
379
581
|
Initial release.
|
|
380
582
|
|
|
583
|
+
[Unreleased]: https://github.com/dchuk/typed_eav/compare/v0.7.0...HEAD
|
|
584
|
+
[0.7.0]: https://github.com/dchuk/typed_eav/releases/tag/v0.7.0
|
|
585
|
+
[0.6.0]: https://github.com/dchuk/typed_eav/releases/tag/v0.6.0
|
|
586
|
+
[0.5.0]: https://github.com/dchuk/typed_eav/releases/tag/v0.5.0
|
|
587
|
+
[0.4.0]: https://github.com/dchuk/typed_eav/releases/tag/v0.4.0
|
|
381
588
|
[0.3.2]: https://github.com/dchuk/typed_eav/releases/tag/v0.3.2
|
|
382
589
|
[0.3.1]: https://github.com/dchuk/typed_eav/releases/tag/v0.3.1
|
|
383
590
|
[0.3.0]: https://github.com/dchuk/typed_eav/releases/tag/v0.3.0
|