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

Sign up to get free protection for your applications and to get access to all the features.
@@ -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