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 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
- Almost all of the implementation is unintrusive, but unfortunately, because DataMapper's DataObjects Adapter does not provide
205
- a great deal of flexibility when it comes to SQL generation, the entire `#select_statement` method has been overridden. For
206
- non-`#by_sql` queries everything follows the original code pathways, and during a `#by_sql` query, the SQL is re-built using
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, but I'm extremely open to contributors which can make the
215
- extension feel as natural and robust as possible. It should be developed such that other DataMapper gems (such as
216
- dm-aggregates and dm-pager) still function without caring that raw SQL is being used in the queries.
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
- - Support overriding `:fields` in a `#by_sql` query (complex if the query depends on RDBMS native functions)
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
 
@@ -35,6 +35,10 @@ module DataMapper
35
35
  def initialize(delegate)
36
36
  @delegate = delegate
37
37
  end
38
+
39
+ def dup
40
+ self.class.new(@delegate.dup)
41
+ end
38
42
  end
39
43
  end
40
44
  end
@@ -1,5 +1,5 @@
1
1
  module DataMapper
2
2
  module SQLFinders
3
- VERSION = "0.0.2"
3
+ VERSION = "0.0.3"
4
4
  end
5
5
  end
@@ -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.2
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-17 00:00:00.000000000Z
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: &13789500 !ruby/object:Gem::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: *13789500
24
+ version_requirements: *17003200
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: dm-do-adapter
27
- requirement: &13785560 !ruby/object:Gem::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: *13785560
35
+ version_requirements: *17002320
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rspec
38
- requirement: &13783660 !ruby/object:Gem::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: *13783660
46
+ version_requirements: *17001160
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: dm-migrations
49
- requirement: &13782460 !ruby/object:Gem::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: *13782460
57
+ version_requirements: *16999680
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: dm-aggregates
60
- requirement: &13779440 !ruby/object:Gem::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: *13779440
68
+ version_requirements: *16995420
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: dm-sqlite-adapter
71
- requirement: &13778640 !ruby/object:Gem::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: *13778640
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