baby_squeel 0.1.0 → 0.2.0
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +6 -0
- data/.travis.yml +1 -0
- data/README.md +52 -36
- data/Rakefile +2 -1
- data/lib/baby_squeel.rb +1 -0
- data/lib/baby_squeel/active_record.rb +6 -1
- data/lib/baby_squeel/association.rb +33 -30
- data/lib/baby_squeel/dsl.rb +14 -0
- data/lib/baby_squeel/join_dependency.rb +24 -40
- data/lib/baby_squeel/nodes.rb +28 -7
- data/lib/baby_squeel/operators.rb +22 -0
- data/lib/baby_squeel/table.rb +34 -22
- data/lib/baby_squeel/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3569d1726ce4c979428cbc2fed31fe8103f16405
|
4
|
+
data.tar.gz: 7d60acb4736d2a7cdda1e921bcb32ac1b8597601
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 81b72fb9e8b0f80dc8a0c5e52b215ed89e8f8801407ec2a60747f06171f35b9e6f8d0970c7009573092b17eaaa67ea8fabfa8dcf542b1aa0396b777df966bd4a
|
7
|
+
data.tar.gz: fdcbff4355e934d51d6f6e57e19fdbda28a93eac0acb3ea91b4fc1d1d7c9ed84ae06c75dcb500a72325577374df38c0969ebef9dbee45b08a7cd0845de27c374
|
data/.rubocop.yml
CHANGED
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -53,41 +53,6 @@ Post.joins(:author).selecting { [id, author.id] }
|
|
53
53
|
# INNER JOIN "authors" ON "posts"."author_id" = "authors"."id"
|
54
54
|
```
|
55
55
|
|
56
|
-
#### Joins
|
57
|
-
|
58
|
-
```ruby
|
59
|
-
Post.joining { author }
|
60
|
-
# SELECT "posts".* FROM "posts"
|
61
|
-
# INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
62
|
-
|
63
|
-
Post.joining { [author.outer, comments] }
|
64
|
-
# SELECT "posts".* FROM "posts"
|
65
|
-
# LEFT OUTER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
66
|
-
# INNER JOIN "comments" ON "comments"."post_id" = "posts"."id"
|
67
|
-
|
68
|
-
Post.joining { author.comments }
|
69
|
-
# SELECT "posts".* FROM "posts"
|
70
|
-
# INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
71
|
-
# INNER JOIN "comments" ON "comments"."author_id" = "authors"."id"
|
72
|
-
|
73
|
-
Post.joining { author.outer.comments.outer }
|
74
|
-
# SELECT "posts".* FROM "posts"
|
75
|
-
# INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
76
|
-
# LEFT OUTER JOIN "comments" ON "comments"."author_id" = "authors"."id"
|
77
|
-
|
78
|
-
Post.joining { author.comments.outer }
|
79
|
-
# SELECT "posts".* FROM "posts"
|
80
|
-
# INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
81
|
-
# LEFT OUTER JOIN "comments" ON "comments"."author_id" = "authors"."id"
|
82
|
-
|
83
|
-
Post.joining { author.alias('a').on((author.id == author_id) | (author.name == title)) }
|
84
|
-
# SELECT "posts".* FROM "posts"
|
85
|
-
# INNER JOIN "authors" "a" ON (
|
86
|
-
# "authors"."id" = "posts"."author_id" OR
|
87
|
-
# "authors"."name" = "posts"."title"
|
88
|
-
# )
|
89
|
-
```
|
90
|
-
|
91
56
|
#### Wheres
|
92
57
|
|
93
58
|
```ruby
|
@@ -110,6 +75,16 @@ Post.joins(:author).where.has { author.name == 'Ray' }
|
|
110
75
|
# WHERE "authors"."name" = 'Ray'
|
111
76
|
```
|
112
77
|
|
78
|
+
Here's the best part. Where conditions will always reference the correct table alias for a given association:
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
Post.joins(author: :posts).where.has { author.posts.title =~ '%fun%' }
|
82
|
+
# SELECT "posts".* FROM "posts"
|
83
|
+
# INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
84
|
+
# INNER JOIN "posts" "posts_authors" ON "posts_authors"."author_id" = "authors"."id"
|
85
|
+
# WHERE ("posts_authors"."title" LIKE '%fun%')
|
86
|
+
```
|
87
|
+
|
113
88
|
#### Orders
|
114
89
|
|
115
90
|
```ruby
|
@@ -130,6 +105,47 @@ Post.joins(:author).ordering { author.id.desc }
|
|
130
105
|
# ORDER BY "authors"."id" DESC
|
131
106
|
```
|
132
107
|
|
108
|
+
|
109
|
+
#### Joins
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
Post.joining { author }
|
113
|
+
# SELECT "posts".* FROM "posts"
|
114
|
+
# INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
115
|
+
|
116
|
+
Post.joining { [author.outer, comments] }
|
117
|
+
# SELECT "posts".* FROM "posts"
|
118
|
+
# LEFT OUTER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
119
|
+
# INNER JOIN "comments" ON "comments"."post_id" = "posts"."id"
|
120
|
+
|
121
|
+
Post.joining { author.comments }
|
122
|
+
# SELECT "posts".* FROM "posts"
|
123
|
+
# INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
124
|
+
# INNER JOIN "comments" ON "comments"."author_id" = "authors"."id"
|
125
|
+
|
126
|
+
Post.joining { author.outer.comments.outer }
|
127
|
+
# SELECT "posts".* FROM "posts"
|
128
|
+
# INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
129
|
+
# LEFT OUTER JOIN "comments" ON "comments"."author_id" = "authors"."id"
|
130
|
+
|
131
|
+
Post.joining { author.comments.outer }
|
132
|
+
# SELECT "posts".* FROM "posts"
|
133
|
+
# INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
134
|
+
# LEFT OUTER JOIN "comments" ON "comments"."author_id" = "authors"."id"
|
135
|
+
|
136
|
+
Post.joining { author.outer.posts }
|
137
|
+
# SELECT "posts".* FROM "posts"
|
138
|
+
# LEFT OUTER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
139
|
+
# INNER JOIN "posts" "posts_authors" ON "posts_authors"."author_id" = "authors"."id"
|
140
|
+
|
141
|
+
Post.joining { author.alias('a').on((author.id == author_id) | (author.name == title)) }
|
142
|
+
# SELECT "posts".* FROM "posts"
|
143
|
+
# INNER JOIN "authors" "a" ON (
|
144
|
+
# "authors"."id" = "posts"."author_id" OR
|
145
|
+
# "authors"."name" = "posts"."title"
|
146
|
+
# )
|
147
|
+
```
|
148
|
+
|
133
149
|
#### Functions
|
134
150
|
|
135
151
|
```ruby
|
@@ -158,7 +174,7 @@ You can also run `bin/console` to open up a prompt where you'll have access to s
|
|
158
174
|
|
159
175
|
## Todo
|
160
176
|
|
161
|
-
|
177
|
+
+ Subqueries
|
162
178
|
|
163
179
|
## Contributing
|
164
180
|
|
data/Rakefile
CHANGED
@@ -15,9 +15,10 @@ def run_version(version, cmd)
|
|
15
15
|
system({ 'AR' => version }, cmd)
|
16
16
|
end
|
17
17
|
|
18
|
-
abort "\nFAILED: #{display}" unless
|
18
|
+
abort "\nFAILED: #{display}" unless $?.success?
|
19
19
|
end
|
20
20
|
|
21
|
+
desc 'Run against all ActiveRecord versions'
|
21
22
|
task 'spec:matrix' do
|
22
23
|
travis = YAML.load_file '.travis.yml'
|
23
24
|
|
data/lib/baby_squeel.rb
CHANGED
@@ -3,14 +3,17 @@ require 'baby_squeel/dsl'
|
|
3
3
|
module BabySqueel
|
4
4
|
module ActiveRecord
|
5
5
|
module QueryMethods
|
6
|
+
# Constructs Arel for ActiveRecord::Base#joins using the DSL.
|
6
7
|
def joining(&block)
|
7
|
-
joins DSL.evaluate(
|
8
|
+
joins DSL.evaluate(unscoped, &block)
|
8
9
|
end
|
9
10
|
|
11
|
+
# Constructs Arel for ActiveRecord::Base#select using the DSL.
|
10
12
|
def selecting(&block)
|
11
13
|
select DSL.evaluate(self, &block)
|
12
14
|
end
|
13
15
|
|
16
|
+
# Constructs Arel for ActiveRecord::Base#order using the DSL.
|
14
17
|
def ordering(&block)
|
15
18
|
order DSL.evaluate(self, &block)
|
16
19
|
end
|
@@ -18,6 +21,7 @@ module BabySqueel
|
|
18
21
|
|
19
22
|
module WhereChain
|
20
23
|
if ::ActiveRecord::VERSION::MAJOR > 4
|
24
|
+
# Constructs Arel for ActiveRecord::Base#where using the DSL.
|
21
25
|
def has(&block)
|
22
26
|
opts = DSL.evaluate(@scope, &block)
|
23
27
|
factory = @scope.send(:where_clause_factory)
|
@@ -25,6 +29,7 @@ module BabySqueel
|
|
25
29
|
@scope
|
26
30
|
end
|
27
31
|
else
|
32
|
+
# Constructs Arel for ActiveRecord::Base#where using the DSL.
|
28
33
|
def has(&block)
|
29
34
|
@scope.where_values += [DSL.evaluate(@scope, &block)]
|
30
35
|
@scope
|
@@ -1,42 +1,45 @@
|
|
1
1
|
require 'baby_squeel/table'
|
2
|
-
require 'baby_squeel/join_dependency'
|
3
2
|
|
4
3
|
module BabySqueel
|
5
|
-
class AliasingError < StandardError
|
6
|
-
MESSAGE =
|
7
|
-
'Attempted to alias \'%{association}\' as \'%{alias_name}\', but the ' \
|
8
|
-
'association was implicitly joined. Either join the association ' \
|
9
|
-
'with `on` or remove the alias.'.freeze
|
10
|
-
|
11
|
-
def initialize(association, alias_name)
|
12
|
-
super format(MESSAGE, association: association, alias_name: alias_name)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
4
|
class Association < Table
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
5
|
+
class AliasingError < StandardError
|
6
|
+
MESSAGE =
|
7
|
+
'Attempted to alias \'%{association}\' as \'%{alias_name}\', but the ' \
|
8
|
+
'association was implicitly joined. Either join the association ' \
|
9
|
+
'with `on` or remove the alias.'.freeze
|
10
|
+
|
11
|
+
def initialize(association, alias_name)
|
12
|
+
super format(MESSAGE, association: association, alias_name: alias_name)
|
13
|
+
end
|
25
14
|
end
|
26
15
|
|
27
|
-
|
28
|
-
|
29
|
-
def join_constraints
|
30
|
-
if props[:table].is_a? Arel::Nodes::TableAlias
|
31
|
-
raise AliasingError.new(@reflection.name, props[:table].right)
|
32
|
-
end
|
16
|
+
attr_reader :_reflection
|
33
17
|
|
34
|
-
|
18
|
+
def initialize(parent, reflection)
|
19
|
+
@parent = parent
|
20
|
+
@_reflection = reflection
|
21
|
+
super(@_reflection.klass)
|
35
22
|
end
|
36
23
|
|
37
|
-
|
38
|
-
|
39
|
-
|
24
|
+
# Intelligently constructs Arel nodes. There are three outcomes:
|
25
|
+
#
|
26
|
+
# 1. The user explicitly constructed their join using #on.
|
27
|
+
# See BabySqueel::Table#_arel.
|
28
|
+
#
|
29
|
+
# 2. The user aliased an implicitly joined association. ActiveRecord's
|
30
|
+
# join dependency gives us no way of handling this, so we have to
|
31
|
+
# throw an error.
|
32
|
+
#
|
33
|
+
# 3. The user implicitly joined this association, so we pass this
|
34
|
+
# association up the tree until it hits the top-level BabySqueel::Table.
|
35
|
+
# Once it gets there, Arel join nodes will be constructed.
|
36
|
+
def _arel(associations = [])
|
37
|
+
if _on
|
38
|
+
super
|
39
|
+
elsif _table.is_a? Arel::Nodes::TableAlias
|
40
|
+
raise AliasingError.new(_reflection.name, _table.right)
|
41
|
+
else
|
42
|
+
@parent._arel([self, *associations])
|
40
43
|
end
|
41
44
|
end
|
42
45
|
end
|
data/lib/baby_squeel/dsl.rb
CHANGED
@@ -4,14 +4,28 @@ require 'baby_squeel/association'
|
|
4
4
|
|
5
5
|
module BabySqueel
|
6
6
|
class DSL < Table
|
7
|
+
# Evaluates a block in the context of a new DSL instance.
|
7
8
|
def self.evaluate(scope, &block)
|
8
9
|
new(scope).evaluate(&block)
|
9
10
|
end
|
10
11
|
|
12
|
+
# Create a SQL function. See Arel::Nodes::NamedFunction.
|
13
|
+
#
|
14
|
+
# ==== Arguments
|
15
|
+
#
|
16
|
+
# * +name+ - The name of a SQL function (ex. coalesce).
|
17
|
+
# * +args+ - The arguments to be passed to the SQL function.
|
18
|
+
#
|
19
|
+
# ==== Example
|
20
|
+
# Post.select { func('coalesce', id, 1) }
|
21
|
+
# #=> SELECT COALESCE("posts"."id", 1) FROM "posts"
|
22
|
+
#
|
11
23
|
def func(name, *args)
|
12
24
|
Nodes.wrap Arel::Nodes::NamedFunction.new(name.to_s, args)
|
13
25
|
end
|
14
26
|
|
27
|
+
# Evaluates a DSL block. If arity is given, this method
|
28
|
+
# `yield` itself, rather than `instance_eval`.
|
15
29
|
def evaluate(&block)
|
16
30
|
if block.arity.zero?
|
17
31
|
Nodes.unwrap instance_eval(&block)
|
@@ -1,55 +1,39 @@
|
|
1
|
-
# Props to Arel Helpers
|
2
|
-
# https://github.com/camertron/arel-helpers/blob/master/lib/arel-helpers/join_association.rb
|
3
|
-
#
|
4
|
-
# This is really, really ugly.
|
5
|
-
#
|
6
1
|
module BabySqueel
|
7
2
|
class JoinDependency
|
8
|
-
def initialize(scope,
|
3
|
+
def initialize(scope, associations = [])
|
9
4
|
@scope = scope
|
10
|
-
@
|
11
|
-
@join_type = join_type
|
5
|
+
@associations = associations
|
12
6
|
end
|
13
7
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
-
end
|
24
|
-
elsif ::ActiveRecord::VERSION::STRING >= '4.1.0'
|
25
|
-
def constraints
|
26
|
-
dependency.join_constraints([]).flat_map { |join| rebuild join }
|
27
|
-
end
|
28
|
-
else
|
29
|
-
def constraints
|
30
|
-
manager = Arel::SelectManager.new(@scope)
|
31
|
-
|
32
|
-
dependency.join_associations.each do |assoc|
|
33
|
-
assoc.join_type = @join_type
|
34
|
-
assoc.join_to(manager)
|
35
|
-
end
|
36
|
-
|
37
|
-
manager.join_sources
|
8
|
+
# Converts an array of BabySqueel::Associations into an array
|
9
|
+
# of Arel join nodes.
|
10
|
+
#
|
11
|
+
# Each association is built individually so that the correct
|
12
|
+
# Arel join node will be used for each individual association.
|
13
|
+
def constraints
|
14
|
+
@associations.each.with_index.inject([]) do |joins, (assoc, i)|
|
15
|
+
inject @associations[0..i], joins, assoc._join
|
38
16
|
end
|
39
17
|
end
|
40
18
|
|
41
19
|
private
|
42
20
|
|
43
|
-
def
|
44
|
-
|
21
|
+
def inject(associations, theirs, join_node)
|
22
|
+
names = join_names associations
|
23
|
+
mine = build names, join_node
|
24
|
+
theirs + mine[theirs.length..-1]
|
45
25
|
end
|
46
26
|
|
47
|
-
def
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
27
|
+
def build(names, join_node)
|
28
|
+
@scope.joins(names).join_sources.map do |join|
|
29
|
+
join_node.new(join.left, join.right)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def join_names(associations = [])
|
34
|
+
associations.reverse.inject({}) do |names, assoc|
|
35
|
+
{ assoc._reflection.name => names }
|
36
|
+
end
|
53
37
|
end
|
54
38
|
end
|
55
39
|
end
|
data/lib/baby_squeel/nodes.rb
CHANGED
@@ -3,6 +3,8 @@ require 'baby_squeel/operators'
|
|
3
3
|
module BabySqueel
|
4
4
|
module Nodes
|
5
5
|
class << self
|
6
|
+
# Wraps an Arel node in a Proxy so that it can
|
7
|
+
# be extended.
|
6
8
|
def wrap(arel)
|
7
9
|
if arel.class.parents.include?(Arel)
|
8
10
|
Generic.new(arel)
|
@@ -11,6 +13,8 @@ module BabySqueel
|
|
11
13
|
end
|
12
14
|
end
|
13
15
|
|
16
|
+
# Unwraps a BabySqueel::Proxy before being passed to
|
17
|
+
# ActiveRecord.
|
14
18
|
def unwrap(node)
|
15
19
|
if node.respond_to? :_arel
|
16
20
|
node._arel
|
@@ -22,9 +26,8 @@ module BabySqueel
|
|
22
26
|
end
|
23
27
|
end
|
24
28
|
|
25
|
-
# This proxy class allows us to quack like
|
26
|
-
#
|
27
|
-
# hit, we'll instantiate a new proxy object.
|
29
|
+
# This proxy class allows us to quack like any arel object. When a
|
30
|
+
# method missing is hit, we'll instantiate a new proxy object.
|
28
31
|
class Proxy < ActiveSupport::ProxyObject
|
29
32
|
# Resolve constants the normal way
|
30
33
|
def self.const_missing(name)
|
@@ -52,11 +55,11 @@ module BabySqueel
|
|
52
55
|
end
|
53
56
|
end
|
54
57
|
|
55
|
-
# This is a generic proxy class that includes
|
56
|
-
#
|
57
|
-
#
|
58
|
-
# only include necessary/applicable modules.
|
58
|
+
# This is a generic proxy class that includes all possible modules.
|
59
|
+
# In the future, these proxy classes should be more specific and only
|
60
|
+
# include necessary/applicable modules.
|
59
61
|
class Generic < Proxy
|
62
|
+
extend Operators::ArelAliasing
|
60
63
|
include Arel::OrderPredications
|
61
64
|
include Operators::Comparison
|
62
65
|
include Operators::Equality
|
@@ -64,5 +67,23 @@ module BabySqueel
|
|
64
67
|
include Operators::Grouping
|
65
68
|
include Operators::Matching
|
66
69
|
end
|
70
|
+
|
71
|
+
class Attribute < Generic
|
72
|
+
def initialize(parent, name)
|
73
|
+
@parent = parent
|
74
|
+
@name = name
|
75
|
+
super(parent._table[name])
|
76
|
+
end
|
77
|
+
|
78
|
+
def _arel
|
79
|
+
parent_arel = @parent._arel
|
80
|
+
|
81
|
+
if parent_arel && parent_arel.last
|
82
|
+
parent_arel.last.left[@name]
|
83
|
+
else
|
84
|
+
super
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
67
88
|
end
|
68
89
|
end
|
@@ -1,6 +1,17 @@
|
|
1
1
|
module BabySqueel
|
2
2
|
module Operators
|
3
3
|
module ArelAliasing
|
4
|
+
# Allows the creation of shorthands for Arel methods.
|
5
|
+
#
|
6
|
+
# ==== Arguments
|
7
|
+
#
|
8
|
+
# * +operator+ - A custom operator.
|
9
|
+
# * +arel_name+ - The name of the Arel method you want to alias.
|
10
|
+
#
|
11
|
+
# ==== Example
|
12
|
+
# BabySqueel::Nodes::Generic.arel_alias :unlike, :does_not_match
|
13
|
+
# Post.where { title.unlike 'something' }
|
14
|
+
#
|
4
15
|
def arel_alias(operator, arel_name)
|
5
16
|
define_method operator do |other|
|
6
17
|
send(arel_name, other)
|
@@ -23,6 +34,17 @@ module BabySqueel
|
|
23
34
|
end
|
24
35
|
|
25
36
|
module Generic
|
37
|
+
# Create a SQL operation. See Arel::Nodes::InfixOperation.
|
38
|
+
#
|
39
|
+
# ==== Arguments
|
40
|
+
#
|
41
|
+
# * +operator+ - A SQL operator.
|
42
|
+
# * +other+ - The argument to be passed to the SQL operator.
|
43
|
+
#
|
44
|
+
# ==== Example
|
45
|
+
# Post.select { title.op('||', 'diddly') }
|
46
|
+
# #=> SELECT "posts"."title" || 'diddly' FROM "posts"
|
47
|
+
#
|
26
48
|
def op(operator, other)
|
27
49
|
Nodes.wrap Arel::Nodes::InfixOperation.new(operator, self, other)
|
28
50
|
end
|
data/lib/baby_squeel/table.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'baby_squeel/join_dependency'
|
2
|
+
|
1
3
|
module BabySqueel
|
2
4
|
class AssociationNotFoundError < StandardError
|
3
5
|
def initialize(scope, name)
|
@@ -6,16 +8,21 @@ module BabySqueel
|
|
6
8
|
end
|
7
9
|
|
8
10
|
class Table
|
9
|
-
|
11
|
+
attr_accessor :_on, :_join, :_table
|
10
12
|
|
11
13
|
def initialize(scope)
|
12
14
|
@scope = scope
|
15
|
+
@_table = scope.arel_table
|
16
|
+
@_join = Arel::Nodes::InnerJoin
|
13
17
|
end
|
14
18
|
|
19
|
+
# See Arel::Table#[]
|
15
20
|
def [](key)
|
16
|
-
Nodes.
|
21
|
+
Nodes::Attribute.new(self, key)
|
17
22
|
end
|
18
23
|
|
24
|
+
# Constructs a new BabySqueel::Association. Raises
|
25
|
+
# an exception if the association is not found.
|
19
26
|
def association(name)
|
20
27
|
if reflection = @scope.reflect_on_association(name)
|
21
28
|
Association.new(self, reflection)
|
@@ -24,58 +31,63 @@ module BabySqueel
|
|
24
31
|
end
|
25
32
|
end
|
26
33
|
|
34
|
+
# Alias a table. This is only possible when joining
|
35
|
+
# an association explicitly.
|
27
36
|
def alias(alias_name)
|
28
|
-
|
37
|
+
clone.alias! alias_name
|
29
38
|
end
|
30
39
|
|
31
40
|
def alias!(alias_name)
|
32
|
-
|
41
|
+
self._table = _table.alias(alias_name)
|
33
42
|
self
|
34
43
|
end
|
35
44
|
|
45
|
+
# Instruct the table to be joined with an INNER JOIN.
|
36
46
|
def outer
|
37
|
-
|
47
|
+
clone.outer!
|
38
48
|
end
|
39
49
|
|
40
50
|
def outer!
|
41
|
-
|
51
|
+
self._join = Arel::Nodes::OuterJoin
|
42
52
|
self
|
43
53
|
end
|
44
54
|
|
55
|
+
# Instruct the table to be joined with an INNER JOIN.
|
45
56
|
def inner
|
46
|
-
|
57
|
+
clone.inner!
|
47
58
|
end
|
48
59
|
|
49
60
|
def inner!
|
50
|
-
|
61
|
+
self._join = Arel::Nodes::InnerJoin
|
51
62
|
self
|
52
63
|
end
|
53
64
|
|
65
|
+
# Specify an explicit join.
|
54
66
|
def on(node)
|
55
|
-
|
67
|
+
clone.on! node
|
56
68
|
end
|
57
69
|
|
58
70
|
def on!(node)
|
59
|
-
|
71
|
+
self._on = Arel::Nodes::On.new(node)
|
60
72
|
self
|
61
73
|
end
|
62
74
|
|
63
|
-
|
64
|
-
|
75
|
+
# This method will be invoked by BabySqueel::Nodes::unwrap. When called,
|
76
|
+
# there are two possible outcomes:
|
77
|
+
#
|
78
|
+
# 1. Join explicitly using an on clause.
|
79
|
+
# 2. Resolve the assocition's join clauses using ActiveRecord.
|
80
|
+
#
|
81
|
+
def _arel(associations = [])
|
82
|
+
if _on
|
83
|
+
_join.new(_table, _on)
|
84
|
+
else
|
85
|
+
JoinDependency.new(@scope, associations).constraints
|
86
|
+
end
|
65
87
|
end
|
66
88
|
|
67
89
|
private
|
68
90
|
|
69
|
-
def props
|
70
|
-
@props ||= { table: @scope.arel_table, join: Arel::Nodes::InnerJoin }
|
71
|
-
end
|
72
|
-
|
73
|
-
def spawn
|
74
|
-
Table.new(@scope).tap do |table|
|
75
|
-
table.props = props
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
91
|
def resolve(name)
|
80
92
|
if @scope.column_names.include?(name.to_s)
|
81
93
|
self[name]
|
data/lib/baby_squeel/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: baby_squeel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ray Zane
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-03-
|
11
|
+
date: 2016-03-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|