baby_squeel 0.2.0 → 0.2.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3569d1726ce4c979428cbc2fed31fe8103f16405
4
- data.tar.gz: 7d60acb4736d2a7cdda1e921bcb32ac1b8597601
3
+ metadata.gz: 630e302720d471b1ea0e6f618ef01e8592c0b9ab
4
+ data.tar.gz: 621e74ac8ad305e143e856e1cee8a8c023b3ac9c
5
5
  SHA512:
6
- metadata.gz: 81b72fb9e8b0f80dc8a0c5e52b215ed89e8f8801407ec2a60747f06171f35b9e6f8d0970c7009573092b17eaaa67ea8fabfa8dcf542b1aa0396b777df966bd4a
7
- data.tar.gz: fdcbff4355e934d51d6f6e57e19fdbda28a93eac0acb3ea91b4fc1d1d7c9ed84ae06c75dcb500a72325577374df38c0969ebef9dbee45b08a7cd0845de27c374
6
+ metadata.gz: c91ddbf39dc8e7a153f9be6df8197ac7223d91d4bf003eb55049bb3c0d9f671e7aa4a810ddb122973e609f70e302db90011b1f82a9794133cd1d2f4f688d8d6c
7
+ data.tar.gz: e71c24fb4bf300ae9806e4664e07c0e07e07cf74997f1259b2e6068fcb304f5d171bea6db2095d1e44a1329fe019f4a381be5e9686c6b9ec33d60b70b7787118
data/.travis.yml CHANGED
@@ -4,7 +4,6 @@ rvm:
4
4
  - 2.2.4
5
5
 
6
6
  before_install: gem install bundler -v 1.11.2
7
- before_script: bundle exec rubocop
8
7
  after_script: bundle exec rake coveralls:push
9
8
 
10
9
  env:
data/Gemfile CHANGED
@@ -15,4 +15,3 @@ group :test do
15
15
  gem 'simplecov'
16
16
  end
17
17
 
