active_fields 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +5 -4
- data/CHANGELOG.md +33 -2
- data/README.md +478 -90
- data/app/models/active_fields/field/boolean.rb +3 -0
- data/app/models/active_fields/field/date.rb +3 -0
- data/app/models/active_fields/field/date_array.rb +3 -0
- data/app/models/active_fields/field/date_time.rb +4 -1
- data/app/models/active_fields/field/date_time_array.rb +4 -1
- data/app/models/active_fields/field/decimal.rb +6 -1
- data/app/models/active_fields/field/decimal_array.rb +6 -1
- data/app/models/active_fields/field/enum.rb +3 -0
- data/app/models/active_fields/field/enum_array.rb +3 -0
- data/app/models/active_fields/field/integer.rb +3 -0
- data/app/models/active_fields/field/integer_array.rb +3 -0
- data/app/models/active_fields/field/text.rb +3 -0
- data/app/models/active_fields/field/text_array.rb +3 -0
- data/app/models/active_fields/field.rb +5 -0
- data/app/models/concerns/active_fields/customizable_concern.rb +93 -4
- data/app/models/concerns/active_fields/field_concern.rb +26 -3
- data/db/migrate/20240229230000_create_active_fields_tables.rb +1 -1
- data/lib/active_fields/casters/date_time_caster.rb +1 -3
- data/lib/active_fields/casters/decimal_caster.rb +2 -5
- data/lib/active_fields/constants.rb +55 -0
- data/lib/active_fields/engine.rb +7 -0
- data/lib/active_fields/finders/array_finder.rb +112 -0
- data/lib/active_fields/finders/base_finder.rb +73 -0
- data/lib/active_fields/finders/boolean_finder.rb +20 -0
- data/lib/active_fields/finders/date_array_finder.rb +65 -0
- data/lib/active_fields/finders/date_finder.rb +32 -0
- data/lib/active_fields/finders/date_time_array_finder.rb +65 -0
- data/lib/active_fields/finders/date_time_finder.rb +32 -0
- data/lib/active_fields/finders/decimal_array_finder.rb +65 -0
- data/lib/active_fields/finders/decimal_finder.rb +32 -0
- data/lib/active_fields/finders/enum_array_finder.rb +41 -0
- data/lib/active_fields/finders/enum_finder.rb +20 -0
- data/lib/active_fields/finders/integer_array_finder.rb +65 -0
- data/lib/active_fields/finders/integer_finder.rb +32 -0
- data/lib/active_fields/finders/singular_finder.rb +66 -0
- data/lib/active_fields/finders/text_array_finder.rb +47 -0
- data/lib/active_fields/finders/text_finder.rb +81 -0
- data/lib/active_fields/has_active_fields.rb +3 -4
- data/lib/active_fields/registry.rb +38 -0
- data/lib/active_fields/version.rb +1 -1
- data/lib/active_fields.rb +79 -31
- data/lib/generators/active_fields/install/install_generator.rb +1 -1
- data/lib/generators/active_fields/scaffold/USAGE +9 -0
- data/lib/generators/active_fields/scaffold/scaffold_generator.rb +34 -0
- data/lib/generators/active_fields/scaffold/templates/controllers/active_fields_controller.rb +133 -0
- data/lib/generators/active_fields/scaffold/templates/controllers/concerns/active_fields_controller_concern.rb +33 -0
- data/lib/generators/active_fields/scaffold/templates/helpers/active_fields_helper.rb +100 -0
- data/lib/generators/active_fields/scaffold/templates/javascript/controllers/active_fields_finders_form_controller.js +59 -0
- data/lib/generators/active_fields/scaffold/templates/javascript/controllers/array_field_controller.js +25 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/edit.html.erb +5 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/finders/_form.html.erb +42 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/finders/inputs/_array_size.html.erb +16 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/finders/inputs/_boolean.html.erb +21 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/finders/inputs/_date.html.erb +16 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/finders/inputs/_date_array.html.erb +16 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/finders/inputs/_datetime.html.erb +16 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/finders/inputs/_datetime_array.html.erb +16 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/finders/inputs/_decimal.html.erb +16 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/finders/inputs/_decimal_array.html.erb +16 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/finders/inputs/_enum.html.erb +16 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/finders/inputs/_enum_array.html.erb +16 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/finders/inputs/_integer.html.erb +16 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/finders/inputs/_integer_array.html.erb +16 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/finders/inputs/_text.html.erb +16 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/finders/inputs/_text_array.html.erb +16 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_boolean.html.erb +53 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_date.html.erb +58 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_date_array.html.erb +70 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_datetime.html.erb +63 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_datetime_array.html.erb +75 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_decimal.html.erb +63 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_decimal_array.html.erb +76 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_enum.html.erb +61 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_enum_array.html.erb +73 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_integer.html.erb +58 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_integer_array.html.erb +70 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_text.html.erb +53 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/forms/_text_array.html.erb +70 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/index.html.erb +41 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/new.html.erb +5 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/show.html.erb +29 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_boolean.html.erb +8 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_date.html.erb +4 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_date_array.html.erb +12 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_datetime.html.erb +4 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_datetime_array.html.erb +12 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_decimal.html.erb +4 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_decimal_array.html.erb +12 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_enum.html.erb +4 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_enum_array.html.erb +4 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_integer.html.erb +4 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_integer_array.html.erb +12 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_text.html.erb +4 -0
- data/lib/generators/active_fields/scaffold/templates/views/active_fields/values/inputs/_text_array.html.erb +12 -0
- data/lib/generators/active_fields/scaffold/templates/views/shared/_array_field.html.erb +19 -0
- metadata +78 -10
- data/lib/active_fields/customizable_config.rb +0 -24
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveFields
|
4
|
+
module Finders
|
5
|
+
class BooleanFinder < SingularFinder
|
6
|
+
operation :eq, operator: OPS[:eq] do |value|
|
7
|
+
scope.where(eq(casted_value_field("boolean"), cast(value)))
|
8
|
+
end
|
9
|
+
operation :not_eq, operator: OPS[:not_eq] do |value|
|
10
|
+
scope.where(not_eq(casted_value_field("boolean"), cast(value)))
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def cast(value)
|
16
|
+
Casters::BooleanCaster.new.deserialize(value)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveFields
|
4
|
+
module Finders
|
5
|
+
class DateArrayFinder < ArrayFinder
|
6
|
+
operation :include, operator: OPS[:include] do |value|
|
7
|
+
scope.where(value_match_any("==", cast(value)))
|
8
|
+
end
|
9
|
+
operation :not_include, operator: OPS[:not_include] do |value|
|
10
|
+
scope.where.not(value_match_any("==", cast(value)))
|
11
|
+
end
|
12
|
+
operation :any_gt, operator: OPS[:any_gt] do |value|
|
13
|
+
scope.where(value_match_any(">", cast(value)))
|
14
|
+
end
|
15
|
+
operation :any_gteq, operator: OPS[:any_gteq] do |value|
|
16
|
+
scope.where(value_match_any(">=", cast(value)))
|
17
|
+
end
|
18
|
+
operation :any_lt, operator: OPS[:any_lt] do |value|
|
19
|
+
scope.where(value_match_any("<", cast(value)))
|
20
|
+
end
|
21
|
+
operation :any_lteq, operator: OPS[:any_lteq] do |value|
|
22
|
+
scope.where(value_match_any("<=", cast(value)))
|
23
|
+
end
|
24
|
+
operation :all_gt, operator: OPS[:all_gt] do |value|
|
25
|
+
scope.where(value_match_all(">", cast(value)))
|
26
|
+
end
|
27
|
+
operation :all_gteq, operator: OPS[:all_gteq] do |value|
|
28
|
+
scope.where(value_match_all(">=", cast(value)))
|
29
|
+
end
|
30
|
+
operation :all_lt, operator: OPS[:all_lt] do |value|
|
31
|
+
scope.where(value_match_all("<", cast(value)))
|
32
|
+
end
|
33
|
+
operation :all_lteq, operator: OPS[:all_lteq] do |value|
|
34
|
+
scope.where(value_match_all("<=", cast(value)))
|
35
|
+
end
|
36
|
+
operation :size_eq, operator: OPS[:size_eq] do |value|
|
37
|
+
scope.where(value_size_eq(value))
|
38
|
+
end
|
39
|
+
operation :size_not_eq, operator: OPS[:size_not_eq] do |value|
|
40
|
+
scope.where(value_size_not_eq(value))
|
41
|
+
end
|
42
|
+
operation :size_gt, operator: OPS[:size_gt] do |value|
|
43
|
+
scope.where(value_size_gt(value))
|
44
|
+
end
|
45
|
+
operation :size_gteq, operator: OPS[:size_gteq] do |value|
|
46
|
+
scope.where(value_size_gteq(value))
|
47
|
+
end
|
48
|
+
operation :size_lt, operator: OPS[:size_lt] do |value|
|
49
|
+
scope.where(value_size_lt(value))
|
50
|
+
end
|
51
|
+
operation :size_lteq, operator: OPS[:size_lteq] do |value|
|
52
|
+
scope.where(value_size_lteq(value))
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def cast(value)
|
58
|
+
caster = Casters::DateCaster.new
|
59
|
+
caster.serialize(caster.deserialize(value))
|
60
|
+
end
|
61
|
+
|
62
|
+
def jsonpath(operator) = "$[*] ? (@.date() #{operator} $value.date())"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveFields
|
4
|
+
module Finders
|
5
|
+
class DateFinder < SingularFinder
|
6
|
+
operation :eq, operator: OPS[:eq] do |value|
|
7
|
+
scope.where(eq(casted_value_field("date"), cast(value)))
|
8
|
+
end
|
9
|
+
operation :not_eq, operator: OPS[:not_eq] do |value|
|
10
|
+
scope.where(not_eq(casted_value_field("date"), cast(value)))
|
11
|
+
end
|
12
|
+
operation :gt, operator: OPS[:gt] do |value|
|
13
|
+
scope.where(gt(casted_value_field("date"), cast(value)))
|
14
|
+
end
|
15
|
+
operation :gteq, operator: OPS[:gteq] do |value|
|
16
|
+
scope.where(gteq(casted_value_field("date"), cast(value)))
|
17
|
+
end
|
18
|
+
operation :lt, operator: OPS[:lt] do |value|
|
19
|
+
scope.where(lt(casted_value_field("date"), cast(value)))
|
20
|
+
end
|
21
|
+
operation :lteq, operator: OPS[:lteq] do |value|
|
22
|
+
scope.where(lteq(casted_value_field("date"), cast(value)))
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def cast(value)
|
28
|
+
Casters::DateCaster.new.deserialize(value)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveFields
|
4
|
+
module Finders
|
5
|
+
class DateTimeArrayFinder < ArrayFinder
|
6
|
+
operation :include, operator: OPS[:include] do |value|
|
7
|
+
scope.where(value_match_any("==", cast(value)))
|
8
|
+
end
|
9
|
+
operation :not_include, operator: OPS[:not_include] do |value|
|
10
|
+
scope.where.not(value_match_any("==", cast(value)))
|
11
|
+
end
|
12
|
+
operation :any_gt, operator: OPS[:any_gt] do |value|
|
13
|
+
scope.where(value_match_any(">", cast(value)))
|
14
|
+
end
|
15
|
+
operation :any_gteq, operator: OPS[:any_gteq] do |value|
|
16
|
+
scope.where(value_match_any(">=", cast(value)))
|
17
|
+
end
|
18
|
+
operation :any_lt, operator: OPS[:any_lt] do |value|
|
19
|
+
scope.where(value_match_any("<", cast(value)))
|
20
|
+
end
|
21
|
+
operation :any_lteq, operator: OPS[:any_lteq] do |value|
|
22
|
+
scope.where(value_match_any("<=", cast(value)))
|
23
|
+
end
|
24
|
+
operation :all_gt, operator: OPS[:all_gt] do |value|
|
25
|
+
scope.where(value_match_all(">", cast(value)))
|
26
|
+
end
|
27
|
+
operation :all_gteq, operator: OPS[:all_gteq] do |value|
|
28
|
+
scope.where(value_match_all(">=", cast(value)))
|
29
|
+
end
|
30
|
+
operation :all_lt, operator: OPS[:all_lt] do |value|
|
31
|
+
scope.where(value_match_all("<", cast(value)))
|
32
|
+
end
|
33
|
+
operation :all_lteq, operator: OPS[:all_lteq] do |value|
|
34
|
+
scope.where(value_match_all("<=", cast(value)))
|
35
|
+
end
|
36
|
+
operation :size_eq, operator: OPS[:size_eq] do |value|
|
37
|
+
scope.where(value_size_eq(value))
|
38
|
+
end
|
39
|
+
operation :size_not_eq, operator: OPS[:size_not_eq] do |value|
|
40
|
+
scope.where(value_size_not_eq(value))
|
41
|
+
end
|
42
|
+
operation :size_gt, operator: OPS[:size_gt] do |value|
|
43
|
+
scope.where(value_size_gt(value))
|
44
|
+
end
|
45
|
+
operation :size_gteq, operator: OPS[:size_gteq] do |value|
|
46
|
+
scope.where(value_size_gteq(value))
|
47
|
+
end
|
48
|
+
operation :size_lt, operator: OPS[:size_lt] do |value|
|
49
|
+
scope.where(value_size_lt(value))
|
50
|
+
end
|
51
|
+
operation :size_lteq, operator: OPS[:size_lteq] do |value|
|
52
|
+
scope.where(value_size_lteq(value))
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def cast(value)
|
58
|
+
caster = Casters::DateTimeCaster.new(precision: active_field.precision)
|
59
|
+
caster.serialize(caster.deserialize(value))
|
60
|
+
end
|
61
|
+
|
62
|
+
def jsonpath(operator) = "$[*] ? (@.timestamp_tz() #{operator} $value.timestamp_tz())"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveFields
|
4
|
+
module Finders
|
5
|
+
class DateTimeFinder < SingularFinder
|
6
|
+
operation :eq, operator: OPS[:eq] do |value|
|
7
|
+
scope.where(eq(casted_value_field("timestamp"), cast(value)))
|
8
|
+
end
|
9
|
+
operation :not_eq, operator: OPS[:not_eq] do |value|
|
10
|
+
scope.where(not_eq(casted_value_field("timestamp"), cast(value)))
|
11
|
+
end
|
12
|
+
operation :gt, operator: OPS[:gt] do |value|
|
13
|
+
scope.where(gt(casted_value_field("timestamp"), cast(value)))
|
14
|
+
end
|
15
|
+
operation :gteq, operator: OPS[:gteq] do |value|
|
16
|
+
scope.where(gteq(casted_value_field("timestamp"), cast(value)))
|
17
|
+
end
|
18
|
+
operation :lt, operator: OPS[:lt] do |value|
|
19
|
+
scope.where(lt(casted_value_field("timestamp"), cast(value)))
|
20
|
+
end
|
21
|
+
operation :lteq, operator: OPS[:lteq] do |value|
|
22
|
+
scope.where(lteq(casted_value_field("timestamp"), cast(value)))
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def cast(value)
|
28
|
+
Casters::DateTimeCaster.new(precision: active_field.precision).deserialize(value)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveFields
|
4
|
+
module Finders
|
5
|
+
class DecimalArrayFinder < ArrayFinder
|
6
|
+
operation :include, operator: OPS[:include] do |value|
|
7
|
+
scope.where(value_match_any("==", cast(value)))
|
8
|
+
end
|
9
|
+
operation :not_include, operator: OPS[:not_include] do |value|
|
10
|
+
scope.where.not(value_match_any("==", cast(value)))
|
11
|
+
end
|
12
|
+
operation :any_gt, operator: OPS[:any_gt] do |value|
|
13
|
+
scope.where(value_match_any(">", cast(value)))
|
14
|
+
end
|
15
|
+
operation :any_gteq, operator: OPS[:any_gteq] do |value|
|
16
|
+
scope.where(value_match_any(">=", cast(value)))
|
17
|
+
end
|
18
|
+
operation :any_lt, operator: OPS[:any_lt] do |value|
|
19
|
+
scope.where(value_match_any("<", cast(value)))
|
20
|
+
end
|
21
|
+
operation :any_lteq, operator: OPS[:any_lteq] do |value|
|
22
|
+
scope.where(value_match_any("<=", cast(value)))
|
23
|
+
end
|
24
|
+
operation :all_gt, operator: OPS[:all_gt] do |value|
|
25
|
+
scope.where(value_match_all(">", cast(value)))
|
26
|
+
end
|
27
|
+
operation :all_gteq, operator: OPS[:all_gteq] do |value|
|
28
|
+
scope.where(value_match_all(">=", cast(value)))
|
29
|
+
end
|
30
|
+
operation :all_lt, operator: OPS[:all_lt] do |value|
|
31
|
+
scope.where(value_match_all("<", cast(value)))
|
32
|
+
end
|
33
|
+
operation :all_lteq, operator: OPS[:all_lteq] do |value|
|
34
|
+
scope.where(value_match_all("<=", cast(value)))
|
35
|
+
end
|
36
|
+
operation :size_eq, operator: OPS[:size_eq] do |value|
|
37
|
+
scope.where(value_size_eq(value))
|
38
|
+
end
|
39
|
+
operation :size_not_eq, operator: OPS[:size_not_eq] do |value|
|
40
|
+
scope.where(value_size_not_eq(value))
|
41
|
+
end
|
42
|
+
operation :size_gt, operator: OPS[:size_gt] do |value|
|
43
|
+
scope.where(value_size_gt(value))
|
44
|
+
end
|
45
|
+
operation :size_gteq, operator: OPS[:size_gteq] do |value|
|
46
|
+
scope.where(value_size_gteq(value))
|
47
|
+
end
|
48
|
+
operation :size_lt, operator: OPS[:size_lt] do |value|
|
49
|
+
scope.where(value_size_lt(value))
|
50
|
+
end
|
51
|
+
operation :size_lteq, operator: OPS[:size_lteq] do |value|
|
52
|
+
scope.where(value_size_lteq(value))
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def cast(value)
|
58
|
+
caster = Casters::DecimalCaster.new(precision: active_field.precision)
|
59
|
+
caster.serialize(caster.deserialize(value))
|
60
|
+
end
|
61
|
+
|
62
|
+
def jsonpath(operator) = "$[*] ? (@.number() #{operator} $value.number())"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveFields
|
4
|
+
module Finders
|
5
|
+
class DecimalFinder < SingularFinder
|
6
|
+
operation :eq, operator: OPS[:eq] do |value|
|
7
|
+
scope.where(eq(casted_value_field("decimal"), cast(value)))
|
8
|
+
end
|
9
|
+
operation :not_eq, operator: OPS[:not_eq] do |value|
|
10
|
+
scope.where(not_eq(casted_value_field("decimal"), cast(value)))
|
11
|
+
end
|
12
|
+
operation :gt, operator: OPS[:gt] do |value|
|
13
|
+
scope.where(gt(casted_value_field("decimal"), cast(value)))
|
14
|
+
end
|
15
|
+
operation :gteq, operator: OPS[:gteq] do |value|
|
16
|
+
scope.where(gteq(casted_value_field("decimal"), cast(value)))
|
17
|
+
end
|
18
|
+
operation :lt, operator: OPS[:lt] do |value|
|
19
|
+
scope.where(lt(casted_value_field("decimal"), cast(value)))
|
20
|
+
end
|
21
|
+
operation :lteq, operator: OPS[:lteq] do |value|
|
22
|
+
scope.where(lteq(casted_value_field("decimal"), cast(value)))
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def cast(value)
|
28
|
+
Casters::DecimalCaster.new(precision: active_field.precision).deserialize(value)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveFields
|
4
|
+
module Finders
|
5
|
+
class EnumArrayFinder < ArrayFinder
|
6
|
+
operation :include, operator: OPS[:include] do |value|
|
7
|
+
scope.where(value_match_any("==", cast(value)))
|
8
|
+
end
|
9
|
+
operation :not_include, operator: OPS[:not_include] do |value|
|
10
|
+
scope.where.not(value_match_any("==", cast(value)))
|
11
|
+
end
|
12
|
+
operation :size_eq, operator: OPS[:size_eq] do |value|
|
13
|
+
scope.where(value_size_eq(value))
|
14
|
+
end
|
15
|
+
operation :size_not_eq, operator: OPS[:size_not_eq] do |value|
|
16
|
+
scope.where(value_size_not_eq(value))
|
17
|
+
end
|
18
|
+
operation :size_gt, operator: OPS[:size_gt] do |value|
|
19
|
+
scope.where(value_size_gt(value))
|
20
|
+
end
|
21
|
+
operation :size_gteq, operator: OPS[:size_gteq] do |value|
|
22
|
+
scope.where(value_size_gteq(value))
|
23
|
+
end
|
24
|
+
operation :size_lt, operator: OPS[:size_lt] do |value|
|
25
|
+
scope.where(value_size_lt(value))
|
26
|
+
end
|
27
|
+
operation :size_lteq, operator: OPS[:size_lteq] do |value|
|
28
|
+
scope.where(value_size_lteq(value))
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def cast(value)
|
34
|
+
caster = Casters::EnumCaster.new
|
35
|
+
caster.serialize(caster.deserialize(value))
|
36
|
+
end
|
37
|
+
|
38
|
+
def jsonpath(operator) = "$[*] ? (@ #{operator} $value)"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveFields
|
4
|
+
module Finders
|
5
|
+
class EnumFinder < SingularFinder
|
6
|
+
operation :eq, operator: OPS[:eq] do |value|
|
7
|
+
scope.where(eq(casted_value_field("text"), cast(value)))
|
8
|
+
end
|
9
|
+
operation :not_eq, operator: OPS[:not_eq] do |value|
|
10
|
+
scope.where(not_eq(casted_value_field("text"), cast(value)))
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def cast(value)
|
16
|
+
Casters::EnumCaster.new.deserialize(value)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveFields
|
4
|
+
module Finders
|
5
|
+
class IntegerArrayFinder < ArrayFinder
|
6
|
+
operation :include, operator: OPS[:include] do |value|
|
7
|
+
scope.where(value_match_any("==", cast(value)))
|
8
|
+
end
|
9
|
+
operation :not_include, operator: OPS[:not_include] do |value|
|
10
|
+
scope.where.not(value_match_any("==", cast(value)))
|
11
|
+
end
|
12
|
+
operation :any_gt, operator: OPS[:any_gt] do |value|
|
13
|
+
scope.where(value_match_any(">", cast(value)))
|
14
|
+
end
|
15
|
+
operation :any_gteq, operator: OPS[:any_gteq] do |value|
|
16
|
+
scope.where(value_match_any(">=", cast(value)))
|
17
|
+
end
|
18
|
+
operation :any_lt, operator: OPS[:any_lt] do |value|
|
19
|
+
scope.where(value_match_any("<", cast(value)))
|
20
|
+
end
|
21
|
+
operation :any_lteq, operator: OPS[:any_lteq] do |value|
|
22
|
+
scope.where(value_match_any("<=", cast(value)))
|
23
|
+
end
|
24
|
+
operation :all_gt, operator: OPS[:all_gt] do |value|
|
25
|
+
scope.where(value_match_all(">", cast(value)))
|
26
|
+
end
|
27
|
+
operation :all_gteq, operator: OPS[:all_gteq] do |value|
|
28
|
+
scope.where(value_match_all(">=", cast(value)))
|
29
|
+
end
|
30
|
+
operation :all_lt, operator: OPS[:all_lt] do |value|
|
31
|
+
scope.where(value_match_all("<", cast(value)))
|
32
|
+
end
|
33
|
+
operation :all_lteq, operator: OPS[:all_lteq] do |value|
|
34
|
+
scope.where(value_match_all("<=", cast(value)))
|
35
|
+
end
|
36
|
+
operation :size_eq, operator: OPS[:size_eq] do |value|
|
37
|
+
scope.where(value_size_eq(value))
|
38
|
+
end
|
39
|
+
operation :size_not_eq, operator: OPS[:size_not_eq] do |value|
|
40
|
+
scope.where(value_size_not_eq(value))
|
41
|
+
end
|
42
|
+
operation :size_gt, operator: OPS[:size_gt] do |value|
|
43
|
+
scope.where(value_size_gt(value))
|
44
|
+
end
|
45
|
+
operation :size_gteq, operator: OPS[:size_gteq] do |value|
|
46
|
+
scope.where(value_size_gteq(value))
|
47
|
+
end
|
48
|
+
operation :size_lt, operator: OPS[:size_lt] do |value|
|
49
|
+
scope.where(value_size_lt(value))
|
50
|
+
end
|
51
|
+
operation :size_lteq, operator: OPS[:size_lteq] do |value|
|
52
|
+
scope.where(value_size_lteq(value))
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def cast(value)
|
58
|
+
caster = Casters::IntegerCaster.new
|
59
|
+
caster.serialize(caster.deserialize(value))
|
60
|
+
end
|
61
|
+
|
62
|
+
def jsonpath(operator) = "$[*] ? (@ #{operator} $value)"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveFields
|
4
|
+
module Finders
|
5
|
+
class IntegerFinder < SingularFinder
|
6
|
+
operation :eq, operator: OPS[:eq] do |value|
|
7
|
+
scope.where(eq(casted_value_field("bigint"), cast(value)))
|
8
|
+
end
|
9
|
+
operation :not_eq, operator: OPS[:not_eq] do |value|
|
10
|
+
scope.where(not_eq(casted_value_field("bigint"), cast(value)))
|
11
|
+
end
|
12
|
+
operation :gt, operator: OPS[:gt] do |value|
|
13
|
+
scope.where(gt(casted_value_field("bigint"), cast(value)))
|
14
|
+
end
|
15
|
+
operation :gteq, operator: OPS[:gteq] do |value|
|
16
|
+
scope.where(gteq(casted_value_field("bigint"), cast(value)))
|
17
|
+
end
|
18
|
+
operation :lt, operator: OPS[:lt] do |value|
|
19
|
+
scope.where(lt(casted_value_field("bigint"), cast(value)))
|
20
|
+
end
|
21
|
+
operation :lteq, operator: OPS[:lteq] do |value|
|
22
|
+
scope.where(lteq(casted_value_field("bigint"), cast(value)))
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def cast(value)
|
28
|
+
Casters::IntegerCaster.new.deserialize(value)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveFields
|
4
|
+
module Finders
|
5
|
+
class SingularFinder < BaseFinder
|
6
|
+
private
|
7
|
+
|
8
|
+
# Arel node for `active_fields.value_meta->>const`
|
9
|
+
def value_field_text
|
10
|
+
Arel::Nodes::InfixOperation.new(
|
11
|
+
"->>",
|
12
|
+
Arel::Table.new(cte_name)[:value_meta],
|
13
|
+
Arel::Nodes.build_quoted("const"),
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Arel node with stored value casted to provided type
|
18
|
+
# E.g. `CAST active_fields.value_meta->>const AS bigint`
|
19
|
+
def casted_value_field(to)
|
20
|
+
Arel::Nodes::NamedFunction.new("CAST", [value_field_text.as(to)])
|
21
|
+
end
|
22
|
+
|
23
|
+
# Equal operation, that respects boolean and NULL values
|
24
|
+
def eq(target, value)
|
25
|
+
if value.is_a?(TrueClass) || value.is_a?(FalseClass) || value.is_a?(NilClass)
|
26
|
+
Arel::Nodes::InfixOperation.new("IS", target, Arel::Nodes.build_quoted(value))
|
27
|
+
else
|
28
|
+
target.eq(value)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Not equal operation, that respects boolean and NULL values
|
33
|
+
def not_eq(target, value)
|
34
|
+
if value.is_a?(TrueClass) || value.is_a?(FalseClass) || value.is_a?(NilClass)
|
35
|
+
Arel::Nodes::InfixOperation.new("IS NOT", target, Arel::Nodes.build_quoted(value))
|
36
|
+
else
|
37
|
+
# Comparison with NULL always returns NULL.
|
38
|
+
# NOT NULL is always NULL as well.
|
39
|
+
# We expect them not to be equal to any provided value except TRUE, FALSE and NULL.
|
40
|
+
# So we should search for NULL values too.
|
41
|
+
target.not_eq(value).or(target.eq(nil))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Greater than operation
|
46
|
+
def gt(target, value)
|
47
|
+
target.gt(value)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Greater than or equal to operation
|
51
|
+
def gteq(target, value)
|
52
|
+
target.gteq(value)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Less than operation
|
56
|
+
def lt(target, value)
|
57
|
+
target.lt(value)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Less than or equal to operation
|
61
|
+
def lteq(target, value)
|
62
|
+
target.lteq(value)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveFields
|
4
|
+
module Finders
|
5
|
+
class TextArrayFinder < ArrayFinder
|
6
|
+
operation :include, operator: OPS[:include] do |value|
|
7
|
+
scope.where(value_match_any("==", cast(value)))
|
8
|
+
end
|
9
|
+
operation :not_include, operator: OPS[:not_include] do |value|
|
10
|
+
scope.where.not(value_match_any("==", cast(value)))
|
11
|
+
end
|
12
|
+
operation :any_start_with, operator: OPS[:any_start_with] do |value|
|
13
|
+
scope.where(value_match_any("starts with", cast(value)))
|
14
|
+
end
|
15
|
+
operation :all_start_with, operator: OPS[:all_start_with] do |value|
|
16
|
+
scope.where(value_match_all("starts with", cast(value)))
|
17
|
+
end
|
18
|
+
operation :size_eq, operator: OPS[:size_eq] do |value|
|
19
|
+
scope.where(value_size_eq(value))
|
20
|
+
end
|
21
|
+
operation :size_not_eq, operator: OPS[:size_not_eq] do |value|
|
22
|
+
scope.where(value_size_not_eq(value))
|
23
|
+
end
|
24
|
+
operation :size_gt, operator: OPS[:size_gt] do |value|
|
25
|
+
scope.where(value_size_gt(value))
|
26
|
+
end
|
27
|
+
operation :size_gteq, operator: OPS[:size_gteq] do |value|
|
28
|
+
scope.where(value_size_gteq(value))
|
29
|
+
end
|
30
|
+
operation :size_lt, operator: OPS[:size_lt] do |value|
|
31
|
+
scope.where(value_size_lt(value))
|
32
|
+
end
|
33
|
+
operation :size_lteq, operator: OPS[:size_lteq] do |value|
|
34
|
+
scope.where(value_size_lteq(value))
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def cast(value)
|
40
|
+
caster = Casters::TextCaster.new
|
41
|
+
caster.serialize(caster.deserialize(value))
|
42
|
+
end
|
43
|
+
|
44
|
+
def jsonpath(operator) = "$[*] ? (@ #{operator} $value)"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveFields
|
4
|
+
module Finders
|
5
|
+
class TextFinder < SingularFinder
|
6
|
+
operation :eq, operator: OPS[:eq] do |value|
|
7
|
+
scope.where(eq(casted_value_field("text"), cast(value)))
|
8
|
+
end
|
9
|
+
operation :not_eq, operator: OPS[:not_eq] do |value|
|
10
|
+
scope.where(not_eq(casted_value_field("text"), cast(value)))
|
11
|
+
end
|
12
|
+
operation :start_with, operator: OPS[:start_with] do |value|
|
13
|
+
scope.where(like(casted_value_field("text"), "#{escape_pattern(cast(value))}%"))
|
14
|
+
end
|
15
|
+
operation :end_with, operator: OPS[:end_with] do |value|
|
16
|
+
scope.where(like(casted_value_field("text"), "%#{escape_pattern(cast(value))}"))
|
17
|
+
end
|
18
|
+
operation :contain, operator: OPS[:contain] do |value|
|
19
|
+
scope.where(like(casted_value_field("text"), "%#{escape_pattern(cast(value))}%"))
|
20
|
+
end
|
21
|
+
operation :not_start_with, operator: OPS[:not_start_with] do |value|
|
22
|
+
scope.where(not_like(casted_value_field("text"), "#{escape_pattern(cast(value))}%"))
|
23
|
+
end
|
24
|
+
operation :not_end_with, operator: OPS[:not_end_with] do |value|
|
25
|
+
scope.where(not_like(casted_value_field("text"), "%#{escape_pattern(cast(value))}"))
|
26
|
+
end
|
27
|
+
operation :not_contain, operator: OPS[:not_contain] do |value|
|
28
|
+
scope.where(not_like(casted_value_field("text"), "%#{escape_pattern(cast(value))}%"))
|
29
|
+
end
|
30
|
+
operation :istart_with, operator: OPS[:istart_with] do |value|
|
31
|
+
scope.where(ilike(casted_value_field("text"), "#{escape_pattern(cast(value))}%"))
|
32
|
+
end
|
33
|
+
operation :iend_with, operator: OPS[:iend_with] do |value|
|
34
|
+
scope.where(ilike(casted_value_field("text"), "%#{escape_pattern(cast(value))}"))
|
35
|
+
end
|
36
|
+
operation :icontain, operator: OPS[:icontain] do |value|
|
37
|
+
scope.where(ilike(casted_value_field("text"), "%#{escape_pattern(cast(value))}%"))
|
38
|
+
end
|
39
|
+
operation :not_istart_with, operator: OPS[:not_istart_with] do |value|
|
40
|
+
scope.where(not_ilike(casted_value_field("text"), "#{escape_pattern(cast(value))}%"))
|
41
|
+
end
|
42
|
+
operation :not_iend_with, operator: OPS[:not_iend_with] do |value|
|
43
|
+
scope.where(not_ilike(casted_value_field("text"), "%#{escape_pattern(cast(value))}"))
|
44
|
+
end
|
45
|
+
operation :not_icontain, operator: OPS[:not_icontain] do |value|
|
46
|
+
scope.where(not_ilike(casted_value_field("text"), "%#{escape_pattern(cast(value))}%"))
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def cast(value)
|
52
|
+
Casters::TextCaster.new.deserialize(value)
|
53
|
+
end
|
54
|
+
|
55
|
+
def like(target, value)
|
56
|
+
target.matches(value, nil, true)
|
57
|
+
end
|
58
|
+
|
59
|
+
def ilike(target, value)
|
60
|
+
target.matches(value, nil, false)
|
61
|
+
end
|
62
|
+
|
63
|
+
def not_like(target, value)
|
64
|
+
# We expect NULLs to never match the pattern
|
65
|
+
target.does_not_match(value, nil, true).or(target.eq(nil))
|
66
|
+
end
|
67
|
+
|
68
|
+
def not_ilike(target, value)
|
69
|
+
# We expect NULLs to never match the pattern
|
70
|
+
target.does_not_match(value, nil, false).or(target.eq(nil))
|
71
|
+
end
|
72
|
+
|
73
|
+
# Escape special chars (\, %, _) in LIKE/ILIKE pattern
|
74
|
+
def escape_pattern(value)
|
75
|
+
return unless value.is_a?(String)
|
76
|
+
|
77
|
+
value.gsub("\\", "\\\\\\").gsub("%", "\\%").gsub("_", "\\_")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|