praxis 2.0.pre.2 → 2.0.pre.3

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.
@@ -0,0 +1,106 @@
1
+ require 'sequel'
2
+
3
+ require 'praxis/mapper/sequel_compat'
4
+
5
+
6
+ # Creates a new in-memory DB, and the necessary tables (and mini-seeds) for the sequel models in this file
7
+ def create_and_seed_tables
8
+ sequeldb = Sequel.sqlite
9
+ # sequeldb.loggers = [Logger.new($stdout)] # Uncomment to see sequel logs
10
+
11
+ sequeldb.create_table! :sequel_simple_models do
12
+ primary_key :id
13
+ String :simple_name
14
+ Integer :parent_id
15
+ String :parent_uuid
16
+ Integer :other_model_id
17
+ String :added_column
18
+ end
19
+ sequeldb.create_table! :sequel_other_models do
20
+ primary_key :id
21
+ end
22
+ sequeldb.create_table! :sequel_parent_models do
23
+ primary_key :id
24
+ String :uuid
25
+ end
26
+ sequeldb.create_table! :sequel_tag_models do
27
+ primary_key :id
28
+ String :tag_name
29
+ end
30
+ sequeldb.create_table! :sequel_simple_models_sequel_tag_models do
31
+ Integer :sequel_simple_model_id
32
+ Integer :tag_id
33
+ end
34
+
35
+ sequeldb[:sequel_parent_models] << { id: 1 , uuid: 'deadbeef1'}
36
+ sequeldb[:sequel_parent_models] << { id: 2 , uuid: 'deadbeef2'}
37
+
38
+ sequeldb[:sequel_other_models] << { id: 11 }
39
+ sequeldb[:sequel_other_models] << { id: 22 }
40
+
41
+ sequeldb[:sequel_tag_models] << { id: 1 , tag_name: 'blue' }
42
+ sequeldb[:sequel_tag_models] << { id: 2 , tag_name: 'red' }
43
+
44
+ # Simple model 1 is tagged as blue and red
45
+ sequeldb[:sequel_simple_models_sequel_tag_models] << { sequel_simple_model_id: 1, tag_id: 1 }
46
+ sequeldb[:sequel_simple_models_sequel_tag_models] << { sequel_simple_model_id: 1, tag_id: 2 }
47
+ # Simple model 2 is tagged as red
48
+ sequeldb[:sequel_simple_models_sequel_tag_models] << { sequel_simple_model_id: 2, tag_id: 2 }
49
+
50
+ # It's weird to have a parent id and parent uuid (which points to different actual parents)
51
+ # But it allows us to check pointing to both PKs and not PK columns
52
+ sequeldb[:sequel_simple_models] << { id: 1 , simple_name: 'Simple1', parent_id: 1, other_model_id: 11, parent_uuid: 'deadbeef1'}
53
+ sequeldb[:sequel_simple_models] << { id: 2 , simple_name: 'Simple2', parent_id: 2, other_model_id: 22, parent_uuid: 'deadbeef1'}
54
+ end
55
+
56
+ create_and_seed_tables
57
+
58
+ class SequelSimpleModel < Sequel::Model
59
+ include Praxis::Mapper::SequelCompat
60
+
61
+ many_to_one :parent, class: 'SequelParentModel'
62
+ many_to_one :other_model, class: 'SequelOtherModel'
63
+ many_to_many :tags, class: 'SequelTagModel'
64
+ end
65
+
66
+ class SequelOtherModel < Sequel::Model
67
+ include Praxis::Mapper::SequelCompat
68
+ end
69
+
70
+ class SequelParentModel < Sequel::Model
71
+ include Praxis::Mapper::SequelCompat
72
+ one_to_many :children, class: 'SequelSimpleModel', primary_key: :uuid, key: :parent_uuid
73
+ end
74
+
75
+ class SequelTagModel < Sequel::Model
76
+ include Praxis::Mapper::SequelCompat
77
+ end
78
+
79
+
80
+ # A set of resource classes for use in specs
81
+ class SequelBaseResource < Praxis::Mapper::Resource
82
+ end
83
+
84
+ class SequelOtherResource < SequelBaseResource
85
+ model SequelOtherModel
86
+
87
+ property :display_name, dependencies: [:name]
88
+ end
89
+
90
+ class SequelParentResource < SequelBaseResource
91
+ model SequelParentModel
92
+ end
93
+
94
+ class SequelTagResource < SequelBaseResource
95
+ model SequelTagModel
96
+ end
97
+
98
+ class SequelSimpleResource < SequelBaseResource
99
+ model SequelSimpleModel
100
+
101
+ # Forces to add an extra column (added_column)...and yet another (parent_id) that will serve
102
+ # to check that if that's already automatically added due to an association, it won't interfere or duplicate
103
+ property :parent, dependencies: [:parent, :added_column, :parent_id]
104
+
105
+ property :name, dependencies: [:simple_name]
106
+ end
@@ -1,301 +1,293 @@
1
- # require 'spec_helper'
1
+ require 'spec_helper'
2
2
 
