sql-builder 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 16002ee092061ecac8b29f725d606e5617252dad607d138269a651dad5b21a3a
4
- data.tar.gz: bc9b44a28f909204e86bc6b8b208b8b48746423552e649ce21002e12f902bfd3
3
+ metadata.gz: 150ba78258f5b3cb152890b76982b01652a5a779bfd4aecfbb1591e0ab7820ad
4
+ data.tar.gz: 726c4b1b6b4d7a522d02848059285529c924ad6109b367bd2fe42cb77f97f26e
5
5
  SHA512:
6
- metadata.gz: eb95a8dddc6c56f9073bfd997e19e184c8c9c1f87992fae67bd9df6329db8af564beb5066e0ab5ecde9495c71da12c4dda3034fdaa3e5dc213cd922302c31dee
7
- data.tar.gz: 115738ea5dda02fe1ef57114ac3765e43b4b30d1e405b1eaee1d332192dd66e4d27a6bbf7262e0980b524dfd22c0077da95065dda009261fdcb5d194f87b138d
6
+ metadata.gz: d912e64843705a78564aed481d87f1dd00959cd80b33583f7cd7b9cdb12b4cf7bf0693d3f9041972a0e00deeb79037905fef68d733aac1e20958e67119c8aca5
7
+ data.tar.gz: 338b7ae715a9c01144a228d5e752db1007fb21504463b58ff69fc9a5201a2d032b317f817b236f628adad540cea113b3bfb3143086ee485bf91c90b1798cf741
data/README.md CHANGED
@@ -4,11 +4,13 @@ A simple SQL builder for generate SQL for non-ActiveRecord supports databases.
4
4
 
