flounder 0.10.0 → 0.11.0

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: d324609dd93210feb39bb7b46739c46cfbc0662f
4
- data.tar.gz: cb52c14ff194b1222eaed3b22b0ad938dc7a1914
3
+ metadata.gz: ea885fee238d20c64364425cad9315b36a857c5a
4
+ data.tar.gz: 213baa1bff13a230263f742537667474e54fecee
5
5
  SHA512:
6
- metadata.gz: 64af342ed59b17cd4912168f60fe61f46fae2e1da4e9077095736b96c917953098a700851c7c877f263d0ddddfc9ddb3a4d683b90313d7d106d778461a7478c8
7
- data.tar.gz: 234cfb876a6f5119807075fcceac54ec63b819af7b733d97964252e43385851af2052ff25928167f376a67383c0dae1e376e5aca60588791fde5ad4cc667e73e
6
+ metadata.gz: 05ecfc437a608a3e87369501f7ab3ffba0373e731752bdaa1fd4d89d7736e6479c33eea3e3ae589e6ae9ba7fb12f699e9100b3d88c763efecbda93e0c1368ae1
7
+ data.tar.gz: 82059189fb7904376ca5d03bd9ceca30fe77e47f67ab61280c49f66b4f9764ac3b34b1710c6f5791f9e66c4d2df64dd2b456309a12ceba636247880714de6409
data/HISTORY CHANGED
@@ -1,3 +1,8 @@
1
+ # 0.11
2
+
3
+ + #anchor now only affects the interpretation of #on, doesn't modify return
4
+ value.
5
+ + #hoist is the opposite of #anchor - it reverts to the original entity.
1
6
 
2
7
  # 0.10
3
8
  + Datamapper interop is improved (also in #order_by)
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.10.0'
5
+ s.version = '0.11.0'
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"
@@ -14,6 +14,9 @@ module Flounder::Query
14
14
  @projection_prefixes = Hash.new
15
15
  @default_projection = []
16
16
 
17
+ # by default, joins are made to the entity that you start the query with
18
+ @join_entity = entity
19
+
17
20
  add_fields_to_default from_entity
18
21
 
19
22
  manager.from from_entity.table
@@ -30,6 +33,8 @@ module Flounder::Query
30
33
  # prefix during this query.
31
34
  attr_reader :projection_prefixes
32
35
 
36
+ attr_reader :join_entity, :last_join
37
+
33
38
  def _join join_node, entity
34
39
  entity = convert_to_entity(entity)
35
40
 
@@ -67,11 +72,17 @@ module Flounder::Query
67
72
 
68
73
  def on join_conditions
69
74
  manager.on(
70
- *join_conditions.map { |(k, v)| transform_tuple(entity, k, join_field(v)) })
75
+ *join_conditions.map { |(k, v)| transform_tuple(
76
+ join_entity, k, join_field(v)) })
71
77
  self
72
78
  end
79
+
73
80
  def anchor
74
- @entity = @last_join
81
+ @join_entity = last_join
82
+ self
83
+ end
84
+ def hoist
85
+ @join_entity = entity
75
86
  self
76
87
  end
77
88
 
data/qed/flounder.sql CHANGED
@@ -30,11 +30,12 @@ DROP TABLE IF EXISTS "comments" CASCADE;
30
30
  CREATE TABLE "comments" (
31
31
  "id" serial PRIMARY KEY,
32
32
  "post_id" int NOT NULL REFERENCES posts("id"),
33
- "text" text NOT NULL
33
+ "text" text NOT NULL,
34
+ "author_id" int not null REFERENCES users("id")
34
35
  );
35
36
 
36
37
  BEGIN;
37
- INSERT INTO "comments" (post_id, text) VALUES (1, 'A silly comment.');
38
+ INSERT INTO "comments" (post_id, text, author_id) VALUES (1, 'A silly comment.', 1);
38
39
  COMMIT;
39
40
 
40
41
  -- import using
data/qed/index.md CHANGED
@@ -72,56 +72,6 @@ By default, symbols are interpreted as field names in the entity that you start
72
72
  assert generates_sql("SELECT [fields] FROM \"users\" WHERE \"posts\".\"id\" = 1")
73
73
  ~~~
74
74
 
75
- # Some JOINs
76
-
77
- Here are some non-crazy joins that also work.
78
-
79
- ~~~ruby
80
- domain[:users].join(domain[:posts]).on(:id => :user_id).
81
- assert generates_sql(%Q(SELECT [fields] FROM "users" INNER JOIN "posts" ON "users"."id" = "posts"."user_id"))
82
-
83
- domain[:users].outer_join(domain[:posts]).on(:id => :user_id).
84
- assert generates_sql(%Q(SELECT [fields] FROM "users" LEFT OUTER JOIN "posts" ON "users"."id" = "posts"."user_id"))
85
- ~~~
86
-
87
- You might want to drop the calls to domain.
88
-
89
- ~~~ruby
90
- domain[:users].join(:posts).on(:id => :user_id).
91
- assert generates_sql(
92
- %Q(SELECT [fields] FROM "users" INNER JOIN "posts" ON "users"."id" = "posts"."user_id"))
93
- ~~~
94
-
95
- Joining presents an interesting dilemma. There are two ways of joining things together, given three tables. The sequence A.B.C might mean to join A to B and C; it might also be interpreted to mean to join A to B and B to C. Here's how we solve this.
96
-
97
- ~~~ruby
98
- domain[:users].
99
- join(domain[:posts]).on(:id => :user_id).
100
- join(domain[:comments]).on(:id => :post_id).
101
- assert generates_sql(%Q(SELECT [fields] FROM "users" INNER JOIN "posts" ON "users"."id" = "posts"."user_id" INNER JOIN "comments" ON "users"."id" = "comments"."post_id"))
102
- ~~~
103
-
104
- So just doing `A.B.C` will give you the first of the above possibilities. Here's how to achive the second effect.
105
-
106
- ~~~ruby
107
- domain[:users].
108
- join(domain[:posts]).on(:id => :user_id).anchor.
109
- join(domain[:comments]).on(:id => :post_id).
110
- assert generates_sql(%Q(SELECT [fields] FROM "users" INNER JOIN "posts" ON "users"."id" = "posts"."user_id" INNER JOIN "comments" ON "posts"."id" = "comments"."post_id"))
111
- ~~~
112
-
113
- The call to `#anchor` anchors all further joins at that point.
114
-
115
- # Ordering records
116
-
117
- ~~~ruby
118
- domain[:users].where(id: 2013).order_by(domain[:users][:id]).
119
- assert generates_sql(%Q(SELECT [fields] FROM "users" WHERE "users"."id" = 2013 ORDER BY "users"."id"))
120
-
121
- domain[:users].order_by(:id).
122
- assert generates_sql(%Q(SELECT [fields] FROM "users" ORDER BY "users"."id"))
123
- ~~~
124
-
125
75
  # Selective projection