3
- # describe Praxis::Mapper::SelectorGenerator do
4
- # let(:properties) { {} }
5
- # let(:resource) { BlogResource }
6
- # subject(:generator) {Praxis::Mapper::SelectorGenerator.new }
7
3
 
8
- # before do
9
- # generator.add(resource,properties)
10
- # end
4
+ describe Praxis::Mapper::SelectorGenerator do
5
+ let(:resource) { SimpleResource }
6
+ subject(:generator) {described_class.new }
11
7
 
12
- # let(:expected_selectors) { {} }
8
+ context '#add' do
9
+ let(:resource) { SimpleResource }
10
+ shared_examples 'a proper selector' do
11
+ it { expect(generator.add(resource, fields).dump).to be_deep_equal selectors }
12
+ end
13
+
14
+ context 'basic combos' do
15
+ context 'direct column fields' do
16
+ let(:fields) { {id: true, foobar: true} }
17
+ let(:selectors) do
18
+ {
19
+ model: SimpleModel,
20
+ columns: [:id, :foobar]
21
+ }
22
+ end
23
+ it_behaves_like 'a proper selector'
24
+ end
13
25
 
14
- # context 'for a simple field' do
15
- # let(:properties) { {id: true} }
16
- # let(:expected_selectors) do
17
- # {
18
- # BlogModel => {
19
- # select: Set.new([:id]),
20
- # track: Set.new()
21
- # }
22
- # }
23
- # end
26
+ context 'aliased column fields' do
27
+ let(:fields) { {id: true, name: true} }
28
+ let(:selectors) do
29
+ {
30
+ model: SimpleModel,
31
+ columns: [:id, :simple_name]
32
+ }
33
+ end
34
+ it_behaves_like 'a proper selector'
35
+ end
24
36
 
25
- # it 'generates the correct set of selectors' do
26
- # generator.selectors.should eq expected_selectors
27
- # end
28
- # end
37
+ context 'pure associations without recursion' do
38
+ let(:fields) { {other_model: true} }
39
+ let(:selectors) do
40
+ {
41
+ model: SimpleModel,
42
+ columns: [:other_model_id], # FK of the other_model association
43
+ tracks: {
44
+ other_model: {
45
+ columns: [:id], # joining key for the association
46
+ model: OtherModel
47
+ }
48
+ }
49
+ }
50
+ end
51
+ it_behaves_like 'a proper selector'
52
+ end
29
53
 
30
- # context 'for a simple property' do
31
- # let(:properties) { {display_name: true} }
32
- # let(:expected_selectors) do
33
- # {
34
- # BlogModel => {
35
- # select: Set.new([:name]),
36
- # track: Set.new()
37
- # }
38
- # }
39
- # end
40
- # it 'generates the correct set of selectors' do
41
- # generator.selectors.should eq expected_selectors
42
- # end
43
- # end
54
+ context 'aliased associations without recursion' do
55
+ let(:fields) { {other_resource: true} }
56
+ let(:selectors) do
57
+ {
58
+ model: SimpleModel,
59
+ columns: [:other_model_id], # FK of the other_model association
60
+ tracks: {
61
+ other_model: {
62
+ columns: [:id], # joining key for the association
63
+ model: OtherModel
64
+ }
65
+ }
66
+ }
67
+ end
68
+ it_behaves_like 'a proper selector'
69
+ end
70
+ context 'aliased associations without recursion (that map to columns and other associations)' do
71
+ let(:fields) { {aliased_method: true} }
72
+ let(:selectors) do
73
+ {
74
+ model: SimpleModel,
75
+ columns: [:column1, :other_model_id], # other_model_id => because of the association
76
+ tracks: {
77
+ other_model: {
78
+ columns: [:id], # joining key for the association
79
+ model: OtherModel
80
+ }
81
+ }
82
+ }
83
+ end
84
+ it_behaves_like 'a proper selector'
85
+ end
44
86
 
