get 0.1.6 → 0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d94cb493af93174c9e0ae92e3496f07d7de70f2f
4
- data.tar.gz: fb442dab1286f24ce10952ac5d744a9704755619
3
+ metadata.gz: b65d91c034544c94bc5f69f130fd281ea846d32d
4
+ data.tar.gz: 3ba99734b8435d50b2fb2372e798b26860dec7db
5
5
  SHA512:
6
- metadata.gz: 706088f656cce4980d28a79ae9cf3a971faf17a12bebc5c52f3003e7e295342c7f719b2ca9c57f07e0465a7df509a201dc8b8a23ba9264722f52c9d1000a422d
7
- data.tar.gz: 20921d8266728bbee9bc6f6695651ca00fb60472e0ade7ee15a841a25446fb742b0714c9a781284f6e771ac054f02c066f5dc1d7017f65312f695ee6b8549187
6
+ metadata.gz: ae40513b32b4063b5bfe7c2d2bcf025e107eeba4aa87013402b298d6601f09815755e1967c0db38c436e92290444820f06034b20a6b6b4b5f6e5541213c136aa
7
+ data.tar.gz: f99002ee16cdd582571be08ea99512dc2eaa6a9e4e9ff661ba9322b5741d75040a27e899eeee37d76201a6c8fd68180e14ea25e08a06d5f15a6e0f117dcf0a26
data/README.md CHANGED
@@ -2,6 +2,92 @@
2
2
 
3
3
  Dynamically generate classes to encapsulate common database queries in Rails.
4
4
 
5
+ ## Usage
6
+
7
+ #### Singular Queries - Return a single record
8
+
9
+ With field being queried in the class name
10
+ ```ruby
11
+ Get::UserById.run(123)
12
+ ```
13
+
14
+ Fail loudly
15
+ ```ruby
16
+ Get::UserById.run!(123)
17
+ ```
18
+
19
+ Slightly more flexible model:
20
+ ```ruby
21
+ Get::UserBy.run(id: 123, employer_id: 88)
22
+ ```
23
+
24
+ #### Plural Queries - Return a collection of records
25
+
26
+ _Note the plurality of 'Users'_
27
+ ```ruby
28
+ Get::UsersByLastName.run('Turner')
29
+ ```
30
+
31
+ With Options
32
+ ```ruby
33
+ Get::UsersByLastName.run('Turner', limit: 10, offset: 20, order: { last_name: :desc })
34
+ ```
35
+
36
+ #### Associations
37
+
38
+ Associations use 'From', and are sugar for the chains we so often write in rails.
39
+
40
+ _You can pass either an entity or an id, the only requirement is that it responds to #id_
41
+
42
+ Parent relationship (user.employer):
43
+ ```ruby
44
+ Get::EmployerFromUser.run(user)
45
+ ```
46
+
47
+ Child relationship (employer.users):
48
+ ```ruby
49
+ Get::UsersFromEmployer.run(employer_id)
50
+ ```
51
+
52
+ Complex relationship (user.employer.sportscars)
53
+ ```ruby
54
+ Get::SportscarsFromUser.run(user, via: :employer)
55
+ ```
56
+
57
+ Eager Loading
58
+ ```ruby
59
+ Get::SportscarsFromUser.run(user, via: :employer, eager_load: true)
60
+ ```
61
+
62
+ Query Associations
63
+ ```ruby
64
+ Get::SportscarsFromUser.run(user, via: :employer, conditions: { make: 'Audi' }, limit: 10, offset: 20)
65
+ ```
66
+
67
+ Keep the plurality of associations in mind. If an Employer has many Users, UsersFromEmployer works,
68
+ but UserFromEmployer will throw `Get::Errors::InvalidAncestry`.
69
+
70
+ ## Options
71
+
72
+ **Base Options**
73
+
74
+ Key | Type | Details
75
+ --- | ---- | -------
76
+ `order` | Hash | { `field` => `:asc`/`:desc` }
77
+ `limit` | Integer | Number of records to return
78
+ `offset` | Integer | Number of records to offset
79
+ `id` | Integer | The id of the root object (associations only)
80
+ `target` | Symbol | The target of the association - ie. employer.users would have a target of :users (associations only)
81
+ `eager_load` | Boolean | Whether to eager_load the association (associations only)
82
+
83
+ **Association Options**
84
+
85
+ Key | Type | Details
86
+ --- | ---- | -------
87
+ `conditions` | Hash | Key value pairs for the query
88
+ `eager_load` | Boolean | Whether to eager_load the association
89
+ `via` | [Symbol] | The associations that need to be traversed in order to reach the desired record(s). These must be in the correct order, ie user.employer.parent.children would be Get::ChildrenFromUser.run(user_id, via: [:employer, :parent]). You can also pass a single symbol instead of an array of length 1.
90
+
5
91
  ## Why is this necessary?
6
92
 
7
93
  #### Problem 1: Encapsulation
