typed_eav 0.7.0 → 0.7.1
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 +32 -2
- data/README.md +17 -2
- data/lib/typed_eav/bulk_read.rb +10 -43
- data/lib/typed_eav/bulk_upsert.rb +10 -14
- data/lib/typed_eav/entity_query.rb +2 -2
- data/lib/typed_eav/filter_query.rb +2 -2
- data/lib/typed_eav/has_typed_eav/instance_methods.rb +2 -2
- data/lib/typed_eav/has_typed_eav.rb +1 -1
- data/lib/typed_eav/partition/definition_batch.rb +70 -0
- data/lib/typed_eav/partition.rb +2 -0
- data/lib/typed_eav/version.rb +1 -1
- data/lib/typed_eav/versioned.rb +8 -6
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 312b444b0c7b29eb298af1ef5bba02d3ba56ad811399b3ffcd2dfd2afd88267b
|
|
4
|
+
data.tar.gz: cfa3ca85088eaff46dff6657d098f9fcf38fec9129b53792cfb37cc19e4358ad
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: abcb3cde1dc9d09da1ea014165c245d74aa2ef2f5fd566ecc9f86343b8e30b1ca32bcc10eb9735a06a23641bb0ccef7c1078d2be288a724a20b6d7e44468e6d9
|
|
7
|
+
data.tar.gz: b259edd0ece6e756569a151194368fc0adda83063d56683f9113d6373c0eede174cb545f9d1ca0ccc70e2dd512239494299f3da8608567aa5e47989e3b780eb3
|
data/CHANGELOG.md
CHANGED
|
@@ -7,7 +7,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
## [0.7.1] - 2026-09-04
|
|
11
|
+
|
|
12
|
+
A focused patch release for inherited Active Record hosts and multi-partition
|
|
13
|
+
bulk upserts. No new database migrations or public API changes are required.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- Resolve inherited and namespaced Active Record host definitions, filters,
|
|
18
|
+
bulk reads, writes, and registry/versioning opt-ins through Rails'
|
|
19
|
+
canonical polymorphic name. STI subclasses now consistently share their
|
|
20
|
+
base class's EAV schema and stored values while queries retain their host
|
|
21
|
+
class restriction. Partition isolation and most-specific field precedence
|
|
22
|
+
are preserved. (#42)
|
|
23
|
+
|
|
24
|
+
### Performance
|
|
25
|
+
|
|
26
|
+
- Batch BulkUpsert field-definition resolution into one SELECT per transaction
|
|
27
|
+
unit while preserving exact tuple isolation and definition precedence. A
|
|
28
|
+
20-partition regression case now issues one definition SELECT instead of 20;
|
|
29
|
+
chunked transactions intentionally issue one per chunk. BulkRead and
|
|
30
|
+
BulkUpsert share the internal batched resolver. This is a query-count
|
|
31
|
+
improvement, not a universal throughput claim. (#43)
|
|
32
|
+
|
|
33
|
+
### Compatibility and verification
|
|
34
|
+
|
|
35
|
+
- BulkUpsert's reduced-semantics acknowledgement, validation, transaction
|
|
36
|
+
boundaries, and callback/versioning behavior are unchanged.
|
|
37
|
+
- Regression coverage includes true STI and namespaced hosts, public
|
|
38
|
+
read/filter/write paths, partition isolation, definition precedence, and
|
|
39
|
+
all/chunk transaction behavior.
|
|
11
40
|
|
|
12
41
|
## [0.7.0] - 2026-08-18
|
|
13
42
|
|
|
@@ -580,7 +609,8 @@ worked examples.
|
|
|
580
609
|
|
|
581
610
|
Initial release.
|
|
582
611
|
|
|
583
|
-
[Unreleased]: https://github.com/dchuk/typed_eav/compare/v0.7.
|
|
612
|
+
[Unreleased]: https://github.com/dchuk/typed_eav/compare/v0.7.1...HEAD
|
|
613
|
+
[0.7.1]: https://github.com/dchuk/typed_eav/releases/tag/v0.7.1
|
|
584
614
|
[0.7.0]: https://github.com/dchuk/typed_eav/releases/tag/v0.7.0
|
|
585
615
|
[0.6.0]: https://github.com/dchuk/typed_eav/releases/tag/v0.6.0
|
|
586
616
|
[0.5.0]: https://github.com/dchuk/typed_eav/releases/tag/v0.5.0
|
data/README.md
CHANGED
|
@@ -119,6 +119,11 @@ tags.field_options.create!([
|
|
|
119
119
|
])
|
|
120
120
|
```
|
|
121
121
|
|
|
122
|
+
When deriving `entity_type` from a model class, use
|
|
123
|
+
`Contact.polymorphic_name`. Rails stores polymorphic associations under that
|
|
124
|
+
canonical name, which is the base-class type for STI hosts and respects the
|
|
125
|
+
application's namespaced-polymorphism setting.
|
|
126
|
+
|
|
122
127
|
### 3. Set values on records
|
|
123
128
|
|
|
124
129
|
```ruby
|
|
@@ -1157,7 +1162,7 @@ directly:
|
|
|
1157
1162
|
|
|
1158
1163
|
```ruby
|
|
1159
1164
|
TypedEAV::ValueVersion
|
|
1160
|
-
.where(entity_type: contact.class.
|
|
1165
|
+
.where(entity_type: contact.class.polymorphic_name, entity_id: contact.id, field_id: age_field.id)
|
|
1161
1166
|
.order(changed_at: :desc, id: :desc)
|
|
1162
1167
|
# => [<ValueVersion change_type: "destroy" before: {"integer_value" => 42} after: {} value_id: nil>,
|
|
1163
1168
|
# <ValueVersion change_type: "update" before: {"integer_value" => 41} after: {"integer_value" => 42} value_id: nil>,
|
|
@@ -1176,7 +1181,7 @@ exports) — drop the `field_id` filter:
|
|
|
1176
1181
|
|
|
1177
1182
|
```ruby
|
|
1178
1183
|
TypedEAV::ValueVersion
|
|
1179
|
-
.where(entity_type: contact.class.
|
|
1184
|
+
.where(entity_type: contact.class.polymorphic_name, entity_id: contact.id)
|
|
1180
1185
|
.order(changed_at: :desc, id: :desc)
|
|
1181
1186
|
# => all version rows for every typed field on this contact, most-recent-first.
|
|
1182
1187
|
# Includes :create, :update, and :destroy events across every field the
|
|
@@ -1416,6 +1421,10 @@ TypedEAV::QueryBuilder ← low altitude: per-field SQL primitive
|
|
|
1416
1421
|
3. Returns a `{record_id => {field_name => value}}` map while skipping orphaned
|
|
1417
1422
|
values and preserving logical missingness.
|
|
1418
1423
|
|
|
1424
|
+
Definitions, filters, reads, registry entries, and writes all use the host's
|
|
1425
|
+
Rails `polymorphic_name`, so an STI leaf class reads and queries the same rows
|
|
1426
|
+
written under its base-class polymorphic type.
|
|
1427
|
+
|
|
1419
1428
|
The final production characterization reduced the 1,002 SQL statements observed
|
|
1420
1429
|
across 1,000 scopes to three for the same BulkRead shape. This is a statement-
|
|
1421
1430
|
count result, not a representative throughput claim; applications should still
|
|
@@ -1459,6 +1468,12 @@ checks, and Value validation callbacks remain; host callbacks and validations,
|
|
|
1459
1468
|
Value persistence callbacks, versioning, delete shorthand, and per-record
|
|
1460
1469
|
savepoint isolation are skipped.
|
|
1461
1470
|
|
|
1471
|
+
Within each `transaction: :all` unit—or each requested chunk—the upsert path
|
|
1472
|
+
resolves every record partition through one batched field-definition SELECT.
|
|
1473
|
+
It shares BulkRead's internal tuple resolver, retaining global, scope-only, and
|
|
1474
|
+
full-tuple precedence independently for each record without broadening tenant
|
|
1475
|
+
visibility.
|
|
1476
|
+
|
|
1462
1477
|
`BulkWrite` and `BulkRead` are siblings — one read path, one write path — but they don't share a base class. Per [ADR-0005](docs/adr/0005-keep-phase-six-modules-independent.md), keeping them independent preserves the option to evolve each on its own schedule.
|
|
1463
1478
|
|
|
1464
1479
|
### Per-record reads/writes: `InstanceMethods`
|
data/lib/typed_eav/bulk_read.rb
CHANGED
|
@@ -10,8 +10,8 @@ module TypedEAV
|
|
|
10
10
|
#
|
|
11
11
|
# 1. validate_records! — nil -> ArgumentError; single-class invariant
|
|
12
12
|
# 2. group_by_tuple — `[typed_eav_scope, typed_eav_parent_scope]`
|
|
13
|
-
# 3. winning_ids_by_tuple — one
|
|
14
|
-
#
|
|
13
|
+
# 3. winning_ids_by_tuple — one `Partition::DefinitionBatch` query, then
|
|
14
|
+
# extract the winning field ids per tuple
|
|
15
15
|
# 4. preload_values — single SELECT across ALL records
|
|
16
16
|
# 5. build_result_hash — per-record inner hash; orphan-skip + winning-id
|
|
17
17
|
# precedence mirrored from the instance path.
|
|
@@ -26,9 +26,10 @@ module TypedEAV
|
|
|
26
26
|
#
|
|
27
27
|
# ## Single-class invariant
|
|
28
28
|
#
|
|
29
|
-
# The polymorphic value query
|
|
30
|
-
#
|
|
31
|
-
# subclasses pass
|
|
29
|
+
# The polymorphic value query targets the host's canonical Rails
|
|
30
|
+
# `polymorphic_name`, so an STI subclass reads rows stored for its base
|
|
31
|
+
# class. Mixed, unrelated input would still be invalid; STI subclasses pass
|
|
32
|
+
# via `records.all?(host_class)`.
|
|
32
33
|
class BulkRead
|
|
33
34
|
def initialize(host_class:, records:)
|
|
34
35
|
@host_class = host_class
|
|
@@ -73,49 +74,15 @@ module TypedEAV
|
|
|
73
74
|
end
|
|
74
75
|
|
|
75
76
|
def winning_ids_by_tuple(tuples)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
tuples.to_h do |tuple|
|
|
81
|
-
s, ps = tuple
|
|
82
|
-
candidate_tuples = [[nil, nil], [s, nil], [s, ps]].uniq
|
|
83
|
-
visible = candidate_tuples.flat_map { |candidate| definitions_by_tuple.fetch(candidate, []) }
|
|
84
|
-
[tuple, TypedEAV::Partition.definitions_by_name(visible).transform_values(&:id)]
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def batched_definitions(tuples)
|
|
89
|
-
tuples.each { |scope, parent_scope| validate_tuple!(scope, parent_scope) }
|
|
90
|
-
relation = TypedEAV::Field::Base.where(entity_type: host_class.name)
|
|
91
|
-
requested = tuples.map { |scope, parent_scope| { "scope" => scope, "parent_scope" => parent_scope } }
|
|
92
|
-
relation.where(<<~SQL.squish, requested.to_json).to_a
|
|
93
|
-
typed_eav_fields.scope IS NULL AND typed_eav_fields.parent_scope IS NULL
|
|
94
|
-
OR EXISTS (
|
|
95
|
-
SELECT 1
|
|
96
|
-
FROM jsonb_to_recordset(?::jsonb) AS requested(scope text, parent_scope text)
|
|
97
|
-
WHERE (
|
|
98
|
-
typed_eav_fields.scope IS NOT DISTINCT FROM requested.scope
|
|
99
|
-
AND typed_eav_fields.parent_scope IS NOT DISTINCT FROM requested.parent_scope
|
|
100
|
-
)
|
|
101
|
-
OR (
|
|
102
|
-
typed_eav_fields.scope IS NOT DISTINCT FROM requested.scope
|
|
103
|
-
AND typed_eav_fields.parent_scope IS NULL
|
|
104
|
-
)
|
|
105
|
-
)
|
|
106
|
-
SQL
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
def validate_tuple!(scope, parent_scope)
|
|
110
|
-
return if TypedEAV::ScopeTuple.invariant_satisfied?(scope, parent_scope)
|
|
111
|
-
|
|
112
|
-
raise ArgumentError, "parent_scope cannot be set when scope is blank"
|
|
77
|
+
TypedEAV::Partition::DefinitionBatch
|
|
78
|
+
.resolve(entity_type: host_class.polymorphic_name, tuples: tuples)
|
|
79
|
+
.transform_values { |fields_by_name| fields_by_name.transform_values(&:id) }
|
|
113
80
|
end
|
|
114
81
|
|
|
115
82
|
def preload_values(records)
|
|
116
83
|
rows = TypedEAV::Value
|
|
117
84
|
.includes(:field)
|
|
118
|
-
.where(entity_type: host_class.
|
|
85
|
+
.where(entity_type: host_class.polymorphic_name, entity_id: records.map(&:id))
|
|
119
86
|
.to_a
|
|
120
87
|
rows.group_by(&:entity_id)
|
|
121
88
|
end
|
|
@@ -8,7 +8,8 @@ module TypedEAV
|
|
|
8
8
|
# persistence callbacks, versioning, or per-record error isolation. Callers must
|
|
9
9
|
# acknowledge those semantics explicitly. It pre-casts and validates every
|
|
10
10
|
# row in a transaction unit before issuing one upsert batch on the host
|
|
11
|
-
# model's connection.
|
|
11
|
+
# model's connection. Field definitions for every tuple in that unit resolve
|
|
12
|
+
# in one batch; scope precedence and field casting remain authoritative.
|
|
12
13
|
module BulkUpsert
|
|
13
14
|
TYPE_COLUMNS = %i[
|
|
14
15
|
string_value text_value boolean_value integer_value decimal_value date_value datetime_value json_value
|
|
@@ -36,19 +37,14 @@ module TypedEAV
|
|
|
36
37
|
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength -- tuple grouping, validation, and row construction are one durability unit.
|
|
37
38
|
def write_unit(host_class, records, values_by_field_name)
|
|
38
39
|
tuples = records.map { |record| [record.typed_eav_scope, record.typed_eav_parent_scope] }.uniq
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
parent_scope: tuple[1],
|
|
48
|
-
),
|
|
49
|
-
)
|
|
50
|
-
[tuple, fields]
|
|
51
|
-
end
|
|
40
|
+
# Resolve every exact tuple in this transaction unit with one query.
|
|
41
|
+
# The shared resolver preserves global/scope/full-tuple precedence per
|
|
42
|
+
# tuple and never observes EntityQuery's administrative ALL_SCOPES
|
|
43
|
+
# bypass, so tenants remain isolated inside an unscoped block.
|
|
44
|
+
fields_by_tuple = TypedEAV::Partition::DefinitionBatch.resolve(
|
|
45
|
+
entity_type: host_class.polymorphic_name,
|
|
46
|
+
tuples: tuples,
|
|
47
|
+
)
|
|
52
48
|
rows = records.flat_map do |record|
|
|
53
49
|
fields = fields_by_tuple.fetch([record.typed_eav_scope, record.typed_eav_parent_scope])
|
|
54
50
|
values_by_field_name.filter_map do |name, raw|
|
|
@@ -103,10 +103,10 @@ module TypedEAV
|
|
|
103
103
|
def typed_eav_definitions(scope: UNSET_SCOPE, parent_scope: UNSET_SCOPE)
|
|
104
104
|
resolved = resolve_scope(scope, parent_scope)
|
|
105
105
|
if resolved.equal?(ALL_SCOPES)
|
|
106
|
-
TypedEAV::Partition.visible_fields(entity_type:
|
|
106
|
+
TypedEAV::Partition.visible_fields(entity_type: polymorphic_name, mode: :all_partitions)
|
|
107
107
|
else
|
|
108
108
|
s, ps = resolved
|
|
109
|
-
TypedEAV::Partition.visible_fields(entity_type:
|
|
109
|
+
TypedEAV::Partition.visible_fields(entity_type: polymorphic_name, scope: s, parent_scope: ps)
|
|
110
110
|
end
|
|
111
111
|
end
|
|
112
112
|
|
|
@@ -106,10 +106,10 @@ module TypedEAV
|
|
|
106
106
|
|
|
107
107
|
def lookup_definitions
|
|
108
108
|
if all_scopes?
|
|
109
|
-
TypedEAV::Partition.visible_fields(entity_type: model.
|
|
109
|
+
TypedEAV::Partition.visible_fields(entity_type: model.polymorphic_name, mode: :all_partitions)
|
|
110
110
|
else
|
|
111
111
|
TypedEAV::Partition.visible_fields(
|
|
112
|
-
entity_type: model.
|
|
112
|
+
entity_type: model.polymorphic_name,
|
|
113
113
|
scope: @scope,
|
|
114
114
|
parent_scope: @parent_scope,
|
|
115
115
|
)
|
|
@@ -262,7 +262,7 @@ module TypedEAV
|
|
|
262
262
|
# because each record's INSERT clears the cache — so cache-do alone
|
|
263
263
|
# cannot keep field-definition reads N+1-free across the bulk loop.
|
|
264
264
|
# The thread-local memo is the explicit fallback documented in plan
|
|
265
|
-
# 06-05 §T3 notes; it pre-warms once per `[
|
|
265
|
+
# 06-05 §T3 notes; it pre-warms once per `[polymorphic_name, scope,
|
|
266
266
|
# parent_scope]` tuple and reuses across every record in that tuple.
|
|
267
267
|
#
|
|
268
268
|
# Outside a bulk operation the memo is nil and we fall through to
|
|
@@ -270,7 +270,7 @@ module TypedEAV
|
|
|
270
270
|
def typed_eav_defs_by_name
|
|
271
271
|
memo = Thread.current[:typed_eav_bulk_defs_memo]
|
|
272
272
|
if memo
|
|
273
|
-
key = [self.class.
|
|
273
|
+
key = [self.class.polymorphic_name, typed_eav_scope, typed_eav_parent_scope]
|
|
274
274
|
memo[key] ||= TypedEAV::Partition.definitions_by_name(typed_eav_definitions)
|
|
275
275
|
else
|
|
276
276
|
TypedEAV::Partition.definitions_by_name(typed_eav_definitions)
|
|
@@ -93,7 +93,7 @@ module TypedEAV
|
|
|
93
93
|
|
|
94
94
|
accepts_nested_attributes_for :typed_values, allow_destroy: true
|
|
95
95
|
|
|
96
|
-
TypedEAV.registry.register(
|
|
96
|
+
TypedEAV.registry.register(polymorphic_name, types: types, versioned: versioned)
|
|
97
97
|
end
|
|
98
98
|
|
|
99
99
|
private
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TypedEAV
|
|
4
|
+
module Partition
|
|
5
|
+
# Internal batched resolver for field definitions visible to many exact
|
|
6
|
+
# partition tuples. It performs one definition SELECT, then applies the
|
|
7
|
+
# same global -> scope -> full-tuple precedence as `definitions_by_name`
|
|
8
|
+
# independently for every requested tuple.
|
|
9
|
+
class DefinitionBatch
|
|
10
|
+
class << self
|
|
11
|
+
def resolve(entity_type:, tuples:)
|
|
12
|
+
new(entity_type: entity_type, tuples: tuples).resolve
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def initialize(entity_type:, tuples:)
|
|
17
|
+
@entity_type = entity_type
|
|
18
|
+
@tuples = tuples.uniq
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def resolve
|
|
22
|
+
tuples.each { |scope, parent_scope| validate_tuple!(scope, parent_scope) }
|
|
23
|
+
return {} if tuples.empty?
|
|
24
|
+
|
|
25
|
+
definitions_by_tuple = load_definitions.group_by do |definition|
|
|
26
|
+
[definition.scope, definition.parent_scope]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
tuples.to_h do |tuple|
|
|
30
|
+
visible = candidate_tuples(tuple).flat_map { |candidate| definitions_by_tuple.fetch(candidate, []) }
|
|
31
|
+
[tuple, TypedEAV::Partition.definitions_by_name(visible)]
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
attr_reader :entity_type, :tuples
|
|
38
|
+
|
|
39
|
+
def load_definitions
|
|
40
|
+
requested = tuples.map { |scope, parent_scope| { "scope" => scope, "parent_scope" => parent_scope } }
|
|
41
|
+
TypedEAV::Field::Base.where(entity_type: entity_type).where(<<~SQL.squish, requested.to_json).to_a
|
|
42
|
+
typed_eav_fields.scope IS NULL AND typed_eav_fields.parent_scope IS NULL
|
|
43
|
+
OR EXISTS (
|
|
44
|
+
SELECT 1
|
|
45
|
+
FROM jsonb_to_recordset(?::jsonb) AS requested(scope text, parent_scope text)
|
|
46
|
+
WHERE (
|
|
47
|
+
typed_eav_fields.scope IS NOT DISTINCT FROM requested.scope
|
|
48
|
+
AND typed_eav_fields.parent_scope IS NOT DISTINCT FROM requested.parent_scope
|
|
49
|
+
)
|
|
50
|
+
OR (
|
|
51
|
+
typed_eav_fields.scope IS NOT DISTINCT FROM requested.scope
|
|
52
|
+
AND typed_eav_fields.parent_scope IS NULL
|
|
53
|
+
)
|
|
54
|
+
)
|
|
55
|
+
SQL
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def candidate_tuples(tuple)
|
|
59
|
+
scope, parent_scope = tuple
|
|
60
|
+
[[nil, nil], [scope, nil], [scope, parent_scope]].uniq
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def validate_tuple!(scope, parent_scope)
|
|
64
|
+
return if TypedEAV::ScopeTuple.invariant_satisfied?(scope, parent_scope)
|
|
65
|
+
|
|
66
|
+
raise ArgumentError, "parent_scope cannot be set when scope is blank"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
data/lib/typed_eav/partition.rb
CHANGED
|
@@ -8,6 +8,8 @@ module TypedEAV
|
|
|
8
8
|
# values. Ambient resolution (`TypedEAV.current_scope`, `with_scope`,
|
|
9
9
|
# `unscoped`) stays with the adapters that know their calling context.
|
|
10
10
|
module Partition
|
|
11
|
+
autoload :DefinitionBatch, "typed_eav/partition/definition_batch"
|
|
12
|
+
|
|
11
13
|
# Frozen orphan-parent ArgumentError message. Kept as a module constant
|
|
12
14
|
# so both `visible_fields` and `visible_sections` raise the same string
|
|
13
15
|
# without re-allocating per call. The string is the wire-stable BC error
|
data/lib/typed_eav/version.rb
CHANGED
data/lib/typed_eav/versioned.rb
CHANGED
|
@@ -62,12 +62,14 @@ module TypedEAV
|
|
|
62
62
|
|
|
63
63
|
# Re-register with versioned: true. Preserve the existing types:
|
|
64
64
|
# restriction by reading the current Registry entry.
|
|
65
|
-
# has_typed_eav already
|
|
66
|
-
#
|
|
67
|
-
#
|
|
68
|
-
# — shouldn't happen post-
|
|
69
|
-
|
|
70
|
-
|
|
65
|
+
# has_typed_eav already registered the canonical Rails polymorphic
|
|
66
|
+
# name. Reuse it here so including this concern on an STI subclass
|
|
67
|
+
# enables versioning for the base entity_type actually stored on Value.
|
|
68
|
+
# If the entry doesn't exist (defensive — shouldn't happen post-
|
|
69
|
+
# has_typed_eav), default types to nil.
|
|
70
|
+
entity_type = polymorphic_name
|
|
71
|
+
existing = TypedEAV.registry.entities[entity_type] || {}
|
|
72
|
+
TypedEAV.registry.register(entity_type, types: existing[:types], versioned: true)
|
|
71
73
|
end
|
|
72
74
|
end
|
|
73
75
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: typed_eav
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.7.
|
|
4
|
+
version: 0.7.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- dchuk
|
|
@@ -159,6 +159,7 @@ files:
|
|
|
159
159
|
- lib/typed_eav/has_typed_eav.rb
|
|
160
160
|
- lib/typed_eav/has_typed_eav/instance_methods.rb
|
|
161
161
|
- lib/typed_eav/partition.rb
|
|
162
|
+
- lib/typed_eav/partition/definition_batch.rb
|
|
162
163
|
- lib/typed_eav/query_builder.rb
|
|
163
164
|
- lib/typed_eav/registry.rb
|
|
164
165
|
- lib/typed_eav/schema_portability.rb
|