45
- # context 'for an association' do
46
- # let(:properties) { {owner: true} }
47
- # let(:expected_selectors) do
48
- # {
49
- # BlogModel => {
50
- # select: Set.new([:owner_id]),
51
- # track: Set.new([:owner])
52
- # }
53
- # }
54
- # end
55
- # it 'generates the correct set of selectors' do
56
- # generator.selectors.should eq expected_selectors
57
- # end
87
+ context 'redefined associations that add some extra columns (would need both the underlying association AND the columns in place)' do
88
+ let(:fields) { {parent: true} }
89
+ let(:selectors) do
90
+ {
91
+ model: SimpleModel,
92
+ columns: [:parent_id, :added_column],
93
+ tracks: {
94
+ parent: {
95
+ columns: [:id],
96
+ model: ParentModel
97
+ }
98
+ }
99
+ }
100
+ end
101
+ it_behaves_like 'a proper selector'
102
+ end
58
103
 
59
- # context 'that is many_to_many' do
60
- # let(:properties) { {commented_posts: true} }
61
- # let(:resource) { UserResource }
62
- # let(:expected_selectors) do
63
- # {
64
- # CommentModel => {
65
- # select: Set.new([:author_id, :post_id]),
66
- # track: Set.new([:post])
67
- # },
68
- # UserModel => {
69
- # select: Set.new([]),
70
- # track: Set.new([:comments])
71
- # }
72
- # }
73
- # end
74
- # it 'generates the correct set of selectors' do
75
- # generator.selectors.should eq expected_selectors
76
- # end
77
- # end
104
+ context 'a simple property that requires all fields' do
105
+ let(:fields) { {everything: true} }
106
+ let(:selectors) do
107
+ {
108
+ model: SimpleModel,
109
+ columns: [:*],
110
+ }
111
+ end
112
+ it_behaves_like 'a proper selector'
113
+ end
78
114
 
79
- # context 'that is many_to_many without a :through option' do
80
- # let(:properties) { {other_commented_posts: { id: true} } }
81
- # let(:resource) { UserResource }
82
- # let(:expected_selectors) do
83
- # {
84
- # PostModel => {
85
- # select: Set.new([:id]),
86
- # track: Set.new([])
87
- # },
88
- # UserModel => {
89
- # select: Set.new([]),
90
- # track: Set.new([:other_commented_posts])
91
- # }
92
- # }
93
- # end
94
- # it 'generates the correct set of selectors' do
95
- # generator.selectors.should eq expected_selectors
96
- # end
97
- # end
115
+ context 'a simple property that requires itself' do
116
+ let(:fields) { {circular_dep: true} }
117
+ let(:selectors) do
118
+ {
119
+ model: SimpleModel,
120
+ columns: [:circular_dep, :column1], #allows to "expand" the dependency into itself + others
121
+ }
122
+ end
123
+ it_behaves_like 'a proper selector'
124
+ end
98
125
 
126
+ context 'a simple property without dependencies' do
127
+ let(:fields) { {no_deps: true} }
128
+ let(:selectors) do
129
+ {
130
+ model: SimpleModel
131
+ }
132
+ end
133
+ it_behaves_like 'a proper selector'
134
+ end
99
135
 
100
- # context 'that uses a composite key' do
101
- # let(:properties) { {composite_model: {id: true, type: true} } }
102
- # let(:resource) { OtherResource }
103
- # let(:expected_selectors) do
104
- # {
105
- # OtherModel => {
106
- # select: Set.new([:composite_id,:composite_type]),
107
- # track: Set.new([:composite_model])
108
- # },
109
- # CompositeIdModel => {
110
- # select: Set.new([:id,:type]),
111
- # track: Set.new
112
- # }
113
- # }
114
- # end
115
- # it 'generates the correct set of selectors' do
116
- # generator.selectors.should eq expected_selectors
117
- # end
118
- # end
119
- # end
136
+ end
120
137
 
121
- # context 'for a property that specifies a field from an association' do
122
- # let(:properties) { {owner_email: true} }
123
- # let(:expected_selectors) do
124
- # {
125
- # BlogModel => {
126
- # select: Set.new([:owner_id]),
127
- # track: Set.new([:owner])
128
- # },
129
- # UserModel => {
130
- # select: Set.new([:email]),
131
- # track: Set.new()
132
- # }
133
- # }
134
- # end
138
+ context 'nested tracking' do
139
+ context 'pure associations follow the nested fields' do
140
+ let(:fields) do
141
+ {
142
+ other_model: {
143
+ id: true
144
+ }
145
+ }
146
+ end
147
+ let(:selectors) do
148
+ {
149
+ model: SimpleModel,
150
+ columns: [:other_model_id],
151
+ tracks: {
152
+ other_model: {
153
+ model: OtherModel,
154
+ columns: [:id]
155
+ }
156
+ }
157
+ }
158
+ end
159
+ it_behaves_like 'a proper selector'
160
+ end
135
161
 
