baby_squeel 0.2.0 → 0.2.1

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: 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