typed_eav 0.1.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 +7 -0
- data/CHANGELOG.md +12 -0
- data/MIT-LICENSE +21 -0
- data/README.md +494 -0
- data/Rakefile +13 -0
- data/app/models/typed_eav/application_record.rb +7 -0
- data/app/models/typed_eav/field/base.rb +234 -0
- data/app/models/typed_eav/field/boolean.rb +22 -0
- data/app/models/typed_eav/field/color.rb +16 -0
- data/app/models/typed_eav/field/date.rb +24 -0
- data/app/models/typed_eav/field/date_array.rb +34 -0
- data/app/models/typed_eav/field/date_time.rb +29 -0
- data/app/models/typed_eav/field/decimal.rb +30 -0
- data/app/models/typed_eav/field/decimal_array.rb +31 -0
- data/app/models/typed_eav/field/email.rb +40 -0
- data/app/models/typed_eav/field/integer.rb +30 -0
- data/app/models/typed_eav/field/integer_array.rb +68 -0
- data/app/models/typed_eav/field/json.rb +26 -0
- data/app/models/typed_eav/field/long_text.rb +19 -0
- data/app/models/typed_eav/field/multi_select.rb +41 -0
- data/app/models/typed_eav/field/select.rb +28 -0
- data/app/models/typed_eav/field/text.rb +41 -0
- data/app/models/typed_eav/field/text_array.rb +36 -0
- data/app/models/typed_eav/field/url.rb +40 -0
- data/app/models/typed_eav/option.rb +24 -0
- data/app/models/typed_eav/section.rb +25 -0
- data/app/models/typed_eav/value.rb +149 -0
- data/db/migrate/20260330000000_create_typed_eav_tables.rb +132 -0
- data/lib/generators/typed_eav/install/install_generator.rb +28 -0
- data/lib/generators/typed_eav/scaffold/scaffold_generator.rb +106 -0
- data/lib/generators/typed_eav/scaffold/templates/config/initializers/typed_eav.rb +45 -0
- data/lib/generators/typed_eav/scaffold/templates/controllers/concerns/typed_eav_controller_concern.rb +24 -0
- data/lib/generators/typed_eav/scaffold/templates/controllers/typed_eav_controller.rb +231 -0
- data/lib/generators/typed_eav/scaffold/templates/helpers/typed_eav_helper.rb +150 -0
- data/lib/generators/typed_eav/scaffold/templates/javascript/controllers/array_field_controller.js +64 -0
- data/lib/generators/typed_eav/scaffold/templates/javascript/controllers/typed_eav_form_controller.js +32 -0
- data/lib/generators/typed_eav/scaffold/templates/views/shared/_array_field.html.erb +23 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/edit.html.erb +47 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/finders/_form.html.erb +80 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_boolean.html.erb +12 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_color.html.erb +11 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_common_fields.html.erb +57 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_date.html.erb +21 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_date_array.html.erb +16 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_date_time.html.erb +21 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_decimal.html.erb +21 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_decimal_array.html.erb +16 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_email.html.erb +11 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_integer.html.erb +21 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_integer_array.html.erb +16 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_json.html.erb +11 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_long_text.html.erb +21 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_multi_select.html.erb +6 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_select.html.erb +14 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_text.html.erb +26 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_text_array.html.erb +16 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_url.html.erb +11 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/index.html.erb +42 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/new.html.erb +7 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/show.html.erb +44 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_boolean.html.erb +10 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_color.html.erb +4 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_date.html.erb +6 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_date_array.html.erb +9 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_date_time.html.erb +5 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_decimal.html.erb +6 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_decimal_array.html.erb +9 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_email.html.erb +5 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_integer.html.erb +6 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_integer_array.html.erb +9 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_json.html.erb +7 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_long_text.html.erb +7 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_multi_select.html.erb +7 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_select.html.erb +7 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_text.html.erb +6 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_text_array.html.erb +9 -0
- data/lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_url.html.erb +5 -0
- data/lib/typed_eav/column_mapping.rb +64 -0
- data/lib/typed_eav/config.rb +91 -0
- data/lib/typed_eav/engine.rb +20 -0
- data/lib/typed_eav/has_typed_eav.rb +484 -0
- data/lib/typed_eav/query_builder.rb +133 -0
- data/lib/typed_eav/registry.rb +52 -0
- data/lib/typed_eav/version.rb +5 -0
- data/lib/typed_eav.rb +86 -0
- metadata +146 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TypedEAV
|
|
4
|
+
# Replaces the per-type Finder class hierarchy from active_fields.
|
|
5
|
+
#
|
|
6
|
+
# Because values live in native typed columns, ActiveRecord already knows
|
|
7
|
+
# the column types from the schema. Arel predicates (eq, gt, lt, matches, etc.)
|
|
8
|
+
# automatically go through the column's ActiveRecord::Type for casting.
|
|
9
|
+
#
|
|
10
|
+
# This means:
|
|
11
|
+
# where(integer_value: "42") -> Rails casts "42" to 42 automatically
|
|
12
|
+
# arel[:date_value].gt(value) -> Rails casts string dates to Date objects
|
|
13
|
+
#
|
|
14
|
+
# No manual CAST() calls. No per-type caster classes for queries.
|
|
15
|
+
# One module handles all field types.
|
|
16
|
+
#
|
|
17
|
+
# Usage:
|
|
18
|
+
# QueryBuilder.filter(field, :gt, 42)
|
|
19
|
+
# # => ActiveRecord::Relation scoped to matching values
|
|
20
|
+
#
|
|
21
|
+
# QueryBuilder.filter(field, :contains, "hello")
|
|
22
|
+
# # => ILIKE query against the field's string_value column
|
|
23
|
+
#
|
|
24
|
+
class QueryBuilder
|
|
25
|
+
class << self
|
|
26
|
+
# Returns an ActiveRecord::Relation of TypedEAV::Value records
|
|
27
|
+
# matching the given field, operator, and comparison value.
|
|
28
|
+
#
|
|
29
|
+
# The relation is suitable for subquery use:
|
|
30
|
+
# Model.where(id: QueryBuilder.filter(field, :gt, 5).select(:entity_id))
|
|
31
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength -- one operator-dispatch case statement; flattening keeps the supported-operators list scannable in one place.
|
|
32
|
+
def filter(field, operator, value)
|
|
33
|
+
col = field.class.value_column
|
|
34
|
+
operator = operator.to_sym
|
|
35
|
+
|
|
36
|
+
# Validate operator is supported by this field type
|
|
37
|
+
supported = field.class.supported_operators
|
|
38
|
+
unless supported.include?(operator)
|
|
39
|
+
raise ArgumentError,
|
|
40
|
+
"Operator :#{operator} is not supported for #{field.class.name}. " \
|
|
41
|
+
"Supported operators: #{supported.map { |o| ":#{o}" }.join(", ")}"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
arel_col = values_table[col]
|
|
45
|
+
|
|
46
|
+
base = value_scope(field)
|
|
47
|
+
|
|
48
|
+
case operator
|
|
49
|
+
when :eq
|
|
50
|
+
eq_predicate(base, arel_col, col, value)
|
|
51
|
+
when :not_eq
|
|
52
|
+
not_eq_predicate(base, arel_col, col, value)
|
|
53
|
+
when :gt
|
|
54
|
+
base.where(arel_col.gt(value))
|
|
55
|
+
when :gteq
|
|
56
|
+
base.where(arel_col.gteq(value))
|
|
57
|
+
when :lt
|
|
58
|
+
base.where(arel_col.lt(value))
|
|
59
|
+
when :lteq
|
|
60
|
+
base.where(arel_col.lteq(value))
|
|
61
|
+
when :between
|
|
62
|
+
unless value.respond_to?(:first) && value.respond_to?(:last)
|
|
63
|
+
raise ArgumentError,
|
|
64
|
+
":between expects a Range or two-element Array"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
base.where(arel_col.between(value.first..value.last))
|
|
68
|
+
when :contains
|
|
69
|
+
base.where(arel_col.matches("%#{sanitize_like(value)}%"))
|
|
70
|
+
when :not_contains
|
|
71
|
+
base.where(arel_col.does_not_match("%#{sanitize_like(value)}%"))
|
|
72
|
+
when :starts_with
|
|
73
|
+
base.where(arel_col.matches("#{sanitize_like(value)}%"))
|
|
74
|
+
when :ends_with
|
|
75
|
+
base.where(arel_col.matches("%#{sanitize_like(value)}"))
|
|
76
|
+
when :is_null
|
|
77
|
+
base.where(col => nil)
|
|
78
|
+
when :is_not_null
|
|
79
|
+
base.where.not(col => nil)
|
|
80
|
+
when :any_eq
|
|
81
|
+
# For json_value arrays: contains the given element
|
|
82
|
+
base.where("#{col} @> ?", [value].to_json)
|
|
83
|
+
when :all_eq
|
|
84
|
+
# For json_value arrays: contains all given elements
|
|
85
|
+
base.where("#{col} @> ?", Array(value).to_json)
|
|
86
|
+
else
|
|
87
|
+
raise ArgumentError, "Unhandled operator: #{operator}"
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
|
92
|
+
|
|
93
|
+
# Convenience: returns entity IDs matching the filter.
|
|
94
|
+
# Useful for subqueries: Model.where(id: QueryBuilder.entity_ids(field, :gt, 5))
|
|
95
|
+
def entity_ids(field, operator, value)
|
|
96
|
+
filter(field, operator, value).distinct.select(:entity_id)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
private
|
|
100
|
+
|
|
101
|
+
def values_table
|
|
102
|
+
TypedEAV::Value.arel_table
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Base scope: values for this specific field
|
|
106
|
+
def value_scope(field)
|
|
107
|
+
TypedEAV::Value.where(field: field)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# NULL-safe equality: AR `where(col => nil)` already emits IS NULL, and
|
|
111
|
+
# `where(col => true/false)` already emits IS TRUE/FALSE on PG, so the
|
|
112
|
+
# same `base.where(col => value)` covers booleans and other types.
|
|
113
|
+
def eq_predicate(base, _arel_col, col, value)
|
|
114
|
+
base.where(col => value)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# NULL-safe inequality: includes NULL rows (they're "not equal" to any value)
|
|
118
|
+
def not_eq_predicate(base, arel_col, col, value)
|
|
119
|
+
if value.nil?
|
|
120
|
+
base.where.not(col => nil)
|
|
121
|
+
else
|
|
122
|
+
# NOT col = value OR col IS NULL
|
|
123
|
+
# Without the OR, NULLs are excluded (SQL tri-valued logic)
|
|
124
|
+
base.where(arel_col.not_eq(value).or(arel_col.eq(nil)))
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def sanitize_like(value)
|
|
129
|
+
value.to_s.gsub(/[%_\\]/) { |m| "\\#{m}" }
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/configurable"
|
|
4
|
+
|
|
5
|
+
module TypedEAV
|
|
6
|
+
# Registry of entity types (host ActiveRecord models) that have opted
|
|
7
|
+
# into typed fields via `has_typed_eav`. Tracks optional field-type
|
|
8
|
+
# restrictions per entity.
|
|
9
|
+
#
|
|
10
|
+
# Populated automatically when a host model calls `has_typed_eav`;
|
|
11
|
+
# read by Field::Base#validate_type_allowed_for_entity to enforce
|
|
12
|
+
# restrictions on field creation.
|
|
13
|
+
class Registry
|
|
14
|
+
include ActiveSupport::Configurable
|
|
15
|
+
|
|
16
|
+
config_accessor(:entities) { {} }
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
# Register an entity type with optional type restrictions.
|
|
20
|
+
def register(entity_type, types: nil)
|
|
21
|
+
entities[entity_type] = { types: types }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# All registered entity type names.
|
|
25
|
+
def entity_types
|
|
26
|
+
entities.keys
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Field-type restrictions for a given entity, or nil if unrestricted.
|
|
30
|
+
def allowed_types_for(entity_type)
|
|
31
|
+
entry = entities[entity_type]
|
|
32
|
+
return nil unless entry
|
|
33
|
+
|
|
34
|
+
entry[:types]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Whether a field type class is allowed for an entity.
|
|
38
|
+
def type_allowed?(entity_type, field_type_class)
|
|
39
|
+
allowed = allowed_types_for(entity_type)
|
|
40
|
+
return true if allowed.nil?
|
|
41
|
+
|
|
42
|
+
type_name = field_type_class.name.demodulize.underscore.to_sym
|
|
43
|
+
allowed.include?(type_name)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Clear all registrations (test isolation).
|
|
47
|
+
def reset!
|
|
48
|
+
entities.clear
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
data/lib/typed_eav.rb
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/inflector"
|
|
4
|
+
ActiveSupport::Inflector.inflections(:en) do |inflect|
|
|
5
|
+
inflect.acronym "EAV"
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
require_relative "typed_eav/version"
|
|
9
|
+
require_relative "typed_eav/engine"
|
|
10
|
+
|
|
11
|
+
module TypedEAV
|
|
12
|
+
extend ActiveSupport::Autoload
|
|
13
|
+
|
|
14
|
+
autoload :Config
|
|
15
|
+
autoload :Registry
|
|
16
|
+
autoload :HasTypedEAV
|
|
17
|
+
autoload :QueryBuilder
|
|
18
|
+
|
|
19
|
+
# Raised when a model declared `has_typed_eav scope_method: ...` but no
|
|
20
|
+
# scope can be resolved at query time and `config.require_scope` is truthy.
|
|
21
|
+
class ScopeRequired < StandardError; end
|
|
22
|
+
|
|
23
|
+
THREAD_SCOPE_STACK = :typed_eav_scope_stack
|
|
24
|
+
THREAD_UNSCOPED = :typed_eav_unscoped
|
|
25
|
+
private_constant :THREAD_SCOPE_STACK, :THREAD_UNSCOPED
|
|
26
|
+
|
|
27
|
+
class << self
|
|
28
|
+
def config
|
|
29
|
+
yield Config if block_given?
|
|
30
|
+
Config
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
alias configure config
|
|
34
|
+
|
|
35
|
+
def registry = Registry
|
|
36
|
+
|
|
37
|
+
# Current ambient scope value. Resolution order:
|
|
38
|
+
# 1. Inside `unscoped { }` → nil (hard bypass)
|
|
39
|
+
# 2. Innermost `with_scope(v)` → v
|
|
40
|
+
# 3. Configured `scope_resolver` callable
|
|
41
|
+
# 4. nil
|
|
42
|
+
#
|
|
43
|
+
# Returns a string (via normalize), or nil when nothing resolves.
|
|
44
|
+
def current_scope
|
|
45
|
+
return nil if Thread.current[THREAD_UNSCOPED]
|
|
46
|
+
|
|
47
|
+
stack = Thread.current[THREAD_SCOPE_STACK]
|
|
48
|
+
return normalize_scope(stack.last) if stack.present?
|
|
49
|
+
|
|
50
|
+
normalize_scope(Config.scope_resolver&.call)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Run the block with `value` as the ambient scope, restoring the prior
|
|
54
|
+
# stack on exit (exception-safe). Nests cleanly.
|
|
55
|
+
def with_scope(value)
|
|
56
|
+
stack = (Thread.current[THREAD_SCOPE_STACK] ||= [])
|
|
57
|
+
stack.push(value)
|
|
58
|
+
yield
|
|
59
|
+
ensure
|
|
60
|
+
stack&.pop
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Run the block with scope enforcement disabled. Queries return results
|
|
64
|
+
# across all scopes. Use for admin tools, migrations, and tests.
|
|
65
|
+
def unscoped
|
|
66
|
+
prev = Thread.current[THREAD_UNSCOPED]
|
|
67
|
+
Thread.current[THREAD_UNSCOPED] = true
|
|
68
|
+
yield
|
|
69
|
+
ensure
|
|
70
|
+
Thread.current[THREAD_UNSCOPED] = prev
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# True when inside an `unscoped { }` block.
|
|
74
|
+
def unscoped?
|
|
75
|
+
!!Thread.current[THREAD_UNSCOPED]
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Coerce resolver/with_scope/explicit-kwarg inputs into the string shape
|
|
79
|
+
# stored in the `scope` column. Accepts raw scalars or AR records.
|
|
80
|
+
def normalize_scope(value)
|
|
81
|
+
return nil if value.nil?
|
|
82
|
+
|
|
83
|
+
value.respond_to?(:id) ? value.id.to_s : value.to_s
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: typed_eav
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Darrin Chuk
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: rails
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '7.1'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '7.1'
|
|
26
|
+
description: Add dynamic custom fields to ActiveRecord models at runtime using native
|
|
27
|
+
database typed columns instead of jsonb blobs. Hybrid EAV with real indexes, real
|
|
28
|
+
types, real query performance.
|
|
29
|
+
email:
|
|
30
|
+
- me@dchuk.com
|
|
31
|
+
executables: []
|
|
32
|
+
extensions: []
|
|
33
|
+
extra_rdoc_files: []
|
|
34
|
+
files:
|
|
35
|
+
- CHANGELOG.md
|
|
36
|
+
- MIT-LICENSE
|
|
37
|
+
- README.md
|
|
38
|
+
- Rakefile
|
|
39
|
+
- app/models/typed_eav/application_record.rb
|
|
40
|
+
- app/models/typed_eav/field/base.rb
|
|
41
|
+
- app/models/typed_eav/field/boolean.rb
|
|
42
|
+
- app/models/typed_eav/field/color.rb
|
|
43
|
+
- app/models/typed_eav/field/date.rb
|
|
44
|
+
- app/models/typed_eav/field/date_array.rb
|
|
45
|
+
- app/models/typed_eav/field/date_time.rb
|
|
46
|
+
- app/models/typed_eav/field/decimal.rb
|
|
47
|
+
- app/models/typed_eav/field/decimal_array.rb
|
|
48
|
+
- app/models/typed_eav/field/email.rb
|
|
49
|
+
- app/models/typed_eav/field/integer.rb
|
|
50
|
+
- app/models/typed_eav/field/integer_array.rb
|
|
51
|
+
- app/models/typed_eav/field/json.rb
|
|
52
|
+
- app/models/typed_eav/field/long_text.rb
|
|
53
|
+
- app/models/typed_eav/field/multi_select.rb
|
|
54
|
+
- app/models/typed_eav/field/select.rb
|
|
55
|
+
- app/models/typed_eav/field/text.rb
|
|
56
|
+
- app/models/typed_eav/field/text_array.rb
|
|
57
|
+
- app/models/typed_eav/field/url.rb
|
|
58
|
+
- app/models/typed_eav/option.rb
|
|
59
|
+
- app/models/typed_eav/section.rb
|
|
60
|
+
- app/models/typed_eav/value.rb
|
|
61
|
+
- db/migrate/20260330000000_create_typed_eav_tables.rb
|
|
62
|
+
- lib/generators/typed_eav/install/install_generator.rb
|
|
63
|
+
- lib/generators/typed_eav/scaffold/scaffold_generator.rb
|
|
64
|
+
- lib/generators/typed_eav/scaffold/templates/config/initializers/typed_eav.rb
|
|
65
|
+
- lib/generators/typed_eav/scaffold/templates/controllers/concerns/typed_eav_controller_concern.rb
|
|
66
|
+
- lib/generators/typed_eav/scaffold/templates/controllers/typed_eav_controller.rb
|
|
67
|
+
- lib/generators/typed_eav/scaffold/templates/helpers/typed_eav_helper.rb
|
|
68
|
+
- lib/generators/typed_eav/scaffold/templates/javascript/controllers/array_field_controller.js
|
|
69
|
+
- lib/generators/typed_eav/scaffold/templates/javascript/controllers/typed_eav_form_controller.js
|
|
70
|
+
- lib/generators/typed_eav/scaffold/templates/views/shared/_array_field.html.erb
|
|
71
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/edit.html.erb
|
|
72
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/finders/_form.html.erb
|
|
73
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_boolean.html.erb
|
|
74
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_color.html.erb
|
|
75
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_common_fields.html.erb
|
|
76
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_date.html.erb
|
|
77
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_date_array.html.erb
|
|
78
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_date_time.html.erb
|
|
79
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_decimal.html.erb
|
|
80
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_decimal_array.html.erb
|
|
81
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_email.html.erb
|
|
82
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_integer.html.erb
|
|
83
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_integer_array.html.erb
|
|
84
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_json.html.erb
|
|
85
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_long_text.html.erb
|
|
86
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_multi_select.html.erb
|
|
87
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_select.html.erb
|
|
88
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_text.html.erb
|
|
89
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_text_array.html.erb
|
|
90
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/forms/_url.html.erb
|
|
91
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/index.html.erb
|
|
92
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/new.html.erb
|
|
93
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/show.html.erb
|
|
94
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_boolean.html.erb
|
|
95
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_color.html.erb
|
|
96
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_date.html.erb
|
|
97
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_date_array.html.erb
|
|
98
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_date_time.html.erb
|
|
99
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_decimal.html.erb
|
|
100
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_decimal_array.html.erb
|
|
101
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_email.html.erb
|
|
102
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_integer.html.erb
|
|
103
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_integer_array.html.erb
|
|
104
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_json.html.erb
|
|
105
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_long_text.html.erb
|
|
106
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_multi_select.html.erb
|
|
107
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_select.html.erb
|
|
108
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_text.html.erb
|
|
109
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_text_array.html.erb
|
|
110
|
+
- lib/generators/typed_eav/scaffold/templates/views/typed_eav/values/inputs/_url.html.erb
|
|
111
|
+
- lib/typed_eav.rb
|
|
112
|
+
- lib/typed_eav/column_mapping.rb
|
|
113
|
+
- lib/typed_eav/config.rb
|
|
114
|
+
- lib/typed_eav/engine.rb
|
|
115
|
+
- lib/typed_eav/has_typed_eav.rb
|
|
116
|
+
- lib/typed_eav/query_builder.rb
|
|
117
|
+
- lib/typed_eav/registry.rb
|
|
118
|
+
- lib/typed_eav/version.rb
|
|
119
|
+
homepage: https://github.com/dchuk/typed_eav
|
|
120
|
+
licenses:
|
|
121
|
+
- MIT
|
|
122
|
+
metadata:
|
|
123
|
+
homepage_uri: https://github.com/dchuk/typed_eav
|
|
124
|
+
source_code_uri: https://github.com/dchuk/typed_eav
|
|
125
|
+
changelog_uri: https://github.com/dchuk/typed_eav/blob/main/CHANGELOG.md
|
|
126
|
+
bug_tracker_uri: https://github.com/dchuk/typed_eav/issues
|
|
127
|
+
allowed_push_host: https://rubygems.org
|
|
128
|
+
rubygems_mfa_required: 'true'
|
|
129
|
+
rdoc_options: []
|
|
130
|
+
require_paths:
|
|
131
|
+
- lib
|
|
132
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
133
|
+
requirements:
|
|
134
|
+
- - ">="
|
|
135
|
+
- !ruby/object:Gem::Version
|
|
136
|
+
version: '3.1'
|
|
137
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
138
|
+
requirements:
|
|
139
|
+
- - ">="
|
|
140
|
+
- !ruby/object:Gem::Version
|
|
141
|
+
version: '0'
|
|
142
|
+
requirements: []
|
|
143
|
+
rubygems_version: 3.7.1
|
|
144
|
+
specification_version: 4
|
|
145
|
+
summary: Typed custom fields for ActiveRecord models
|
|
146
|
+
test_files: []
|