sql-builder 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 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