136
- # it 'generates the correct set of selectors' do
137
- # generator.selectors.should eq expected_selectors
138
- # end
139
- # end
162
+ context 'Aliased resources disregard any nested fields...' do
163
+ let(:fields) do
164
+ {
165
+ other_resource: {
166
+ id: true
167
+ }
168
+ }
169
+ end
170
+ let(:selectors) do
171
+ {
172
+ model: SimpleModel,
173
+ columns: [:other_model_id],
174
+ tracks: {
175
+ other_model: {
176
+ model: OtherModel,
177
+ columns: [:id]
178
+ }
179
+ }
180
+ }
181
+ end
182
+ it_behaves_like 'a proper selector'
183
+ end
184
+ end
140
185
 
141
- # context 'for a simple property that requires all fields' do
142
- # let(:properties) { {everything: true} }
143
- # let(:expected_selectors) do
144
- # {
145
- # BlogModel => {
146
- # select: true,
147
- # track: Set.new()
148
- # }
149
- # }
150
- # end
151
- # it 'generates the correct set of selectors' do
152
- # generator.selectors.should eq expected_selectors
153
- # end
154
- # end
186
+ context 'string associations' do
187
+ context 'that specify a direct existing colum in the target dependency' do
188
+ let(:fields) { { direct_other_name: true } }
189
+ let(:selectors) do
190
+ {
191
+ model: SimpleModel,
192
+ columns: [:other_model_id],
193
+ tracks: {
194
+ other_model: {
195
+ model: OtherModel,
196
+ columns: [:id, :name]
197
+ }
198
+ }
199
+ }
200
+ end
201
+ it_behaves_like 'a proper selector'
202
+ end
155
203
 
156
- # context 'for property that uses an associated property' do
157
- # let(:properties) { {owner_full_name: true} }
158
- # let(:expected_selectors) do
159
- # {
160
- # BlogModel => {
161
- # select: Set.new([:owner_id]),
162
- # track: Set.new([:owner])
163
- # },
164
- # UserModel => {
165
- # select: Set.new([:first_name, :last_name]),
166
- # track: Set.new()
167
- # }
168
- # }
169
- # end
170
- # it 'generates the correct set of selectors' do
171
- # generator.selectors.should eq expected_selectors
172
- # end
173
- # end
204
+ context 'that specify an aliased property in the target dependency' do
205
+ let(:fields) { { aliased_other_name: true } }
206
+ let(:selectors) do
207
+ {
208
+ model: SimpleModel,
209
+ columns: [:other_model_id],
210
+ tracks: {
211
+ other_model: {
212
+ model: OtherModel,
213
+ columns: [:id, :name]
214
+ }
215
+ }
216
+ }
217
+ end
218
+ it_behaves_like 'a proper selector'
219
+ end
174
220
 
221
+ context 'for a property that requires all fields from an association' do
222
+ let(:fields) { {everything_from_parent: true} }
223
+ let(:selectors) do
224
+ {
225
+ model: SimpleModel,
226
+ columns: [:parent_id],
227
+ tracks: {
228
+ parent: {
229
+ model: ParentModel,
230
+ columns: [:*]
231
+ }
232
+ }
233
+ }
234
+ end
235
+ it_behaves_like 'a proper selector'
236
+ end
237
+ end
175
238
 
