Module: TypedEAV::Partition
- Defined in:
- lib/typed_eav/partition.rb
Overview
Partition-aware visibility for schema objects keyed by the canonical
(entity_type, scope, parent_scope) tuple.
This module is deliberately explicit: callers pass already-resolved scope
values. Ambient resolution (TypedEAV.current_scope, with_scope,
unscoped) stays with the adapters that know their calling context.
Class Method Summary collapse
-
.definitions_by_name(defs) ⇒ Object
Indexes field definitions by name with deterministic three-way collision resolution: when global (scope=NULL, parent_scope=NULL), scope-only (scope set, parent_scope=NULL), and full-triple (both set) fields share a name, the most-specific row wins.
-
.definitions_multimap_by_name(defs) ⇒ Object
Indexes field definitions by name into a multi-map (one name -> array of fields).
-
.effective_fields_by_name(entity_type:, scope: nil, parent_scope: nil, mode: :partition) ⇒ Object
One visible field per name after collision resolution.
-
.find_visible_section!(id, entity_type:, scope: nil, parent_scope: nil, mode: :partition) ⇒ TypedEAV::Section
Looks up a single Section by
idconstrained to the caller's partition tuple. -
.visible_fields(entity_type: nil, scope: nil, parent_scope: nil, mode: :partition) ⇒ Object
All field definitions visible from a tuple: pure global rows, scope-only rows, and full-tuple rows.
-
.visible_sections(entity_type:, scope: nil, parent_scope: nil, mode: :partition) ⇒ Object
All sections visible from the same tuple as field definitions.
Class Method Details
.definitions_by_name(defs) ⇒ Object
Indexes field definitions by name with deterministic three-way collision resolution: when global (scope=NULL, parent_scope=NULL), scope-only (scope set, parent_scope=NULL), and full-triple (both set) fields share a name, the most-specific row wins.
Sort key [scope.nil? ? 0 : 1, parent_scope.nil? ? 0 : 1] orders rows:
[0, 0] global (least specific) -> comes first
[1, 0] scope-only (middle)
[1, 1] full triple (most specific) -> comes last
index_by(&:name) keeps the LAST entry on duplicate keys (Rails
convention via Array#to_h), so most-specific wins. The two-key sort
extends the prior "scoped beats global" rule into "two-key beats
one-key beats global" without changing the index_by-last-wins
mechanism. The (scope=NULL, parent_scope=NOT NULL) slot is
unreachable by construction (orphan-parent invariant in Field::Base),
so the ordering is exhaustive across the three valid shapes.
Shared by the class-query path (FilterQuery / BulkRead / EntityQuery) and the instance path (HasTypedEAV::InstanceMethods#typed_eav_defs_by_name) so the two cannot drift. Lives on Partition because partition-tuple precedence is a partition concept.
71 72 73 74 75 |
# File 'lib/typed_eav/partition.rb', line 71 def definitions_by_name(defs) defs.to_a .sort_by { |d| [d.scope.nil? ? 0 : 1, d.parent_scope.nil? ? 0 : 1] } .index_by(&:name) end |
.definitions_multimap_by_name(defs) ⇒ Object
Indexes field definitions by name into a multi-map (one name ->
array of fields). Used by the class-query path under
TypedEAV.unscoped { }, where the same field name may legitimately
exist across multiple tenant partitions and we must OR-across all
matching field_ids per filter rather than collapse to a single row.
82 83 84 |
# File 'lib/typed_eav/partition.rb', line 82 def definitions_multimap_by_name(defs) defs.to_a.group_by(&:name) end |
.effective_fields_by_name(entity_type:, scope: nil, parent_scope: nil, mode: :partition) ⇒ Object
One visible field per name after collision resolution. Most-specific wins: full tuple beats scope-only, scope-only beats global.
40 41 42 43 44 45 46 47 |
# File 'lib/typed_eav/partition.rb', line 40 def effective_fields_by_name(entity_type:, scope: nil, parent_scope: nil, mode: :partition) fields = visible_fields(entity_type: entity_type, scope: scope, parent_scope: parent_scope, mode: mode) if mode == :all_partitions definitions_multimap_by_name(fields) else definitions_by_name(fields) end end |
.find_visible_section!(id, entity_type:, scope: nil, parent_scope: nil, mode: :partition) ⇒ TypedEAV::Section
Looks up a single Section by id constrained to the
caller's partition tuple. Documented-public surface: apps building
admin UIs that need to authorize a section lookup before editing,
rendering, or destroying it should call this rather than
Section.find(id), which would happily return a section belonging
to another tenant's partition.
Visibility merge matches visible_sections: rows whose
(entity_type, scope, parent_scope) is either the requested tuple
or the global (scope: nil, parent_scope: nil) partition are
eligible. The most-specific-wins precedence used for field
collision resolution does not apply here — section lookup is by
primary key, not by name.
Sibling documented-public methods on this module that share the same partition-visibility surface: visible_fields, effective_fields_by_name, definitions_by_name, definitions_multimap_by_name, visible_sections.
139 140 141 |
# File 'lib/typed_eav/partition.rb', line 139 def find_visible_section!(id, entity_type:, scope: nil, parent_scope: nil, mode: :partition) visible_sections(entity_type: entity_type, scope: scope, parent_scope: parent_scope, mode: mode).find(id) end |
.visible_fields(entity_type: nil, scope: nil, parent_scope: nil, mode: :partition) ⇒ Object
All field definitions visible from a tuple: pure global rows,
scope-only rows, and full-tuple rows. Passing mode: :all_partitions is
the deliberate admin bypass; it is distinct from scope: nil, which
means the global partition only.
24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/typed_eav/partition.rb', line 24 def visible_fields(entity_type: nil, scope: nil, parent_scope: nil, mode: :partition) validate_mode!(mode) fields = TypedEAV::Field::Base.all fields = fields.where(entity_type: entity_type) if entity_type return fields if mode == :all_partitions raise ArgumentError, ORPHAN_PARENT_MESSAGE unless ScopeTuple.invariant_satisfied?(scope, parent_scope) fields.where( scope: [scope, nil].uniq, parent_scope: [parent_scope, nil].uniq, ) end |
.visible_sections(entity_type:, scope: nil, parent_scope: nil, mode: :partition) ⇒ Object
All sections visible from the same tuple as field definitions.
87 88 89 90 91 92 93 94 |
# File 'lib/typed_eav/partition.rb', line 87 def visible_sections(entity_type:, scope: nil, parent_scope: nil, mode: :partition) validate_mode!(mode) return TypedEAV::Section.where(entity_type: entity_type) if mode == :all_partitions raise ArgumentError, ORPHAN_PARENT_MESSAGE unless ScopeTuple.invariant_satisfied?(scope, parent_scope) TypedEAV::Section.for_entity(entity_type, scope: scope, parent_scope: parent_scope) end |