dm-sql-finders 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|