@@ -87,56 +173,6 @@ Get identifies four themes in common queries:
87
173
 
88
174
  These themes are not mutually exclusive; **Query** and **Association** can be either **Singular** or **Plural**.
89
175
 
90
- ## Usage
91
-
92
- #### Singular Queries - Return a single record
93
-
94
- With field being queried in the class name
95
- ```ruby
96
- Get::UserById.run(123)
97
- ```
98
-
99
- Fail loudly
100
- ```ruby
101
- Get::UserById.run!(123)
102
- ```
103
-
104
- Slightly more flexible model:
105
- ```ruby
106
- Get::UserBy.run(id: 123, employer_id: 88)
107
- ```
108
-
109
- #### Plural Queries - Return a collection of records
110
-
111
- _Note the plurality of 'Users'_
112
- ```ruby
113
- Get::UsersByLastName.run('Turner')
114
- ```
115
-
116
- #### Associations
117
-
118
- Associations use 'From', and are sugar for the chains we so often write in rails.
119
-
120
- _You can pass either an entity or an id, the only requirement is that it responds to #id_
121
-
122
- Parent relationship (user.employer):
123
- ```ruby
124
- Get::EmployerFromUser.run(user)
125
- ```
126
-
127
- Child relationship (employer.users):
128
- ```ruby
129
- Get::UsersFromEmployer.run(employer_id)
130
- ```
131
-
132
- Complex relationship (user.employer.sportscars)
133
- ```ruby
134
- Get::SportscarsFromUser.run(user, via: :employer)
135
- ```
136
-
137
- Keep the plurality of associations in mind. If an Employer has many Users, UsersFromEmployer works,
138
- but UserFromEmployer will throw `Get::Errors::InvalidAncestry`.
139
-
140
176
  ## Entities
141
177
 
142
178
  Ironically, one of the "features" of Get is its removal of the ability to query associations from the ORM response object.
@@ -234,7 +270,7 @@ Some attributes contain the word 'by', ie. `Customer.invited_by`.
234
270
  Because of the way Get parses classnames, you won't be able to use the attribute-specific format.
235
271
  Use the more general form instead.
236
272
 
237
- ```
273
+ ```ruby
238
274
  Get::CustomerByInvitedBy.run('John') #=> throws Get::Errors::InvalidClassName
239
275
  Get::CustomerBy.run(invited_by: 'John') #=> will work
