Class: FactDb::Models::Entity
- Inherits:
-
ActiveRecord::Base
- Object
- ActiveRecord::Base
- FactDb::Models::Entity
- Defined in:
- lib/fact_db/models/entity.rb
Overview
Represents a named entity in the fact database
Entities are real-world things like people, organizations, places, etc. that can be referenced in facts. Entities support aliases for name variations and can be merged to deduplicate records.
Constant Summary collapse
- STATUSES =
Returns valid resolution statuses.
%w[unresolved resolved merged split].freeze
- ENTITY_KINDS =
Returns valid entity kinds.
%w[person organization place product event concept other].freeze
Class Method Summary collapse
-
.nearest_neighbors(embedding, limit: 10) ⇒ ActiveRecord::Relation
Finds entities by vector similarity using pgvector.
Instance Method Summary collapse
-
#add_alias(text, kind: nil, confidence: 1.0) ⇒ EntityAlias?
Adds an alias to this entity.
-
#all_aliases ⇒ Array<String>
Returns all alias names as an array of strings.
-
#by_kind(k) ⇒ ActiveRecord::Relation
Returns entities of a specific kind.
-
#canonical_entity ⇒ Entity
Returns the canonical entity (follows merge chain).
-
#current_facts ⇒ ActiveRecord::Relation
Returns currently valid canonical facts mentioning this entity.
-
#facts_at(date) ⇒ ActiveRecord::Relation
Returns facts valid at a specific date.
-
#matches_name?(query) ⇒ Boolean
Checks if the entity matches a query (by name or alias).
-
#merged? ⇒ Boolean
Checks if the entity has been merged into another.
-
#not_merged ⇒ ActiveRecord::Relation
Returns entities that have not been merged.
-
#resolved ⇒ ActiveRecord::Relation
Returns entities with “resolved” status.
-
#resolved? ⇒ Boolean
Checks if the entity is resolved.
-
#unresolved ⇒ ActiveRecord::Relation
Returns entities with “unresolved” status.
Class Method Details
.nearest_neighbors(embedding, limit: 10) ⇒ ActiveRecord::Relation
Finds entities by vector similarity using pgvector
149 150 151 152 153 |
# File 'lib/fact_db/models/entity.rb', line 149 def self.nearest_neighbors(, limit: 10) return none unless order(Arel.sql("embedding <=> '#{}'")).limit(limit) end |
Instance Method Details
#add_alias(text, kind: nil, confidence: 1.0) ⇒ EntityAlias?
Adds an alias to this entity
Validates the alias before creation using AliasFilter. Returns nil if validation fails.
106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/fact_db/models/entity.rb', line 106 def add_alias(text, kind: nil, confidence: 1.0) # Pre-validate before attempting to create return nil unless Validation::AliasFilter.valid?(text, name: name) aliases.find_or_create_by!(name: text) do |a| a.kind = kind a.confidence = confidence end rescue ActiveRecord::RecordInvalid # Alias validation failed (pronoun, generic term, etc.) nil end |
#all_aliases ⇒ Array<String>
Returns all alias names as an array of strings
93 94 95 |
# File 'lib/fact_db/models/entity.rb', line 93 def all_aliases aliases.pluck(:name) end |
#by_kind(k) ⇒ ActiveRecord::Relation
Returns entities of a specific kind
49 |
# File 'lib/fact_db/models/entity.rb', line 49 scope :by_kind, ->(k) { where(kind: k) } |
#canonical_entity ⇒ Entity
Returns the canonical entity (follows merge chain)
If this entity has been merged, recursively follows the canonical_id chain to find the ultimate canonical entity.
86 87 88 |
# File 'lib/fact_db/models/entity.rb', line 86 def canonical_entity merged? ? canonical&.canonical_entity || canonical : self end |
#current_facts ⇒ ActiveRecord::Relation
Returns currently valid canonical facts mentioning this entity
132 133 134 |
# File 'lib/fact_db/models/entity.rb', line 132 def current_facts facts.currently_valid.canonical end |
#facts_at(date) ⇒ ActiveRecord::Relation
Returns facts valid at a specific date
140 141 142 |
# File 'lib/fact_db/models/entity.rb', line 140 def facts_at(date) facts.valid_at(date).canonical end |
#matches_name?(query) ⇒ Boolean
Checks if the entity matches a query (by name or alias)
123 124 125 126 127 |
# File 'lib/fact_db/models/entity.rb', line 123 def matches_name?(query) return true if self.name.downcase == query.downcase aliases.exists?(["LOWER(name) = ?", query.downcase]) end |
#merged? ⇒ Boolean
Checks if the entity has been merged into another
76 77 78 |
# File 'lib/fact_db/models/entity.rb', line 76 def merged? resolution_status == "merged" end |
#not_merged ⇒ ActiveRecord::Relation
Returns entities that have not been merged
64 |
# File 'lib/fact_db/models/entity.rb', line 64 scope :not_merged, -> { where.not(resolution_status: "merged") } |
#resolved ⇒ ActiveRecord::Relation
Returns entities with “resolved” status
54 |
# File 'lib/fact_db/models/entity.rb', line 54 scope :resolved, -> { where(resolution_status: "resolved") } |
#resolved? ⇒ Boolean
Checks if the entity is resolved
69 70 71 |
# File 'lib/fact_db/models/entity.rb', line 69 def resolved? resolution_status == "resolved" end |
#unresolved ⇒ ActiveRecord::Relation
Returns entities with “unresolved” status
59 |
# File 'lib/fact_db/models/entity.rb', line 59 scope :unresolved, -> { where(resolution_status: "unresolved") } |