18
- gem 'rubocop', require: false
data/README.md CHANGED
@@ -4,13 +4,13 @@
4
4
  [![Code Climate](https://codeclimate.com/github/rzane/baby_squeel/badges/gpa.svg)](https://codeclimate.com/github/rzane/baby_squeel)
5
5
  [![Coverage Status](https://coveralls.io/repos/github/rzane/baby_squeel/badge.svg?branch=master)](https://coveralls.io/github/rzane/baby_squeel?branch=master)
6
6
 
7
- ![biddy piggy](http://static.thefrisky.com/uploads/2010/07/01/pig_in_boots_070110_m.jpg)
7
+ <img align="right" src="http://static.thefrisky.com/uploads/2010/07/01/pig_in_boots_070110_m.jpg" alt="biddy piggy">
8
8
 
9
9
  Have you ever used the [squeel](https://github.com/activerecord-hackery/squeel) gem? It's a really nice way to build complex queries. However, squeel monkeypatches ActiveRecord internals, so it has a tendency to break every time a new ActiveRecord version comes out.
10
10
 
11
- For me, that's a deal breaker. BabySqueel provides a query DSL for ActiveRecord without all of the evil :heart:.
11
+ For me, that's a deal breaker. BabySqueel provides a query DSL for ActiveRecord without all of the evil. :heart:
12
12
 
13
- It's also suprisingly uncomplicated. It's really just a layer of sugar on top of Arel.
13
+ It's really just a layer of sugar on top of Arel.
14
14
 
15
15
  ## Installation
16
16
 
@@ -30,54 +30,58 @@ Or install it yourself as:
30
30
 
31
31
  ## Usage
32
32
 
33
- Okay, so we have a `Post` model:
33
+ Okay, so we have some models:
34
34
 
35
35
  ```ruby
36
36
  class Post < ActiveRecord::Base
37
37
  belongs_to :author
38
+ has_many :comments
39
+ end
40
+
41
+ class Author < ActiveRecord::Base
42
+ has_many :posts
43
+ has_many :comments, through: :posts
44
+ end
45
+
46
+ class Comment < ActiveRecord::Base
47
+ belongs_to :post
38
48
  end
39
49
  ```
40
50
 
41
- #### Selects
51
+ ##### Selects
42
52
 
43
53
  ```ruby
44
54
  Post.selecting { (id + 5).as('id_plus_five') }
45
- # SELECT "posts"."id" + 5 AS id_plus_five FROM "posts"
55
+ # SELECT ("posts"."id" + 5) AS id_plus_five FROM "posts"
46
56
 
47
57
  Post.selecting { id.sum }
48
58
  # SELECT SUM("posts"."id") FROM "posts"
49
59
 
50
60
  Post.joins(:author).selecting { [id, author.id] }
51
- # SELECT "posts"."id", "author"."id"
52
- # FROM "posts"
53
- # INNER JOIN "authors" ON "posts"."author_id" = "authors"."id"
61
+ # SELECT "posts"."id", "authors"."id" FROM "posts"
62
+ # INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
54
63
  ```
55
64
 
56
- #### Wheres
65
+ ##### Wheres
57
66
 
58
67
  ```ruby
59
68
  Post.where.has { title == 'My Post' }
60
- # SELECT "posts".* FROM "posts" WHERE "posts"."title" = 'My Post'
69
+ # SELECT "posts".* FROM "posts"
70
+ # WHERE "posts"."title" = 'My Post'
61
71
 
62
72
  Post.where.has { title =~ 'My P%' }
63
- # SELECT "posts".* FROM "posts" WHERE "posts"."title" LIKE 'My P%'
73
+ # SELECT "posts".* FROM "posts"
74
+ # WHERE ("posts"."title" LIKE 'My P%')
64
75
 
65
76
  Author.where.has { (name =~ 'Ray%') & (id < 5) | (name.lower =~ 'zane%') & (id > 100) }
66
77
  # SELECT "authors".* FROM "authors"
67
- # WHERE (
68
- # "authors"."name" LIKE 'Ray%' AND "authors"."id" < 5 OR
69
- # LOWER("authors"."name") LIKE 'zane%' AND "authors"."id" > 100
70
- # )
78
+ # WHERE ("authors"."name" LIKE 'Ray%' AND "authors"."id" < 5 OR LOWER("authors"."name") LIKE 'zane%' AND "authors"."id" > 100)
71
79
 
72
80
  Post.joins(:author).where.has { author.name == 'Ray' }
73
81
  # SELECT "posts".* FROM "posts"
74
82
  # INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
75
83
  # WHERE "authors"."name" = 'Ray'
76
- ```
77
-
78
- Here's the best part. Where conditions will always reference the correct table alias for a given association:
79
84
 
80
- ```ruby
81
85
  Post.joins(author: :posts).where.has { author.posts.title =~ '%fun%' }
82
86
  # SELECT "posts".* FROM "posts"
83
87
  # INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
@@ -85,18 +89,20 @@ Post.joins(author: :posts).where.has { author.posts.title =~ '%fun%' }
85
89
  # WHERE ("posts_authors"."title" LIKE '%fun%')
86
90
  ```
87
91
 
88
- #### Orders
92
+ ##### Orders
89
93
 
90
94
  ```ruby
91
95
  Post.ordering { [id.desc, title.asc] }
92
- # SELECT "posts".* FROM "posts" ORDER BY "posts"."id" DESC, "posts"."title" ASC
96
+ # SELECT "posts".* FROM "posts"
97
+ # ORDER BY "posts"."id" DESC, "posts"."title" ASC
93
98
 
94
99
  Post.ordering { (id * 5).desc }
95
- # SELECT "posts".* FROM "posts" ORDER BY "posts"."id" * 5 DESC
100
+ # SELECT "posts".* FROM "posts"
101
+ # ORDER BY "posts"."id" * 5 DESC
96
102
 
97
103
  Post.select(:author_id).group(:author_id).ordering { id.count.desc }
98
- # SELECT "posts"."author_id"
99
- # FROM "posts" GROUP BY "posts"."author_id"
104
+ # SELECT "posts"."author_id" FROM "posts"
105
+ # GROUP BY "posts"."author_id"
100
106
  # ORDER BY COUNT("posts"."id") DESC
101
107
 
102
108
  Post.joins(:author).ordering { author.id.desc }
@@ -105,8 +111,7 @@ Post.joins(:author).ordering { author.id.desc }
105
111
  # ORDER BY "authors"."id" DESC
106
112
  ```
107
113
 
108
-
109
- #### Joins
114
+ ##### Joins
110
115
 
111
116
  ```ruby
112
117
  Post.joining { author }
@@ -121,17 +126,20 @@ Post.joining { [author.outer, comments] }
121
126
  Post.joining { author.comments }
122
127
  # SELECT "posts".* FROM "posts"
123
128
  # INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
124
- # INNER JOIN "comments" ON "comments"."author_id" = "authors"."id"
129
+ # INNER JOIN "posts" "posts_authors_join" ON "posts_authors_join"."author_id" = "authors"."id"
130
+ # INNER JOIN "comments" ON "comments"."post_id" = "posts_authors_join"."id"
125
131
 
126
132
  Post.joining { author.outer.comments.outer }
127
133
  # 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"
134
+ # LEFT OUTER JOIN "authors" ON "authors"."id" = "posts"."author_id"
135
+ # LEFT OUTER JOIN "posts" "posts_authors_join" ON "posts_authors_join"."author_id" = "authors"."id"
136
+ # LEFT OUTER JOIN "comments" ON "comments"."post_id" = "posts_authors_join"."id"
130
137
 
131
138
  Post.joining { author.comments.outer }
132
139
  # SELECT "posts".* FROM "posts"
133
140
  # INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
134
- # LEFT OUTER JOIN "comments" ON "comments"."author_id" = "authors"."id"
141
+ # LEFT OUTER JOIN "posts" "posts_authors_join" ON "posts_authors_join"."author_id" = "authors"."id"
142
+ # LEFT OUTER JOIN "comments" ON "comments"."post_id" = "posts_authors_join"."id"
135
143
 
136
144
  Post.joining { author.outer.posts }
137
145
  # SELECT "posts".* FROM "posts"
@@ -140,19 +148,30 @@ Post.joining { author.outer.posts }
140
148
 
141
149
  Post.joining { author.alias('a').on((author.id == author_id) | (author.name == title)) }
142
150
  # SELECT "posts".* FROM "posts"
143
- # INNER JOIN "authors" "a" ON (
144
- # "authors"."id" = "posts"."author_id" OR
145
- # "authors"."name" = "posts"."title"
146
- # )
151
+ # INNER JOIN "authors" "a" ON ("authors"."id" = "posts"."author_id" OR "authors"."name" = "posts"."title")
147
152
  ```
148
153
 
149
- #### Functions
154
+ ##### Functions
150
155
 
151
156
  ```ruby
152
157
  Post.selecting { coalesce(author_id, 5).as('author_id_with_default') }
153
158
  # SELECT coalesce("posts"."author_id", 5) AS author_id_with_default FROM "posts"
154
159
  ```
155
160
 
161
+ ##### Subqueries
162
+
163
+ ```ruby
164
+ Post.joins(:author).where.has {
165
+ author.id.in Author.select(:id).where(name: 'Ray')
166
+ }
167
+ # SELECT "posts".* FROM "posts"
168
+ # INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
169
+ # WHERE "authors"."id" IN (
170
+ # SELECT "authors"."id" FROM "authors"
171
+ # WHERE "authors"."name" = 'Ray'
172
+ # )
173
+ ```
174
+
156
175
  ## Important Notes
157
176
 
158
177
  While inside one of BabySqueel's blocks, `self` will be something totally different. You won't have access to your instance variables or methods.
@@ -172,10 +191,6 @@ Post.where.has { |table| table.title == 'Test' }
172
191
 
173
192
  You can also run `bin/console` to open up a prompt where you'll have access to some models to experiment with.
174
193
 
175
- ## Todo
176
-
177
- + Subqueries
178
-
179
194
  ## Contributing
180
195
 
181
196
  Bug reports and pull requests are welcome on GitHub at https://github.com/rzane/baby_squeel.
data/Rakefile CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'yaml'
2
+ require 'open3'
2
3
  require 'bundler/gem_tasks'
3
4
  require 'rspec/core/rake_task'
4
5
  require 'coveralls/rake/task'
@@ -7,26 +8,33 @@ Coveralls::RakeTask.new
7
8
 
8
9
  RSpec::Core::RakeTask.new(:spec)
9
10
 
10
- def run_version(version, cmd)
11
- display = "AR=#{version} #{cmd}"
12
- puts display
13
-
11
+ def invoke(version, cmd)
14
12
  Bundler.with_clean_env do
15
- system({ 'AR' => version }, cmd)
13
+ system({ 'AR' => version, 'SKIPCOV' => '1' }, cmd)
14
+ end
15
+ end
16
+
17
+ desc 'Run against a specific ActiveRecord version'
18
+ task 'spec:version', [:version] do |_, args|
19
+ if args.version.nil? || args.version.empty?
20
+ abort 'No version given'
16
21
  end
17
22
 
18
- abort "\nFAILED: #{display}" unless $?.success?
23
+ FileUtils.rm_rf 'Gemfile.lock'
24
+ invoke args.version, 'bundle install --quiet'
25
+ invoke args.version, 'bundle exec rspec -f progress' if $?.success?
26
+ $stderr.puts "#{args.version} failed." unless $?.success?
19
27
  end
20
28
 
21
29
  desc 'Run against all ActiveRecord versions'
22
30
  task 'spec:matrix' do
23
31
  travis = YAML.load_file '.travis.yml'
32
+ spec_task = Rake::Task['spec:version']
24
33
 
25
- travis['env']['matrix'].reverse.each do |variable|
26
- version = variable[/\=(.+)$/, 1]
27
- rm_rf 'Gemfile.lock'
28
- run_version version, 'bundle install > /dev/null'
29
- run_version version, 'rake spec'
34
+ travis['env']['matrix'].each do |matrix|
35
+ spec_task.invoke matrix[/\=(.+)$/, 1]
36
+ spec_task.reenable
37
+ puts "\n\n"
30
38
  end
31
39
  end
32
40
 
@@ -60,6 +60,7 @@ module BabySqueel
60
60
  # include necessary/applicable modules.
61
61
  class Generic < Proxy
62
62
  extend Operators::ArelAliasing
63
+ include Arel::AliasPredication
63
64
  include Arel::OrderPredications
64
65
  include Operators::Comparison
65
66
  include Operators::Equality
@@ -75,6 +76,14 @@ module BabySqueel
75
76
  super(parent._table[name])
76
77
  end
77
78
 
79
+ def in(rel)
80
+ if rel.is_a? ::ActiveRecord::Relation
81
+ ::Arel::Nodes::In.new(self, Arel.sql(rel.to_sql))
82
+ else
83
+ super
84
+ end
85
+ end
86
+
78
87
  def _arel
79
88
  parent_arel = @parent._arel
80
89
 
@@ -1,3 +1,3 @@
1
1
  module BabySqueel
2
- VERSION = '0.2.0'.freeze
2
+ VERSION = '0.2.1'.freeze
3
3
  end
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.2.0
4
+ version: 0.2.1
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-25 00:00:00.000000000 Z
11
+ date: 2016-03-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -89,7 +89,6 @@ extra_rdoc_files: []
89
89
  files:
90
90
  - ".gitignore"
91
91
  - ".rspec"
92
- - ".rubocop.yml"
93
92
  - ".travis.yml"
94
93
  - Gemfile
95
94
  - LICENSE.txt
@@ -127,7 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
127
126
  version: '0'
128
127
  requirements: []
129
128
  rubyforge_project:
130
- rubygems_version: 2.4.8
129
+ rubygems_version: 2.5.1
131
130
  signing_key:
132
131
  specification_version: 4
133
132
  summary: A tiny squeel implementation without all of the evil.
data/.rubocop.yml DELETED
@@ -1,21 +0,0 @@
1
- Lint/AssignmentInCondition:
2
- Enabled: false
3
-
4
- Style/BlockDelimiters:
5
- Enabled: false
6
-
7
- Style/Documentation:
8
- Enabled: false
9
-
10
- Style/SpecialGlobalVars:
11
- Enabled: false
12
-
13
- Style/NilComparison:
14
- Exclude:
15
- - spec/**/*
16
-
17
- Metrics/LineLength:
18
- Max: 100
19
-
20
- Metrics/AbcSize:
21
- Enabled: false