240
276
  ```
@@ -29,17 +29,18 @@ module Get
29
29
 
30
30
  private
31
31
 
32
- def id
33
- return @model.id if @model.respond_to? :id
34
- @model
35
- end
36
-
37
32
  def query_params
38
- options = @options.except(:via) || {}
39
- { ancestors: ancestor_params }.merge(options)
33
+ { association: ancestor_params }
40
34
  end
41
35
 
42
36
  def ancestor_params
37
+ # Add options to hash only if they exist - empty objects/nil values can wreak havoc
38
+ [:conditions, :limit, :offset, :order, :eager_load].reduce(required_params) do |params, key|
39
+ @options[key] ? params.merge(key => @options[key]) : params
40
+ end
41
+ end
42
+
43
+ def required_params
43
44
  {
44
45
  id: id,
45
46
  via: via,
@@ -47,6 +48,11 @@ module Get
47
48
  }
48
49
  end
49
50
 
51
+ def id
52
+ return @model.id if @model.respond_to? :id
53
+ @model
54
+ end
55
+
50
56
  def via
51
57
  case @options[:via]
52
58
  when Symbol
@@ -22,15 +22,15 @@ module Get
22
22
 
23
23
  @field, @entity, @collection, @store = args[:key], args[:result_entity], args[:collection], args[:store]
24
24
 
25
- def initialize(params)
26
- @params = params
25
+ def initialize(params, options = {})
26
+ @params, @options = params, options
27
27
  super(query_params)
28
28
  end
29
29
 
30
30
  private
31
31
 
32
32
  def query_params
33
- { query_action => conditions }
33
+ { query_action => conditions.merge(@options) }
34
34
  end
35
35
 
36
36
  def query_action
@@ -39,13 +39,8 @@ module Get
39
39
 
40
40
  # find_first
41
41
  def conditions
42
- return @params unless self.class.field
43
- { self.class.field => @params }
44
- end
45
-
46
- def single_params
47
- return {} if self.class.collection
48
- { limit: 1, first: true }
42
+ return { conditions: @params } unless self.class.field
43
+ { conditions: { self.class.field => @params } }
49
44
  end
50
45
  end
51
46
  end
data/lib/get/db.rb CHANGED
@@ -2,10 +2,6 @@ module Get
2
2
  class Db
3
3
  class << self
4
4
  attr_accessor :entity, :query_key, :collection, :store
5
-
6
- def entity_factory
7
- @factory ||= EntityFactory.new(entity, name, collection, query_key)
8
- end
9
5
  end
10
6
 
11
7
  def initialize(actions)
data/spec/get_spec.rb CHANGED
@@ -210,6 +210,41 @@ describe Get do
210
210
  end
211
211
  end
212
212
 
213
+ context 'with options' do
214
+ let(:last_name) { 'Turner' }
215
+ let(:match_count) { 20 }
216
+ let(:miss_count) { 7 }
217
+
218
+ before do
219
+ match_count.times { GetSpec::User.create(last_name: last_name) }
220
+ miss_count.times { GetSpec::User.create }
221
+ end
222
+
223
+ context 'when limit is passed' do
224
+ it 'limits the records' do
225
+ result = Get::UsersBy.run({ last_name: last_name }, limit: 2)
226
+ expect(result.length).to eq 2
227
+ end
228
+ end
229
+
230
+ context 'when offset is passed' do
231
+ it 'offsets the response' do
232
+ result = Get::UsersBy.run({ last_name: last_name }, offset: 5)
233
+ expect(result.length).to eq 15
234
+ end
235
+ end
236
+
237
+ context 'when order is passed' do
238
+ it 'orders the response' do
239
+ result = Get::UsersBy.run({ last_name: last_name }, order: { id: :asc })
240
+ ar_result = GetSpec::User.where(last_name: last_name).order('id asc')
241
+
242
+ expect(result.first.id).to eq ar_result.first.id
243
+ expect(result.last.id).to eq ar_result.last.id
244
+ end
245
+ end
246
+ end
247
+
213
248
  context 'when no records exist' do
214
249
  it 'returns empty collection' do
215
250
  expect(Get::UsersBy.run(last_name: last_name).empty?).to be true
@@ -217,7 +252,7 @@ describe Get do
217
252
  end
218
253
  end
219
254
 
220
- context 'ancestry' do
255
+ context 'associations' do
221
256
  context 'direct relation' do
222
257
  let(:employer) { GetSpec::Employer.create }
223
258
  let!(:user1) { GetSpec::User.create(employer: employer) }
@@ -232,8 +267,9 @@ describe Get do
232
267
  context 'ChildrenFromParent' do
233
268
  it 'returns children' do
234
269
  result = Get::UsersFromEmployer.run(employer)
235
- expect(result.first.to_h).to eq user1.attributes
236
- expect(result.last.to_h).to eq user2.attributes
270
+ ar_result = GetSpec::User.where(employer_id: employer.id).order('id desc')
271
+ expect(result.first.id).to eq ar_result.first.id
272
+ expect(result.last.id).to eq ar_result.last.id
237
273
  end
238
274
  end
239
275
 
@@ -277,6 +313,55 @@ describe Get do
277
313
  expect(result.first.to_h).to eq sportscar.attributes
278
314
  end
279
315
  end
316
+
317
+ context 'with options' do
318
+ let(:employer) { GetSpec::Employer.create }
319
+ let(:match_count) { 20 }
320
+ let(:miss_count) { 7 }
321
+
322
+ before do
323
+ match_count.times { employer.users << GetSpec::User.create(employer: employer, last_name: last_name) }
324
+ miss_count.times { employer.users << GetSpec::User.create(employer: employer) }
325
+ end
326
+
327
+ context 'when conditions are passed' do
328
+ it 'filters response' do
329
+ result = Get::UsersFromEmployer.run(employer.id, conditions: { last_name: last_name })
330
+ expect(result.length).to eq match_count
331
+ end
332
+ end
333
+
334
+ context 'when limit is passed' do
335
+ it 'limits response' do
336
+ result = Get::UsersFromEmployer.run(employer.id, conditions: { last_name: last_name }, limit: 5)
337
+ expect(result.length).to eq 5
338
+ end
339
+ end
340
+
341
+ context 'when offset is passed' do
342
+ it 'offsets response' do
343
+ result = Get::UsersFromEmployer.run(employer.id, conditions: { last_name: last_name }, offset: 16)
344
+ expect(result.length).to eq match_count - 16
345
+ end
346
+ end
347
+
348
+ context 'when order is passed' do
349
+ it 'orders response' do
350
+ result = Get::UsersFromEmployer.run(employer.id, conditions: { last_name: last_name }, order: { id: :asc })
351
+ ar_result = GetSpec::User.where(employer_id: employer.id, last_name: last_name).order('id asc')
352
+
353
+ expect(result.first.id).to eq ar_result.first.id
354
+ expect(result.last.id).to eq ar_result.last.id
355
+ end
356
+ end
357
+
358
+ context 'when eager_load is passed' do
359
+ it 'behaves as expected' do
360
+ result = Get::UsersFromEmployer.run(employer.id, conditions: { last_name: last_name }, eager_load: true)
361
+ expect(result.length).to eq match_count
362
+ end
363
+ end
364
+ end
280
365
  end
281
366
  end
282
367
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: get
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Blake Turner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-05 00:00:00.000000000 Z
11
+ date: 2015-06-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: horza
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.2.1
19
+ version: 0.3.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.2.1
26
+ version: 0.3.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement