baby_squeel 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|