126
76
 
127
77
  ~~~ruby
data/qed/joins.md CHANGED
@@ -11,7 +11,7 @@ Joins are correctly created.
11
11
  row.post.id.assert == 1
12
12
  ~~~
13
13
 
14
- Joins are joined using AND.
14
+ Join conditions are joined using `AND`.
15
15
 
16
16
  ~~~ruby
17
17
  query = domain[:posts].
@@ -19,3 +19,67 @@ Joins are … joined using AND.
19
19
 
20
20
  query.assert generates_sql(%Q(SELECT [fields] FROM "posts" INNER JOIN "users" ON "posts"."user_id" = "users"."id" AND "posts"."strange_example_id" = "users"."id"))
21
21
  ~~~
22
+
23
+ You might want to drop the calls to domain.
24
+
25
+ ~~~ruby
26
+ domain[:users].join(:posts).on(:id => :user_id).
27
+ assert generates_sql(
28
+ %Q(SELECT [fields] FROM "users" INNER JOIN "posts" ON "users"."id" = "posts"."user_id"))
29
+ ~~~
30
+
31
+
32
+ # Anchoring
33
+
34
+ Joining presents an interesting dilemma. There are two ways of joining things together, given three tables. The sequence A.B.C might mean to join A to B and C; it might also be interpreted to mean to join A to B and B to C. Here's how we solve this.
35
+
36
+ ~~~ruby
37
+ domain[:users].
38
+ join(domain[:posts]).on(:id => :user_id).
39
+ join(domain[:comments]).on(:id => :post_id).
40
+ assert generates_sql(%Q(SELECT [fields] FROM "users" INNER JOIN "posts" ON "users"."id" = "posts"."user_id" INNER JOIN "comments" ON "users"."id" = "comments"."post_id"))
41
+ ~~~
42
+
43
+ So just doing `A.B.C` will give you the first of the above possibilities. Here's how to achive the second effect.
44
+
45
+ ~~~ruby
46
+ users.
47
+ join(:posts).on(:id => :user_id).anchor.
48
+ join(:comments).on(:id => :post_id).
49
+ assert generates_sql(%Q(SELECT [fields] FROM "users" INNER JOIN "posts" ON "users"."id" = "posts"."user_id" INNER JOIN "comments" ON "posts"."id" = "comments"."post_id"))
50
+ ~~~
51
+
52
+ During the construction of the query, flounder keeps track of what table joins are relative to. That table also provides field resolution for the left hand side of the `#on` clause:
53
+
54
+ A.join(B).on(:a_field => :b_field).
55
+ join(C).on(:a_field => :c_field)
56
+
57
+ By default, A in the above example will always be the entity that you started the query with. To anchor a join on a different entity, you will need to join that entity in and then end the join with a call to `#anchor`:
58
+
59
+ A.join(B).on(:a_field => :b_field).anchor.
60
+ join(C).on(:b_field => :c_field)
61
+
62
+ To get rid of the anchor, you will need to call `#hoist`. This will always reset the left side of all further joins to the entity that you started the
63
+ query with:
64
+
65
+ A.join(B).on(:a_field => :b_field).anchor.
66
+ join(C).on(:b_field => :c_field).hoist.
67
+ join(D).on(:a_field => :d_field)
68
+
69
+ Here's a real usage example.
70
+
71
+ ~~~ruby
72
+ query = users.
73
+ join(:posts).on(:id => :user_id).anchor.
74
+ join(:comments).on(:id => :post_id).hoist.
75
+ join(comments.as(:other_comments, :other_comment)).on(:id => :author_id)
76
+
77
+ query.assert generates_sql("SELECT [fields] FROM \"users\" INNER JOIN \"posts\" ON \"users\".\"id\" = \"posts\".\"user_id\" INNER JOIN \"comments\" ON \"posts\".\"id\" = \"comments\".\"post_id\" INNER JOIN \"comments\" \"other_comments\" ON \"users\".\"id\" = \"other_comments\".\"author_id\"")
78
+ ~~~
79
+
80
+ Results should also be correct:
81
+
82
+ ~~~ruby
83
+ row = query.first
84
+ row.other_comment.assert == row.comment
85
+ ~~~
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.10.0
4
+ version: 0.11.0
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-22 00:00:00.000000000 Z
12
+ date: 2014-08-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: arel