Class: Huginn::Datatable::Validator
- Inherits:
-
Object
- Object
- Huginn::Datatable::Validator
- Defined in:
- lib/huginn/datatable/validator.rb
Overview
Resolves and validates column references used by datatable filters, orders and ranges.
A field is either a plain column ("status"), an association-scoped
column ("pessoa.nome", "company.people.age") or — when the model
declares huginn_attributes — a public API alias that maps to the
real column.
Fields are never interpolated into SQL strings: scoped fields are
resolved through AssociationPath (direction aware FK/PK linking) and
authorization is enforced against the allowed_paths allowlist. When
the model configures huginn_attributes(strict: true) only the
declared aliases are accepted, so the schema stays hidden from callers.
Constant Summary collapse
- FIELD_PATTERN =
/\A[a-z_][a-z0-9_]*\z/
Class Method Summary collapse
Instance Method Summary collapse
- #allowlist_key ⇒ Object
- #arel_attribute ⇒ Object
-
#association_name ⇒ Object
First association name of the chain (backwards compatible alias used by specs), or nil for plain columns.
-
#association_path ⇒ Object
The AssociationPath for scoped fields (builds filter/order subqueries), or nil for plain columns.
-
#authorization_path ⇒ Object
Canonical chain of association reflection names (e.g. ["company", "people"]) used to match the allowlist.
- #column_type ⇒ Object
- #correlated_order_expression ⇒ Object
-
#initialize(model, field) ⇒ Validator
constructor
A new instance of Validator.
- #plain? ⇒ Boolean
- #scoped? ⇒ Boolean
- #segments ⇒ Object
- #valid? ⇒ Boolean
Constructor Details
#initialize(model, field) ⇒ Validator
Returns a new instance of Validator.
25 26 27 28 29 30 |
# File 'lib/huginn/datatable/validator.rb', line 25 def initialize(model, field) @model = model @strict_denied = false @field = resolve_alias(field) @field = @field.split(".").drop(1).join(".") if own_table_prefix?(@field) end |
Class Method Details
.call(model, field) ⇒ Object
21 22 23 |
# File 'lib/huginn/datatable/validator.rb', line 21 def self.call(model, field) new(model, field) end |
Instance Method Details
#allowlist_key ⇒ Object
95 96 97 98 99 100 |
# File 'lib/huginn/datatable/validator.rb', line 95 def allowlist_key return nil if plain? joined = .join(".") joined.empty? ? nil : joined end |
#arel_attribute ⇒ Object
64 65 66 67 68 |
# File 'lib/huginn/datatable/validator.rb', line 64 def arel_attribute return nil unless valid? plain? ? model.arel_table[column] : association_path.target_table[column] end |
#association_name ⇒ Object
First association name of the chain (backwards compatible alias used by specs), or nil for plain columns.
85 86 87 88 89 |
# File 'lib/huginn/datatable/validator.rb', line 85 def association_name return nil if plain? association_path&.association_names&.first&.to_sym end |
#association_path ⇒ Object
The AssociationPath for scoped fields (builds filter/order subqueries), or nil for plain columns.
79 80 81 |
# File 'lib/huginn/datatable/validator.rb', line 79 def association_path @association_path ||= (AssociationPath.call(model, @field) if scoped?) end |
#authorization_path ⇒ Object
Canonical chain of association reflection names (e.g. ["company", "people"]) used to match the allowlist. Table names and public aliases are normalized through the reflection.
58 59 60 61 62 |
# File 'lib/huginn/datatable/validator.rb', line 58 def return [] if plain? association_path&.association_names || [] end |
#column_type ⇒ Object
70 71 72 73 74 75 |
# File 'lib/huginn/datatable/validator.rb', line 70 def column_type return nil unless valid? klass = plain? ? model : association_path.target_klass klass.columns_hash[column].type end |
#correlated_order_expression ⇒ Object
91 92 93 |
# File 'lib/huginn/datatable/validator.rb', line 91 def association_path&. end |
#plain? ⇒ Boolean
36 37 38 |
# File 'lib/huginn/datatable/validator.rb', line 36 def plain? segments.size == 1 end |
#scoped? ⇒ Boolean
40 41 42 |
# File 'lib/huginn/datatable/validator.rb', line 40 def scoped? !plain? && segments.size >= 2 end |
#segments ⇒ Object
32 33 34 |
# File 'lib/huginn/datatable/validator.rb', line 32 def segments @segments ||= @field.split(".") end |
#valid? ⇒ Boolean
44 45 46 47 48 49 50 51 52 53 |
# File 'lib/huginn/datatable/validator.rb', line 44 def valid? return false if strict_denied? return false unless segments.all? { |segment| segment.match?(FIELD_PATTERN) } if plain? model.columns_hash.key?(column) else association_path&.valid? && association_path.target_klass.columns_hash.key?(column) end end |