praxis-mapper 4.2 → 4.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.
- checksums.yaml +4 -4
- data/.travis.yml +2 -2
- data/CHANGELOG.md +11 -0
- data/lib/praxis-mapper/query/sequel.rb +4 -4
- data/lib/praxis-mapper/selector_generator.rb +27 -7
- data/lib/praxis-mapper/version.rb +1 -1
- data/spec/factories/all.rb +1 -0
- data/spec/praxis-mapper/selector_generator_spec.rb +46 -7
- data/spec/support/spec_sequel_models.rb +4 -1
- data/spec/support/spec_sequel_resources.rb +24 -2
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cc62b721f14cfb74cf3915d1123dc9970b9033ff
|
4
|
+
data.tar.gz: bc4dda08a87b9d20ffd0be68d963406ea55b3972
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 090b9a57b17a4abaea12a5c58c8540d8c940c323b3ed32a183922353c155279d58561e2454a0c84591d6b18522fd28e4ec15b964c24b6d503c77c3edb93e46cb
|
7
|
+
data.tar.gz: a8425a849b5456eeff9cfa36e954a4f89dcdf0ae0d361b80b8411b29328d4d68fbd19c83b42da95c25ffe56de6b8950670c6258afe50a111cd447ac2acafa7f9
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,17 @@
|
|
2
2
|
|
3
3
|
## next
|
4
4
|
|
5
|
+
## 4.3
|
6
|
+
|
7
|
+
* Added a `:through` option to `Resource.property` to specify that the property
|
8
|
+
effectively traverses the association(s) given so that it may continue to
|
9
|
+
process additional subfield selections.
|
10
|
+
* Fixed `SystemStackError` from `IdentityMap#add_selectors` if the provided
|
11
|
+
field hashes are self-referencing. I.e. `{author: {posts: {author: {...}}}}`
|
12
|
+
* Fixed `SystemStackError` from `SelectorGenerator` for circular `Resource.property` definitions like `property :foo, dependencies: [:foo, :bar]`.
|
13
|
+
* Fixed `Query::Sequel` not working with raw SQL queries.
|
14
|
+
* Fixed SQL logging in `Query::Sequel` for query execution passing a dataset.
|
15
|
+
|
5
16
|
## 4.2
|
6
17
|
|
7
18
|
* Added `Resource.property` to specify the fields and associations from the
|
@@ -52,7 +52,7 @@ module Praxis::Mapper
|
|
52
52
|
#
|
53
53
|
# @return [Array] result-set
|
54
54
|
def _execute(ds=nil)
|
55
|
-
Praxis::Mapper.logger.debug "SQL:\n#{self.describe}\n"
|
55
|
+
Praxis::Mapper.logger.debug "SQL:\n#{self.describe(ds)}\n"
|
56
56
|
self.statistics[:datastore_interactions] += 1
|
57
57
|
start_time = Time.now
|
58
58
|
|
@@ -60,7 +60,7 @@ module Praxis::Mapper
|
|
60
60
|
unless ds.nil?
|
61
61
|
warn 'WARNING: Query::Sequel#_execute ignoring passed dataset due to previously-specified raw SQL'
|
62
62
|
end
|
63
|
-
connection
|
63
|
+
connection[@raw_query].to_a
|
64
64
|
else
|
65
65
|
(ds || self.dataset).to_a
|
66
66
|
end
|
@@ -70,8 +70,8 @@ module Praxis::Mapper
|
|
70
70
|
end
|
71
71
|
|
72
72
|
# @see #sql
|
73
|
-
def describe
|
74
|
-
self.sql
|
73
|
+
def describe(ds=nil)
|
74
|
+
(ds || self).sql
|
75
75
|
end
|
76
76
|
|
77
77
|
# Constructs a raw SQL statement.
|
@@ -8,9 +8,15 @@ module Praxis::Mapper
|
|
8
8
|
@selectors = Hash.new do |hash, key|
|
9
9
|
hash[key] = {select: Set.new, track: Set.new}
|
10
10
|
end
|
11
|
+
@seen = Hash.new do |hash, resource|
|
12
|
+
hash[resource] = Set.new
|
13
|
+
end
|
11
14
|
end
|
12
15
|
|
13
16
|
def add(resource, fields)
|
17
|
+
return if @seen[resource].include? fields
|
18
|
+
@seen[resource] << fields
|
19
|
+
|
14
20
|
fields.each do |name, field|
|
15
21
|
map_property(resource, name, field)
|
16
22
|
end
|
@@ -20,11 +26,11 @@ module Praxis::Mapper
|
|
20
26
|
selectors[resource.model][:select] = true
|
21
27
|
end
|
22
28
|
|
23
|
-
def map_property(resource, name,
|
29
|
+
def map_property(resource, name, fields)
|
24
30
|
if resource.properties.key?(name)
|
25
|
-
add_property(resource, name)
|
31
|
+
add_property(resource, name, fields)
|
26
32
|
elsif resource.model.associations.key?(name)
|
27
|
-
add_association(resource, name,
|
33
|
+
add_association(resource, name, fields)
|
28
34
|
else
|
29
35
|
add_select(resource, name)
|
30
36
|
end
|
@@ -73,13 +79,27 @@ module Praxis::Mapper
|
|
73
79
|
end
|
74
80
|
end
|
75
81
|
|
76
|
-
def add_property(resource, name)
|
82
|
+
def add_property(resource, name, fields)
|
77
83
|
dependencies = resource.properties[name][:dependencies]
|
78
|
-
|
84
|
+
if dependencies
|
85
|
+
dependencies.each do |dependency|
|
86
|
+
# if dependency includes the name, then map it directly as the field
|
87
|
+
if dependency == name
|
88
|
+
add_select(resource, name)
|
89
|
+
else
|
90
|
+
apply_dependency(resource, dependency)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
head, *tail = resource.properties[name][:through]
|
96
|
+
return if head.nil?
|
79
97
|
|
80
|
-
|
81
|
-
|
98
|
+
new_fields = tail.reverse.inject(fields) do |thing, step|
|
99
|
+
{step => thing}
|
82
100
|
end
|
101
|
+
|
102
|
+
add_association(resource, head, new_fields)
|
83
103
|
end
|
84
104
|
|
85
105
|
def apply_dependency(resource, dependency)
|
data/spec/factories/all.rb
CHANGED
@@ -151,21 +151,59 @@ describe Praxis::Mapper::SelectorGenerator do
|
|
151
151
|
end
|
152
152
|
end
|
153
153
|
|
154
|
-
context '
|
155
|
-
let(:properties) { {
|
154
|
+
context 'using a property that specifies a :through option' do
|
155
|
+
let(:properties) { {recent_posts: {author: {full_name: true}}} }
|
156
|
+
let(:resource) { UserResource }
|
156
157
|
let(:expected_selectors) do
|
157
158
|
{
|
158
|
-
|
159
|
-
select: Set.new([:
|
160
|
-
track: Set.new([:
|
159
|
+
PostModel => {
|
160
|
+
select: Set.new([:author_id, :created_at]),
|
161
|
+
track: Set.new([:author])
|
161
162
|
},
|
162
163
|
UserModel => {
|
163
164
|
select: Set.new([:first_name, :last_name]),
|
164
|
-
track: Set.new()
|
165
|
+
track: Set.new([:posts])
|
165
166
|
}
|
166
167
|
}
|
167
168
|
end
|
168
|
-
it 'generates
|
169
|
+
it 'generates the correct set of selectors' do
|
170
|
+
generator.selectors.should eq expected_selectors
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
context 'with a property with a circular definition (ie, includes its own field)' do
|
175
|
+
let(:resource) { PostResource }
|
176
|
+
|
177
|
+
let(:properties) { {id: true, slug: true} }
|
178
|
+
let(:expected_selectors) do
|
179
|
+
{
|
180
|
+
PostModel => {
|
181
|
+
select: Set.new([:id, :slug, :title]),
|
182
|
+
track: Set.new
|
183
|
+
}
|
184
|
+
}
|
185
|
+
end
|
186
|
+
it 'generates the correct set of selectors' do
|
187
|
+
generator.selectors.should eq expected_selectors
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
context 'with a property without the :through option' do
|
192
|
+
let(:resource) { UserResource }
|
193
|
+
let(:properties) { {blogs_summary: {size: true}} }
|
194
|
+
let(:expected_selectors) do
|
195
|
+
{
|
196
|
+
BlogModel => {
|
197
|
+
select: Set.new([:owner_id]),
|
198
|
+
track: Set.new()
|
199
|
+
},
|
200
|
+
UserModel => {
|
201
|
+
select: Set.new([:id]),
|
202
|
+
track: Set.new([:blogs])
|
203
|
+
}
|
204
|
+
}
|
205
|
+
end
|
206
|
+
it 'ignores any subsequent fields when generating selectors' do
|
169
207
|
generator.selectors.should eq expected_selectors
|
170
208
|
end
|
171
209
|
end
|
@@ -216,6 +254,7 @@ describe Praxis::Mapper::SelectorGenerator do
|
|
216
254
|
it 'generates the correct set of selectors' do
|
217
255
|
generator.selectors.should eq(expected_selectors)
|
218
256
|
end
|
257
|
+
|
219
258
|
end
|
220
259
|
|
221
260
|
end
|
@@ -27,7 +27,10 @@ DB.create_table! :posts do
|
|
27
27
|
Integer :author_id
|
28
28
|
|
29
29
|
String :title
|
30
|
+
String :slug
|
30
31
|
String :body
|
32
|
+
|
33
|
+
DateTime :created_at
|
31
34
|
end
|
32
35
|
|
33
36
|
|
@@ -76,7 +79,7 @@ class UserModel < Sequel::Model(:users)
|
|
76
79
|
|
77
80
|
repository_name :sequel
|
78
81
|
|
79
|
-
one_to_many :posts, class: 'PostModel', key: :
|
82
|
+
one_to_many :posts, class: 'PostModel', key: :author_id
|
80
83
|
one_to_many :comments, class: 'CommentModel', key: :author_id
|
81
84
|
one_to_many :blogs, class: 'BlogModel', key: :owner_id
|
82
85
|
|
@@ -37,10 +37,16 @@ end
|
|
37
37
|
class UserResource < BaseResource
|
38
38
|
model UserModel
|
39
39
|
|
40
|
+
property :full_name, dependencies: [:first_name, :last_name]
|
41
|
+
property :blogs_summary, dependencies: [:id, :blogs]
|
42
|
+
|
43
|
+
property :recent_posts, dependencies: ['posts.created_at'],
|
44
|
+
through: [:posts]
|
45
|
+
|
46
|
+
|
40
47
|
def full_name
|
41
48
|
"#{first_name} #{last_name}"
|
42
49
|
end
|
43
|
-
property :full_name, dependencies: [:first_name, :last_name]
|
44
50
|
|
45
51
|
def blogs_summary
|
46
52
|
{
|
@@ -49,9 +55,25 @@ class UserResource < BaseResource
|
|
49
55
|
}
|
50
56
|
end
|
51
57
|
|
52
|
-
|
58
|
+
def recent_posts
|
59
|
+
posts.sort_by(&:created_at).reverse[2]
|
60
|
+
end
|
61
|
+
|
53
62
|
end
|
54
63
|
|
55
64
|
class CommentResource < BaseResource
|
56
65
|
model CommentModel
|
57
66
|
end
|
67
|
+
|
68
|
+
class PostResource < BaseResource
|
69
|
+
model PostModel
|
70
|
+
|
71
|
+
property :slug, dependencies: [:slug, :title]
|
72
|
+
|
73
|
+
# generate default slug from title if one wasn't set in the db
|
74
|
+
def slug
|
75
|
+
return record.slug if record.slug
|
76
|
+
record.title.gsub(" ", "-").downcase
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: praxis-mapper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '4.
|
4
|
+
version: '4.3'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josep M. Blanquer
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2016-08-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: randexp
|
@@ -333,7 +333,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
333
333
|
version: '0'
|
334
334
|
requirements: []
|
335
335
|
rubyforge_project:
|
336
|
-
rubygems_version: 2.
|
336
|
+
rubygems_version: 2.5.1
|
337
337
|
signing_key:
|
338
338
|
specification_version: 4
|
339
339
|
summary: A multi-datastore library designed for efficiency in loading large datasets.
|