5
5
  [![Build Status](https://travis-ci.org/huacnlee/sql-builder.svg?branch=master)](https://travis-ci.org/huacnlee/sql-builder)
6
6
 
7
+ [中文说明](https://ruby-china.org/topics/39399)
8
+
7
9
  ## Features
8
10
 
9
- - Simple SQL generator with DSL.
10
- - Sanitize SQL by ActiveRecord methods, keep security.
11
- - Simple SQL geneate logic for keep support any SQL databases (MySQL, PostgreSQL, TiDB, Amazon Redshift...)
11
+ - ActiveRecord style DSL.
12
+ - [Sanitize](https://api.rubyonrails.org/classes/ActiveRecord/Sanitization/ClassMethods.html#method-i-sanitize_sql) SQL by ActiveRecord methods, keep security.
13
+ - Support any SQL databases (MySQL, PostgreSQL, TiDB, Amazon Redshift...)
12
14
 
13
15
  ## Installation
14
16
 
@@ -20,7 +22,9 @@ gem 'sql-builder'
20
22
 
21
23
  ## Usage
22
24
 
23
- ```rb
25
+ More API documents, please visit [rdoc.info/gems/sql-builder](https://rdoc.info/gems/sql-builder).
26
+
27
+ ```ruby
24
28
  SQLBuilder.new("SELECT * FROM users")
25
29
  .where("name = ?", "hello world")
26
30
  .where("status != ?", 1)
@@ -33,31 +37,51 @@ SQLBuilder.new("SELECT * FROM users")
33
37
  => "SELECT * FROM users WHERE name = 'hello world' AND status != 1 ORDER BY created_at desc, id asc LIMIT 20 OFFSET 0"
34
38
  ```
35
39
 
36
- More complext:
40
+ ### More complex case
37
41
 
38
- ```rb
42
+ ```ruby
39
43
  query = SQLBuilder.new("SELECT users.name, users.age, user_profiles.bio, user_profiles.avatar FROM users INNER JOIN user_profiles ON users.id = user_profiles.user_id")
44
+ ```
40
45
 
41
- # conditions by params
46
+ Add the conditions by request params:
47
+
48
+ ```ruby
42
49
  query.where("age >= ?", params[:age]) unless params[:age].blank?
43
50
  query.where("status = ?", params[:status]) unless params[:status].nil?
44
51
  if params[:created_at_from] && params[:created_at_to]
45
52
  query.where("created_at >= ? and created_at <= ?", params[:created_at_from], params[:created_at_to])
46
53
  end
47
54
  query.order("id desc").limit(100).to_sql
55
+ ```
56
+
57
+ Returns string SQL:
48
58
 
49
- => "SELECT users.name, users.age, user_profiles.bio, user_profiles.avatar FROM users INNER JOIN user_profiles ON users.id = user_profiles.user_id WHERE age >= 18 AND status = 3 AND created_at >= '2020-01-03 10:54:08 +0800' and created_at <= '2020-01-03 10:54:08 +0800' ORDER BY id desc LIMIT 100 OFFSET 0"
59
+ ```sql
60
+ SELECT users.name, users.age, user_profiles.bio, user_profiles.avatar FROM users
61
+ INNER JOIN user_profiles ON users.id = user_profiles.user_id
62
+ WHERE age >= 18 AND status = 3 AND created_at >= '2020-01-03 10:54:08 +0800' AND created_at <= '2020-01-03 10:54:08 +0800'
63
+ ORDER BY id desc LIMIT 100 OFFSET 0
50
64
  ```
51
65
 
52
- ## TODO
66
+ ### Group by, Having
67
+
68
+ ```rb
69
+ query = SQLBuilder.new("select user_id, name, count(ip) as ip_count from user_visits")
70
+ query.where("status = ?", 1).where("created_at > ?", params[:created_at])
71
+ query.group("user_id").group("name").having("count(ip) > 2")
72
+ query.to_sql
73
+ ```
53
74
 
54
- - [ ] where by or;
75
+ returns
55
76
 
56
- ## Development
77
+ ```sql
78
+ select user_id, name, count(ip) as ip_count from user_visits WHERE status = 1 AND status = 1 AND created_at > '2020-01-03 10:54:08 +0800' GROUP BY user_id, name HAVING count(ip) > 2"
79
+ ```
57
80
 
58
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
81
+ ## TODO
59
82
 
60
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
83
+ - [ ] `OR` conditions;
84
+ - [X] `Group By`, `Having`;
61
85
 
62
86
  ## License
63
87
 
@@ -1,33 +1,43 @@
1
+ require "active_record"
2
+
1
3
  # SQLBuilder write the complex SQL as DSL
4
+ # = Example:
2
5
  #
3
- # Example:
4
- #
5
- # query = SQLBuilder.new("SELECT * FROM users inner join ")
6
+ # query = SQLBuilder.new("SELECT * FROM users")
6
7
  # .where("name = ?", "hello world")
7
8
  # .where("status != ?", 1)
8
9
  # .order("created_at desc")
9
10
  # .order("id asc")
10
11
  # .page(1).per(20)
11
12
  # .to_sql
12
- require "active_record"
13
-
14
13
  class SQLBuilder
15
- attr_reader :sql, :conditions, :orders, :limit_options, :page_options
14
+ attr_reader :sql, :conditions, :havings, :orders, :groups, :limit_options, :page_options
16
15
  delegate :sanitize_sql, :sanitize_sql_for_order, to: ActiveRecord::Base
17
16
 
17
+ # Create a new SQLBuilder
18
+ #
19
+ # == Example
20
+ # query = SQLBuilder.new("SELECT users.*, user_profiles.avatar FROM users INNER JOIN user_profiles ON users.id = user_profiles.id")
21
+ # query.to_sql
22
+ # # => "SELECT users.*, user_profiles.avatar FROM users INNER JOIN user_profiles ON users.id = user_profiles.id"
23
+ #
18
24
  def initialize(sql = "")
19
25
  @sql = sql
20
26
  @conditions = []
21
27
  @orders = []
28
+ @groups = []
29
+ @havings = []
22
30
  @limit_options = {}
23
31
  @page_options = { per_page: 20 }
24
32
  end
25
33
 
26
34
  # Add `AND` condition
27
35
  #
28
- # query.where("name = ?", params[:name]).where("age >= ?", 18)
36
+ # query.where("name = ?", params[:name]).where("age >= ?", 18)
37
+ #
29
38
  # or
30
- # count_query.where(query)
39
+ #
40
+ # count_query.where(query)
31
41
  def where(*condition)
32
42
  case condition.first
33
43
  when SQLBuilder
@@ -42,16 +52,15 @@ class SQLBuilder
42
52
 
43
53
  # Order By
44
54
  #
45
- # query.order("name asc").order("created_at desc").to_sql
46
- # => "ORDER BY name asc, created_at desc"
55
+ # query.order("name asc").order("created_at desc").to_sql
56
+ # # => "ORDER BY name asc, created_at desc"
47
57
  def order(condition)
48
58
  orders << sanitize_sql_for_order(condition)
49
59
  self
50
60
  end
51
61
 
52
62
  # Offset
53
- #
54
- # query.offset(3).limit(10) => "LIMIT 10 OFFSET 3"
63
+ # See #limit
55
64
  def offset(offset)
56
65
  limit_options[:offset] = offset.to_i
57
66
  self
@@ -59,17 +68,54 @@ class SQLBuilder
59
68
 
60
69
  # Limit
61
70
  #
62
- # query.offset(3).limit(10) => "LIMIT 10 OFFSET 3"
71
+ # query.offset(3).limit(10).to_sql
72
+ # # => "LIMIT 10 OFFSET 3"
63
73
  def limit(limit)
64
74
  limit_options[:offset] ||= 0
65
75
  limit_options[:limit] = limit.to_i
66
76
  self
67
77
  end
68
78
 
79
+ # Group By
80
+ #
81
+ # Allows to specify a group attribute:
82
+ #
83
+ # query.group("name as new_name, age").to_sql
84
+ # # => "GROUP BY name as new_name, age"
85
+ #
86
+ # or
87
+ #
88
+ # query.group("name", "age").to_sql # => "GROUP BY name, age"
89
+ # query.group(:name, :age).to_sql # => "GROUP BY name, age"
90
+ # query.group(["name", "age"]).to_sql # => "GROUP BY name, age"
91
+ # query.group("name").group("age").to_sql # => "GROUP BY name, age"
92
+ #
93
+ def group(*args)
94
+ case args.first
95
+ when Array
96
+ @groups += args.first.collect(&:to_s)
97
+ else
98
+ @groups += args.collect(&:to_s)
99
+ end
100
+
101
+ @groups.uniq!
102
+ self
103
+ end
104
+
105
+ # Having
106
+ #
107
+ # query.group("name").having("count(name) > ?", 5).to_sql
108
+ # # => "GROUP BY name HAVING count(name) > 5"
109
+ #
110
+ def having(*condition)
111
+ havings << sanitize_sql(condition)
112
+ self
113
+ end
114
+
69
115
  # Pagination
70
116
  #
71
- # query.page(1).per(12) => "LIMIT 12 OFFSET 0"
72
- # query.page(2).per(12) => "LIMIT 12 OFFSET 12"
117
+ # query.page(1).per(12).to_sql # => "LIMIT 12 OFFSET 0"
118
+ # query.page(2).per(12).to_sql # => "LIMIT 12 OFFSET 12"
73
119
  def page(page_no)
74
120
  page_options[:page] = page_no
75
121
  page_options[:per_page] ||= 10
@@ -79,7 +125,8 @@ class SQLBuilder
79
125
  self
80
126
  end
81
127
 
82
- # See page
128
+ # Set per_page limit
129
+ # See #page
83
130
  def per(per_page)
84
131
  page_options[:per_page] = per_page
85
132
  self.page(page_options[:page])
@@ -95,6 +142,12 @@ class SQLBuilder
95
142
  if orders.any?
96
143
  sql_parts << "ORDER BY " + orders.join(", ")
97
144
  end
145
+ if groups.any?
146
+ sql_parts << "GROUP BY " + groups.join(", ")
147
+ end
148
+ if havings.any?
149
+ sql_parts << "HAVING " + havings.join(" AND ")
150
+ end
98
151
  if limit_options[:limit]
99
152
  sql_parts << "LIMIT " + limit_options[:limit].to_s
100
153
  end
@@ -103,4 +156,4 @@ class SQLBuilder
103
156
  end
104
157
  sql_parts.join(" ")
105
158
  end
106
- end
159
+ end
@@ -1,3 +1,3 @@
1
1
  class SQLBuilder
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sql-builder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Lee
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-03 00:00:00.000000000 Z
11
+ date: 2020-01-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord