flounder 0.9.4 → 0.9.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a2a4bab6f9430ad7169aafe13673bb79debf2d1a
4
- data.tar.gz: ddaa62449b7848ba338f79e48c22eab8d95da823
3
+ metadata.gz: 5e50bc0d92b9351ee20f0dbf9ca3881acf3c58a7
4
+ data.tar.gz: 45da1bd52d62d5fd874f45788564d068e1c47e3a
5
5
  SHA512:
6
- metadata.gz: ef55ee6011bb3a31c99161529775800e347691a93b39b685eb6561c7ad0364a2f1b37d03e8c4236dd99e32d63cfd656900aed69404ffe2143e846dafaac34f91
7
- data.tar.gz: c86cfee4eb453d63af98b23da4a5faeaad3292a3023b983631c159c53ad7bb7037eacd3cc2a8c341b73e0144f79db3166d9377eea5ac0bf10b1f34182f93fad4
6
+ metadata.gz: 87dfe61309ca308686f916ad8475649210720162d660426a6dbaf43dde7e23d8be1c3bc4ce893a901a3623157bc8a2127ff4a52b1f97b9f1f04e5748f5e9bce4
7
+ data.tar.gz: 067d2ef4f6e7adc18e4a1c9a4ef1b5c11ce0bcc00d7ad95648776cccbbcfaf0835e2f995dfa9aec8a633aa2d1cec2cec6354194bcc552ae0400d66da4cbd37a9
data/HISTORY CHANGED
@@ -16,4 +16,9 @@
16
16
  + DELETE FROM - entity#delete
17
17
 
18
18
  0.9.4
19
- + nested transactions
19
+ + nested transactions
20
+
21
+ 0.9.5
22
+ + subquery support
23
+ + localized where as in where(entity, :field => value)
24
+
Binary file
data/flounder.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "flounder"
5
- s.version = '0.9.4'
5
+ s.version = '0.9.5'
6
6
  s.summary = "Flounder is a way to write SQL simply in Ruby. It deals with everything BUT object relational mapping. "
7
7
  s.email = "kaspar.schiess@technologyastronauts.ch"
8
8
  s.homepage = "https://bitbucket.org/technologyastronauts/oss_flounder"
@@ -31,12 +31,22 @@ module Flounder::Query
31
31
  # query.where(:id.noteq => 1) # ... WHERE id != 1
32
32
  #
33
33
  def where *conditions
34
+ conditions = conditions.dup
35
+
36
+ resolve_entity = entity
37
+
38
+ # is the first argument an entity? if yes, interpret field names relative
39
+ # to that entity.
40
+ if conditions.size > 1 && conditions.first.kind_of?(Flounder::Entity)
41
+ resolve_entity = conditions.shift
42
+ end
43
+
34
44
  # is this a hash? extract the first element
35
45
  if conditions.size == 1 && conditions.first.kind_of?(Hash)
36
46
  conditions = conditions.first
37
47
 
38
48
  conditions.each do |k, v|
39
- manager.where(transform_tuple(k, v))
49
+ manager.where(transform_tuple(resolve_entity, k, v))
40
50
  end
41
51
  return self
42
52
  end
@@ -125,21 +135,31 @@ module Flounder::Query
125
135
  # * #where
126
136
  # * #on
127
137
  #
128
- def transform_tuple field, value
138
+ def transform_tuple entity, field, value
129
139
  if value.kind_of? Flounder::Field
130
140
  value = value.arel_field
131
141
  end
132
142
 
143
+ if defined?(DataMapper) &&
144
+ defined?(DataMapper::Query::Operator) &&
145
+ field.kind_of?(DataMapper::Query::Operator)
146
+
147
+ # interop: datamapper hijacks some of our operators, let's reverse this
148
+ field = Flounder::SymbolExtensions::Modifier.new(
149
+ field.target, field.operator)
150
+ end
151
+
133
152
  case field
134
153
  # covers: :field_a => ...
135
154
  when Symbol
136
- join_and_condition_part(entity[field].arel_field, value)
155
+ join_and_condition_part(entity, entity[field].arel_field, value)
137
156
  # covers: entity[:field] => ...
138
157
  when Flounder::Field
139
- join_and_condition_part(field.arel_field, value)
158
+ join_and_condition_part(entity, field.arel_field, value)
140
159
  # covers: :field_a.noteq => ...
141
160
  when Flounder::SymbolExtensions::Modifier
142
161
  join_and_condition_part(
162
+ entity,
143
163
  field.to_arel_field(entity),
144
164
  value,
145
165
  field.kind)
@@ -147,8 +167,11 @@ module Flounder::Query
147
167
  fail "Could not transform condition part. (#{field.inspect}, #{value.inspect})"
148
168
  end
149
169
  end
150
- def join_and_condition_part arel_field, value, kind=:eq
170
+ def join_and_condition_part entity, arel_field, value, kind=:eq
151
171
  case value
172
+ # covers subselects
173
+ when Flounder::Query::Base
174
+ arel_field.send(kind, value.manager)
152
175
  # covers :field_a => :field_b
153
176
  when Symbol
154
177
  value_field = entity[value].arel_field
@@ -66,7 +66,7 @@ module Flounder::Query
66
66
  def on join_conditions
67
67
  join_conditions.each do |k, v|
68
68
  manager.on(
69
- transform_tuple(k, join_field(v)))
69
+ transform_tuple(entity, k, join_field(v)))
70
70
  end
71
71
  self
72
72
  end
@@ -102,6 +102,10 @@ module Flounder::Query
102
102
  self
103
103
  end
104
104
 
105
+ def limit n
106
+ manager.take n
107
+ end
108
+
105
109
  alias all kick
106
110
 
107
111
  def each &block
@@ -133,8 +137,8 @@ module Flounder::Query
133
137
  # or respects field values passed in.
134
138
  #
135
139
  def join_field name
136
- return name if name.kind_of? Flounder::Field
137
- @last_join[name]
140
+ return @last_join[name] if name.kind_of?(Symbol)
141
+ name
138
142
  end
139
143
 
140
144
  # Maps an array of field references to Flounder::Field objects. A field
data/lib/flounder.rb CHANGED
@@ -31,6 +31,11 @@ module_function
31
31
  def domain connection, &block
32
32
  Domain.new(connection).tap { |d| yield d if block_given? }
33
33
  end
34
+
35
+ def literal str
36
+ Arel::Nodes::SqlLiteral.new(str)
37
+ end
38
+ module_function :literal
34
39
  end
35
40
 
36
41
  Symbol.send(:include, Flounder::SymbolExtensions)
data/qed/applique/ae.rb CHANGED
@@ -2,6 +2,6 @@ require 'ae'
2
2
 
3
3
  def generates_sql(expected)
4
4
  -> (given) {
5
- given.to_sql.gsub(/^SELECT.*FROM/, 'SELECT [fields] FROM').assert == expected
5
+ given.to_sql.gsub(/^SELECT.*?FROM/, 'SELECT [fields] FROM').assert == expected
6
6
  }
7
7
  end
data/qed/index.md CHANGED
@@ -63,6 +63,13 @@ Fields can be used fully qualified by going through the entity.
63
63
  assert generates_sql("SELECT [fields] FROM \"users\" WHERE \"users\".\"user_id\" = \"users\".\"approver_id\"")
64
64
  ~~~
65
65
 
66
+ By default, symbols are interpreted as field names in the entity that you start your query with. But you can localize your `#where` clause to any other entity.
67
+
68
+ ~~~ruby
69
+ users.where(posts, :id => 1).
70
+ assert generates_sql("SELECT [fields] FROM \"users\" WHERE \"posts\".\"id\" = 1")
71
+ ~~~
72
+
66
73
  # Some JOINs
67
74
 
68
75
  Here are some non-crazy joins that also work.
data/qed/selects.md CHANGED
@@ -44,3 +44,23 @@ You can treat the entities and the queries like an array.
44
44
  query = entity.where(:id => :id)
45
45
  query.size.assert == entity.size
46
46
  ~~~
47
+
48
+ # Subqueries
49
+
50
+ Sometimes you have to say it with a subquery. For example, you might want to look at the latest post for each author in the database.
51
+
52
+ ~~~ruby
53
+ last_post = posts.
54
+ project(:id).
55
+ order_by(:id.desc). # for lack of timestamps, not as a best practice
56
+ where(:approver_id => domain[:users][:id]).limit(1)
57
+
58
+ query = domain[:users].
59
+ join(posts).on(:id => :user_id, posts[:id] => last_post)
60
+
61
+ query.assert generates_sql(%Q(SELECT [fields] FROM "users" INNER JOIN "posts" ON "posts"."id" = (SELECT "posts"."id" FROM "posts" WHERE "posts"."approver_id" = "users"."id" ORDER BY "posts"."id" DESC LIMIT 1)))
62
+
63
+ row = query.first
64
+ row.post.id.assert == 1
65
+ ~~~
66
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flounder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.4
4
+ version: 0.9.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kaspar Schiess
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-08-14 00:00:00.000000000 Z
12
+ date: 2014-08-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: arel
@@ -92,6 +92,7 @@ files:
92
92
  - HISTORY
93
93
  - LICENSE
94
94
  - README
95
+ - flounder-0.9.4.gem
95
96
  - flounder.gemspec
96
97
  - lib/flounder.rb
97
98
  - lib/flounder/connection.rb