dbee-active_record 1.1.0 → 1.2.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 +4 -4
- data/CHANGELOG.md +5 -0
- data/dbee-active_record.gemspec +1 -1
- data/lib/dbee/providers/active_record_provider/expression_builder/constraint_maker.rb +2 -0
- data/lib/dbee/providers/active_record_provider/expression_builder/order_maker.rb +2 -0
- data/lib/dbee/providers/active_record_provider/expression_builder/select_maker.rb +2 -0
- data/lib/dbee/providers/active_record_provider/expression_builder/where_maker.rb +2 -0
- data/lib/dbee/providers/active_record_provider/expression_builder.rb +46 -38
- data/lib/dbee/providers/active_record_provider/safe_alias_maker.rb +4 -2
- data/lib/dbee/providers/active_record_provider/version.rb +1 -1
- data/spec/db_helper.rb +7 -0
- data/spec/fixtures/active_record_snapshots/partitioner_example_1_query.yaml +27 -0
- data/spec/fixtures/active_record_snapshots/partitioner_example_2_query.yaml +37 -0
- data/spec/fixtures/models.yaml +23 -0
- metadata +8 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a19e2929826b2291f8309610e4740340a887deead5ad1a19a9a54b49d5e1fb12
|
4
|
+
data.tar.gz: aa96b0004e4a7d7c11c161088d6edaafe9d21099df94d20beed8df0dc0676b84
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 87eaf4667b57c442f8f08923c96f2ba9428acff018b6e4f5f44becfe7e4fca41031f93a19f35935a46fc2277bbc0484f48807bf483a06c5fcd06d7616009f165
|
7
|
+
data.tar.gz: 67838d5d7d683ce91bfbebbed17dce20d50cd640af580c0f816a8e5989bd2cc46fa4eff356226bc84af66a689200c9c63790693c465727fde3abea3f919ab3ed
|
data/CHANGELOG.md
CHANGED
data/dbee-active_record.gemspec
CHANGED
@@ -34,7 +34,7 @@ Gem::Specification.new do |s|
|
|
34
34
|
end
|
35
35
|
|
36
36
|
s.add_dependency('activerecord', activerecord_version)
|
37
|
-
s.add_dependency('dbee', '~>1', '>=1.
|
37
|
+
s.add_dependency('dbee', '~>1', '>=1.2.0')
|
38
38
|
|
39
39
|
s.add_development_dependency('guard-rspec', '~>4.7')
|
40
40
|
s.add_development_dependency('mysql2', '~>0.5')
|
@@ -13,6 +13,8 @@ module Dbee
|
|
13
13
|
class ExpressionBuilder
|
14
14
|
# Can derive constraints for Arel table JOIN statements.
|
15
15
|
class ConstraintMaker
|
16
|
+
include Singleton
|
17
|
+
|
16
18
|
CONCAT_METHOD = lambda do |on, arel_column, value|
|
17
19
|
on ? on.and(arel_column.eq(value)) : arel_column.eq(value)
|
18
20
|
end
|
@@ -13,6 +13,8 @@ module Dbee
|
|
13
13
|
class ExpressionBuilder
|
14
14
|
# Derives Arel#where predicates.
|
15
15
|
class WhereMaker
|
16
|
+
include Singleton
|
17
|
+
|
16
18
|
FILTER_EVALUATORS = {
|
17
19
|
Query::Filters::Contains => ->(column, val) { column.matches("%#{val}%") },
|
18
20
|
Query::Filters::Equals => ->(column, val) { column.eq(val) },
|
@@ -28,10 +28,15 @@ module Dbee
|
|
28
28
|
@table_alias_maker = table_alias_maker
|
29
29
|
@column_alias_maker = column_alias_maker
|
30
30
|
|
31
|
-
|
32
|
-
|
31
|
+
clear
|
32
|
+
end
|
33
|
+
|
34
|
+
def clear
|
35
|
+
@base_table = make_table(model.table, model.name)
|
33
36
|
|
34
|
-
|
37
|
+
build(base_table)
|
38
|
+
|
39
|
+
add_partitioners(base_table, model.partitioners)
|
35
40
|
end
|
36
41
|
|
37
42
|
def add(query)
|
@@ -60,31 +65,14 @@ module Dbee
|
|
60
65
|
@key_paths_to_arel_columns ||= {}
|
61
66
|
end
|
62
67
|
|
63
|
-
def where_maker
|
64
|
-
@where_maker ||= WhereMaker.new
|
65
|
-
end
|
66
|
-
|
67
|
-
def order_maker
|
68
|
-
@order_maker ||= OrderMaker.new
|
69
|
-
end
|
70
|
-
|
71
|
-
def select_maker
|
72
|
-
@select_maker ||= SelectMaker.new
|
73
|
-
end
|
74
|
-
|
75
|
-
def constraint_maker
|
76
|
-
@constraint_maker ||= ConstraintMaker.new
|
77
|
-
end
|
78
|
-
|
79
68
|
def add_filter(filter)
|
80
69
|
add_key_path(filter.key_path)
|
81
70
|
|
82
71
|
key_path = filter.key_path
|
83
72
|
arel_column = key_paths_to_arel_columns[key_path]
|
73
|
+
predicate = WhereMaker.instance.make(filter, arel_column)
|
84
74
|
|
85
|
-
|
86
|
-
|
87
|
-
@statement = statement.where(predicate)
|
75
|
+
build(statement.where(predicate))
|
88
76
|
|
89
77
|
self
|
90
78
|
end
|
@@ -92,12 +80,11 @@ module Dbee
|
|
92
80
|
def add_sorter(sorter)
|
93
81
|
add_key_path(sorter.key_path)
|
94
82
|
|
95
|
-
key_path
|
83
|
+
key_path = sorter.key_path
|
96
84
|
arel_column = key_paths_to_arel_columns[key_path]
|
85
|
+
predicate = OrderMaker.instance.make(sorter, arel_column)
|
97
86
|
|
98
|
-
|
99
|
-
|
100
|
-
@statement = statement.order(predicate)
|
87
|
+
build(statement.order(predicate))
|
101
88
|
|
102
89
|
self
|
103
90
|
end
|
@@ -105,34 +92,45 @@ module Dbee
|
|
105
92
|
def add_field(field)
|
106
93
|
add_key_path(field.key_path)
|
107
94
|
|
108
|
-
key_path
|
95
|
+
key_path = field.key_path
|
109
96
|
arel_column = key_paths_to_arel_columns[key_path]
|
97
|
+
predicate = SelectMaker.instance.make(field, arel_column, column_alias_maker)
|
110
98
|
|
111
|
-
|
112
|
-
|
113
|
-
@statement = statement.project(predicate)
|
99
|
+
build(statement.project(predicate))
|
114
100
|
|
115
101
|
self
|
116
102
|
end
|
117
103
|
|
118
104
|
def add_limit(limit)
|
119
|
-
|
105
|
+
limit = limit ? limit.to_i : nil
|
106
|
+
|
107
|
+
build(statement.take(limit))
|
120
108
|
|
121
|
-
|
109
|
+
self
|
110
|
+
end
|
111
|
+
|
112
|
+
def add_partitioners(table, partitioners)
|
113
|
+
partitioners.each do |partitioner|
|
114
|
+
arel_column = table[partitioner.name]
|
115
|
+
predicate = arel_column.eq(partitioner.value)
|
116
|
+
|
117
|
+
build(statement.where(predicate))
|
118
|
+
end
|
122
119
|
|
123
120
|
self
|
124
121
|
end
|
125
122
|
|
126
123
|
def table(name, model, previous_table)
|
127
|
-
table =
|
128
|
-
table.table_alias = table_alias_maker.make(name)
|
124
|
+
table = make_table(model.table, name)
|
129
125
|
|
130
|
-
on =
|
126
|
+
on = ConstraintMaker.instance.make(model.constraints, table, previous_table)
|
131
127
|
|
132
128
|
raise MissingConstraintError, "for: #{name}" unless on
|
133
129
|
|
134
|
-
|
135
|
-
|
130
|
+
build(statement.join(table, ::Arel::Nodes::OuterJoin))
|
131
|
+
build(statement.on(on))
|
132
|
+
|
133
|
+
add_partitioners(table, model.partitioners)
|
136
134
|
|
137
135
|
tables[name] = table
|
138
136
|
end
|
@@ -146,7 +144,7 @@ module Dbee
|
|
146
144
|
def add_key_path(key_path)
|
147
145
|
return if key_paths_to_arel_columns.key?(key_path)
|
148
146
|
|
149
|
-
ancestors = model.ancestors(key_path.ancestor_names)
|
147
|
+
ancestors = model.ancestors!(key_path.ancestor_names)
|
150
148
|
|
151
149
|
table = traverse_ancestors(ancestors)
|
152
150
|
|
@@ -155,6 +153,16 @@ module Dbee
|
|
155
153
|
|
156
154
|
self
|
157
155
|
end
|
156
|
+
|
157
|
+
def build(new_expression)
|
158
|
+
@statement = new_expression
|
159
|
+
end
|
160
|
+
|
161
|
+
def make_table(table_name, alias_name)
|
162
|
+
Arel::Table.new(table_name).tap do |table|
|
163
|
+
table.table_alias = table_alias_maker.make(alias_name)
|
164
|
+
end
|
165
|
+
end
|
158
166
|
end
|
159
167
|
end
|
160
168
|
end
|
@@ -12,8 +12,10 @@ module Dbee
|
|
12
12
|
class ActiveRecordProvider
|
13
13
|
# This class can be used when readable alias names are expected.
|
14
14
|
class SafeAliasMaker
|
15
|
-
def make(
|
16
|
-
|
15
|
+
def make(*parts)
|
16
|
+
parts.flatten
|
17
|
+
.join('_')
|
18
|
+
.tr('.', '_')
|
17
19
|
end
|
18
20
|
end
|
19
21
|
end
|
data/spec/db_helper.rb
CHANGED
@@ -53,10 +53,17 @@ def load_schema
|
|
53
53
|
t.timestamps
|
54
54
|
end
|
55
55
|
|
56
|
+
create_table :owners do |t|
|
57
|
+
t.column :name, :string
|
58
|
+
t.timestamps
|
59
|
+
end
|
60
|
+
|
56
61
|
create_table :animals do |t|
|
62
|
+
t.column :owner_id, :integer
|
57
63
|
t.column :toy_id, :integer
|
58
64
|
t.column :type, :string
|
59
65
|
t.column :name, :string
|
66
|
+
t.column :deleted, :boolean
|
60
67
|
t.timestamps
|
61
68
|
end
|
62
69
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
model_name: Partitioner Example 1
|
2
|
+
query:
|
3
|
+
fields:
|
4
|
+
- key_path: id
|
5
|
+
sqlite_readable: |+
|
6
|
+
SELECT "dogs"."id" AS 'id'
|
7
|
+
FROM "animals" "dogs"
|
8
|
+
WHERE "dogs"."type" = 'Dog' AND
|
9
|
+
"dogs"."deleted" = 'f'
|
10
|
+
sqlite_not_readable: |+
|
11
|
+
SELECT
|
12
|
+
"t0"."id" AS 'c0'
|
13
|
+
FROM "animals" "t0"
|
14
|
+
WHERE "t0"."type" = 'Dog' AND
|
15
|
+
"t0"."deleted" = 'f'
|
16
|
+
mysql_readable: |+
|
17
|
+
SELECT
|
18
|
+
`dogs`.`id` AS 'id'
|
19
|
+
FROM `animals` `dogs`
|
20
|
+
WHERE `dogs`.`type` = 'Dog' AND
|
21
|
+
`dogs`.`deleted` = FALSE
|
22
|
+
mysql_not_readable: |+
|
23
|
+
SELECT
|
24
|
+
`t0`.`id` AS 'c0'
|
25
|
+
FROM `animals` `t0`
|
26
|
+
WHERE `t0`.`type` = 'Dog' AND
|
27
|
+
`t0`.`deleted` = FALSE
|
@@ -0,0 +1,37 @@
|
|
1
|
+
model_name: Partitioner Example 2
|
2
|
+
query:
|
3
|
+
fields:
|
4
|
+
- key_path: id
|
5
|
+
- key_path: dogs.id
|
6
|
+
sqlite_readable: |+
|
7
|
+
SELECT
|
8
|
+
"owners"."id" AS 'id',
|
9
|
+
"dogs"."id" AS 'dogs_id'
|
10
|
+
FROM "owners" "owners"
|
11
|
+
LEFT OUTER JOIN "animals" "dogs" ON "dogs"."owner_id" = "owners"."id"
|
12
|
+
WHERE "dogs"."type" = 'Dog' AND
|
13
|
+
"dogs"."deleted" = 'f'
|
14
|
+
sqlite_not_readable: |+
|
15
|
+
SELECT
|
16
|
+
"t0"."id" AS 'c0',
|
17
|
+
"t1"."id" AS 'c1'
|
18
|
+
FROM "owners" "t0"
|
19
|
+
LEFT OUTER JOIN "animals" "t1" ON "t1"."owner_id" = "t0"."id"
|
20
|
+
WHERE "t1"."type" = 'Dog' AND
|
21
|
+
"t1"."deleted" = 'f'
|
22
|
+
mysql_readable: |+
|
23
|
+
SELECT
|
24
|
+
`owners`.`id` AS 'id',
|
25
|
+
`dogs`.`id` AS 'dogs_id'
|
26
|
+
FROM `owners` `owners`
|
27
|
+
LEFT OUTER JOIN `animals` `dogs` ON `dogs`.`owner_id` = `owners`.`id`
|
28
|
+
WHERE `dogs`.`type` = 'Dog' AND
|
29
|
+
`dogs`.`deleted` = FALSE
|
30
|
+
mysql_not_readable: |+
|
31
|
+
SELECT
|
32
|
+
`t0`.`id` AS 'c0',
|
33
|
+
`t1`.`id` AS 'c1'
|
34
|
+
FROM `owners` `t0`
|
35
|
+
LEFT OUTER JOIN `animals` `t1` ON `t1`.`owner_id` = `t0`.`id`
|
36
|
+
WHERE `t1`.`type` = 'Dog' AND
|
37
|
+
`t1`.`deleted` = FALSE
|
data/spec/fixtures/models.yaml
CHANGED
@@ -80,3 +80,26 @@ Reverse Polymorphic Example:
|
|
80
80
|
- type: static
|
81
81
|
parent: type
|
82
82
|
value: Cat
|
83
|
+
|
84
|
+
Partitioner Example 1:
|
85
|
+
name: dogs
|
86
|
+
table: animals
|
87
|
+
partitioners:
|
88
|
+
- name: type
|
89
|
+
value: Dog
|
90
|
+
- name: deleted
|
91
|
+
value: false
|
92
|
+
|
93
|
+
Partitioner Example 2:
|
94
|
+
name: owners
|
95
|
+
models:
|
96
|
+
- name: dogs
|
97
|
+
table: animals
|
98
|
+
constraints:
|
99
|
+
- name: owner_id
|
100
|
+
parent: id
|
101
|
+
partitioners:
|
102
|
+
- name: type
|
103
|
+
value: Dog
|
104
|
+
- name: deleted
|
105
|
+
value: false
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dbee-active_record
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthew Ruggio
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-08-
|
11
|
+
date: 2019-08-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -39,7 +39,7 @@ dependencies:
|
|
39
39
|
version: '1'
|
40
40
|
- - ">="
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version: 1.
|
42
|
+
version: 1.2.0
|
43
43
|
type: :runtime
|
44
44
|
prerelease: false
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -49,7 +49,7 @@ dependencies:
|
|
49
49
|
version: '1'
|
50
50
|
- - ">="
|
51
51
|
- !ruby/object:Gem::Version
|
52
|
-
version: 1.
|
52
|
+
version: 1.2.0
|
53
53
|
- !ruby/object:Gem::Dependency
|
54
54
|
name: guard-rspec
|
55
55
|
requirement: !ruby/object:Gem::Requirement
|
@@ -219,6 +219,8 @@ files:
|
|
219
219
|
- spec/fixtures/active_record_snapshots/one_table_query_with_filters.yaml
|
220
220
|
- spec/fixtures/active_record_snapshots/one_table_query_with_limit.yaml
|
221
221
|
- spec/fixtures/active_record_snapshots/one_table_query_with_multiple_sorts.yaml
|
222
|
+
- spec/fixtures/active_record_snapshots/partitioner_example_1_query.yaml
|
223
|
+
- spec/fixtures/active_record_snapshots/partitioner_example_2_query.yaml
|
222
224
|
- spec/fixtures/active_record_snapshots/reverse_polymorphic_query.yaml
|
223
225
|
- spec/fixtures/active_record_snapshots/two_table_query.yaml
|
224
226
|
- spec/fixtures/models.yaml
|
@@ -258,6 +260,8 @@ test_files:
|
|
258
260
|
- spec/fixtures/active_record_snapshots/one_table_query_with_filters.yaml
|
259
261
|
- spec/fixtures/active_record_snapshots/one_table_query_with_limit.yaml
|
260
262
|
- spec/fixtures/active_record_snapshots/one_table_query_with_multiple_sorts.yaml
|
263
|
+
- spec/fixtures/active_record_snapshots/partitioner_example_1_query.yaml
|
264
|
+
- spec/fixtures/active_record_snapshots/partitioner_example_2_query.yaml
|
261
265
|
- spec/fixtures/active_record_snapshots/reverse_polymorphic_query.yaml
|
262
266
|
- spec/fixtures/active_record_snapshots/two_table_query.yaml
|
263
267
|
- spec/fixtures/models.yaml
|