176
- # context 'for a property that requires all fields from an association' do
177
- # let(:properties) { {everything_from_owner: true} }
178
- # let(:expected_selectors) do
179
- # {
180
- # BlogModel => {
181
- # select: Set.new([:owner_id]),
182
- # track: Set.new([:owner])
183
- # },
184
- # UserModel => {
185
- # select: true,
186
- # track: Set.new()
187
- # }
188
- # }
189
- # end
190
- # it 'generates the correct set of selectors' do
191
- # generator.selectors.should eq expected_selectors
192
- # end
193
- # end
239
+ context 'required extra select fields due to associations' do
240
+ context 'many_to_one' do
241
+ let(:fields) { {other_model: true} }
242
+ let(:selectors) do
243
+ {
244
+ model: SimpleModel,
245
+ columns: [:other_model_id], # FK of the other_model association
246
+ tracks: {
247
+ other_model: {
248
+ columns: [:id],
249
+ model: OtherModel
250
+ }
251
+ }
252
+ }
253
+ end
254
+ it_behaves_like 'a proper selector'
255
+ end
256
+ context 'one_to_many' do
257
+ let(:resource) { ParentResource }
258
+ let(:fields) { {simple_children: true} }
259
+ let(:selectors) do
260
+ {
261
+ model: ParentModel,
262
+ columns: [:id], # No FKs in the source model for one_to_many
263
+ tracks: {
264
+ simple_children: {
265
+ columns: [:parent_id],
266
+ model: SimpleModel
267
+ }
268
+ }
269
+ }
270
+ end
271
+ it_behaves_like 'a proper selector'
272
+ end
273
+ context 'many_to_many' do
274
+ let(:resource) { OtherResource }
275
+ let(:fields) { {simple_models: true} }
276
+ let(:selectors) do
277
+ {
278
+ model: OtherModel,
279
+ columns: [:id], #join key in the source model for many_to_many (where the middle table points to)
280
+ tracks: {
281
+ simple_models: {
282
+ columns: [:id], #join key in the target model for many_to_many (where the middle table points to)
283
+ model: SimpleModel
284
+ }
285
+ }
286
+ }
287
+ end
288
+ it_behaves_like 'a proper selector'
289
+ end
194
290
 
195
- # context 'using a property that specifies a :through option' do
196
- # let(:properties) { {recent_posts: {author: {full_name: true}}} }
197
- # let(:resource) { UserResource }
198
- # let(:expected_selectors) do
199
- # {
200
- # PostModel => {
201
- # select: Set.new([:author_id, :created_at]),
202
- # track: Set.new([:author])
203
- # },
204
- # UserModel => {
205
- # select: Set.new([:first_name, :last_name]),
206
- # track: Set.new([:posts])
207
- # }
208
- # }
209
- # end
210
- # it 'generates the correct set of selectors' do
211
- # generator.selectors.should eq expected_selectors
212
- # end
213
- # end
214
-
215
- # context 'with a property with a circular definition (ie, includes its own field)' do
216
- # let(:resource) { PostResource }
217
-
218
- # let(:properties) { {id: true, slug: true} }
219
- # let(:expected_selectors) do
220
- # {
221
- # PostModel => {
222
- # select: Set.new([:id, :slug, :title]),
223
- # track: Set.new
224
- # }
225
- # }
226
- # end
227
- # it 'generates the correct set of selectors' do
228
- # generator.selectors.should eq expected_selectors
229
- # end
230
- # end
231
-
232
- # context 'with a property without the :through option' do
233
- # let(:resource) { UserResource }
234
- # let(:properties) { {blogs_summary: {size: true}} }
235
- # let(:expected_selectors) do
236
- # {
237
- # BlogModel => {
238
- # select: Set.new([:owner_id]),
239
- # track: Set.new()
240
- # },
241
- # UserModel => {
242
- # select: Set.new([:id]),
243
- # track: Set.new([:blogs])
244
- # }
245
- # }
246
- # end
247
- # it 'ignores any subsequent fields when generating selectors' do
248
- # generator.selectors.should eq expected_selectors
249
- # end
250
- # end
251
-
252
- # context 'for a property with no dependencies' do
253
- # let(:properties) { {id: true, kind: true} }
254
- # let(:expected_selectors) do
255
- # {
256
- # BlogModel => {
257
- # select: Set.new([:id]),
258
- # track: Set.new()
259
- # }
260
- # }
261
- # end
262
- # it 'generates the correct set of selectors' do
263
- # generator.selectors.should eq expected_selectors
264
- # end
265
- # end
266
-
267
- # context 'with large set of properties' do
268
-
269
- # let(:properties) do
270
- # {
271
- # display_name: true,
272
- # owner: {
273
- # id: true,
274
- # full_name: true,
275
- # blogs_summary: {href: true, size: true},
276
- # main_blog: {id: true},
277
- # },
278
- # administrator: {id: true, full_name: true}
279
- # }
280
- # end
281
-
282
- # let(:expected_selectors) do
283
- # {
284
- # BlogModel=> {
285
- # select: Set.new([:id, :name, :owner_id, :administrator_id]),
286
- # track: Set.new([:owner, :administrator])
287
- # },
288
- # UserModel=> {
289
- # select: Set.new([:id, :first_name, :last_name, :main_blog_id]),
290
- # track: Set.new([:blogs, :main_blog])
291
- # }
292
- # }
293
- # end
294
-
295
- # it 'generates the correct set of selectors' do
296
- # generator.selectors.should eq(expected_selectors)
297
- # end
298
-
299
- # end
300
-
301
- # end
291
+ end
292
+ end
293
+ end