dm-sql-finders 0.0.2 → 0.0.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.
- data/README.md +47 -16
- data/lib/data_mapper/sql_finders/query.rb +4 -0
- data/lib/data_mapper/sql_finders/version.rb +1 -1
- data/spec/public/adapter_spec.rb +8 -0
- metadata +14 -14
data/README.md
CHANGED
@@ -67,7 +67,8 @@ The DataMapper guys are hard at work creating DataMapper 2.0, which involves a l
|
|
67
67
|
notably building DM's query interface atop [Veritas](https://github.com/dkubb/veritas), with the adapter layer generating
|
68
68
|
SQL by walking a Veritas relation (an AST - abstract syntax tree). Because of the way DM 1 handles queries, it is not
|
69
69
|
trivial to support SQL provided by the user (except for the trival case of it being in the WHERE clause). With any hope,
|
70
|
-
gems like this will either not be needed in DM 2.0, or at least will be easy to implement cleanly
|
70
|
+
gems like this will either not be needed in DM 2.0, or at least will be easy to implement cleanly, since SQL and Veritas
|
71
|
+
play nicely with each other.
|
71
72
|
|
72
73
|
## Installation
|
73
74
|
|
@@ -75,10 +76,6 @@ Via rubygems:
|
|
75
76
|
|
76
77
|
gem install dm-sql-finders
|
77
78
|
|
78
|
-
Note that while the gem is functional, it has several known limitations, which I aim to work about by improving the
|
79
|
-
parsing and generating logic. It is unlikely you will hit the limitations unless you extensively use `#by_sql` in
|
80
|
-
conjunction with options such as `:links`.
|
81
|
-
|
82
79
|
## Detailed Usage
|
83
80
|
|
84
81
|
Note that in the following examples, you are not forced to use the table representations yielded into the block, but you
|
@@ -90,7 +87,7 @@ are encouraged to. They respond to the following methods:
|
|
90
87
|
- `tbl.property_name`: represents the field name in the database mapping to `property_name` in your model.
|
91
88
|
|
92
89
|
Writing the field/table names directly, while it will work, is not advised, since it will significantly hamper any future
|
93
|
-
efforts to chain onto the query (and it reads just like SQL, right?).
|
90
|
+
efforts to chain onto the query (and it reads just like SQL anyway, right?).
|
94
91
|
|
95
92
|
### Basic SELECT statements
|
96
93
|
|
@@ -112,6 +109,34 @@ def self.created_after(time)
|
|
112
109
|
end
|
113
110
|
```
|
114
111
|
|
112
|
+
### Selecting less than all fields
|
113
|
+
|
114
|
+
Just specify individual fields in the SQL. The regular DM semantics apply (i.e. the rest will be lazy loaded, and omitting the
|
115
|
+
primary key means your records are immutable).
|
116
|
+
|
117
|
+
``` ruby
|
118
|
+
def self.usernames_only
|
119
|
+
by_sql { |u| "SELECT #{u.username} FROM #{u}" }
|
120
|
+
end
|
121
|
+
```
|
122
|
+
|
123
|
+
### Selecting *more* than all fields (experimental)
|
124
|
+
|
125
|
+
This allows you to pre-load things like aggregate calculations you may otherwise add denormalizations for:
|
126
|
+
|
127
|
+
``` ruby
|
128
|
+
def self.with_post_counts
|
129
|
+
by_sql(Post) { |u, p| "SELECT #{u.*}, COUNT(#{p.id}) AS post_count FROM #{u} INNER JOIN #{p} ON #{p.user_id} = #{u.id} GROUP BY #{u.id}" }
|
130
|
+
end
|
131
|
+
```
|
132
|
+
|
133
|
+
A `@post_count` instnace variable is set on all resources. Currently this is always a String. You will need to typecast manually.
|
134
|
+
|
135
|
+
See the section on "Joins" for details on the join syntax.
|
136
|
+
|
137
|
+
You should consider this feature experimental. It takes advantage of the fact DM Property instances can be created and thrown-away
|
138
|
+
on-the-fly.
|
139
|
+
|
115
140
|
### Ordering
|
116
141
|
|
117
142
|
DataMapper always adds an ORDER BY to your queries if you don't specify one. DataMapper SQL Finders behaves no differently.
|
@@ -201,27 +226,33 @@ I have no idea what will happen if it is attempted, but it almost certainly will
|
|
201
226
|
|
202
227
|
## Will it interfere with DataMapper?
|
203
228
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
a combination of the original logic and some custom logic to include your SQL. In short, yes, it does interfere, but I don't
|
208
|
-
believe there are any alternatives without extensive work on DataMapper's Query interface and the DataObjects adapter itself.
|
229
|
+
`#select_statement` on the adapter is overridden such that, when you use `#by_sql` query, code in the gem is executed, and
|
230
|
+
when you execute a regular query, the original code pathways are followed. I'd prefer some sort of extension API in
|
231
|
+
DataObjectsAdapter to allow hooks into its SQL generation logic, but for now, this is how it works.
|
209
232
|
|
210
233
|
DataMapper 2.0 *should* fix this.
|
211
234
|
|
212
235
|
## Contributors
|
213
236
|
|
214
|
-
DataMapper SQL Finders is currently written by Chris Corbyn
|
215
|
-
|
216
|
-
|
237
|
+
DataMapper SQL Finders is currently written by [Chris Corbyn](https://github.com/d11wtq)
|
238
|
+
|
239
|
+
Contributions are more than gladly accepted. The primary goal is to support SQL in a way that does not break gems like dm-aggregates
|
240
|
+
and dm-pager. The more the SQL can be interpreted and turned into a native Query, the better.
|
217
241
|
|
218
242
|
## TODO
|
219
243
|
|
220
|
-
|
244
|
+
There are some known limitations, that are mostly edge-cases. You will only run into them if you try to get too crazy combining regular
|
245
|
+
DM queries with SQL (e.g. adding `:links` to a hand-written SQL query works, unless you have used bind values somewhere other than the
|
246
|
+
WHERE clause *and if*, and *only if* DataMapper needs to use a bind value in the join, such as for special join conditions). Real
|
247
|
+
edge-cases.
|
248
|
+
|
249
|
+
- Support overriding `:fields` in a `#by_sql` query (complex if the query depends on RDBMS native functions in both the WHERE and the SELECT)
|
221
250
|
- Reverse the order when invoking `#reverse` in a `#by_sql` query that used `ORDER BY` in the SQL (note this will work just fine if
|
222
251
|
you use the `:order` option)
|
223
252
|
- Better support for `?` replacements in places other than the `WHERE` clause
|
224
253
|
- Support set operations (union, intersection, difference)
|
254
|
+
- Possibly (?) support crazy complex mass-updates (seems a little DB-specific though):
|
255
|
+
`User.by_sql { ... something with join conditions ... }.update!(:banned => true)` (MySQL, for one, can do `UPDATE ... INNER JOIN ...`)
|
225
256
|
|
226
257
|
## Future Plans
|
227
258
|
|
@@ -233,7 +264,7 @@ therefore allowing you to simplify the query and let DMQL hande things like JOIN
|
|
233
264
|
Post.by_dmql("JOIN User u WHERE u.username = ?", "Bob")
|
234
265
|
```
|
235
266
|
|
236
|
-
Which would INNER JOIN posts with users and map u.username with the real field name of the `User#username` property.
|
267
|
+
Which would INNER JOIN posts with users and map `u.username` with the real field name of the `User#username` property.
|
237
268
|
|
238
269
|
This gem would be a pre-requisite for that.
|
239
270
|
|
data/spec/public/adapter_spec.rb
CHANGED
@@ -319,5 +319,13 @@ describe DataMapper::Adapters::DataObjectsAdapter do
|
|
319
319
|
@users.to_a.first.post_count.should == 1
|
320
320
|
end
|
321
321
|
end
|
322
|
+
|
323
|
+
# fixed an obscure bug with state leakage here
|
324
|
+
describe "#reverse!" do
|
325
|
+
it "is consistent between invocations" do
|
326
|
+
User.all.query.reverse.order.first.operator.should == :desc
|
327
|
+
User.all.query.reverse.order.first.operator.should == :desc
|
328
|
+
end
|
329
|
+
end
|
322
330
|
end
|
323
331
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dm-sql-finders
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-10-
|
12
|
+
date: 2011-10-20 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: dm-core
|
16
|
-
requirement: &
|
16
|
+
requirement: &17003200 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 1.2.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *17003200
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: dm-do-adapter
|
27
|
-
requirement: &
|
27
|
+
requirement: &17002320 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 1.2.0
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *17002320
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rspec
|
38
|
-
requirement: &
|
38
|
+
requirement: &17001160 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '2.6'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *17001160
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: dm-migrations
|
49
|
-
requirement: &
|
49
|
+
requirement: &16999680 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 1.2.0
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *16999680
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: dm-aggregates
|
60
|
-
requirement: &
|
60
|
+
requirement: &16995420 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: 1.2.0
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *16995420
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: dm-sqlite-adapter
|
71
|
-
requirement: &
|
71
|
+
requirement: &16993080 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,7 +76,7 @@ dependencies:
|
|
76
76
|
version: 1.2.0
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *16993080
|
80
80
|
description: ! "dm-sql-finders add #by_sql to your DataMapper models and provides
|
81
81
|
a clean mechanism for using\n the names of the properties in
|
82
82
|
your model, instead of the actual fields in the database. Any SQL\n is
|