mini_sql 1.4.0 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +6 -0
- data/README.md +29 -18
- data/lib/mini_sql/builder.rb +43 -26
- data/lib/mini_sql/connection.rb +8 -0
- data/lib/mini_sql/mysql/connection.rb +1 -8
- data/lib/mini_sql/postgres/connection.rb +1 -8
- data/lib/mini_sql/postgres_jdbc/connection.rb +1 -8
- data/lib/mini_sql/sqlite/connection.rb +8 -10
- data/lib/mini_sql/sqlite/prepared_connection.rb +1 -1
- data/lib/mini_sql/version.rb +1 -1
- data/mini_sql.gemspec +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 491de0ce7925ad9ec428409af4a78e5ce3f91b6f886bfcca7c17544a4b44e23a
|
4
|
+
data.tar.gz: 2269da4aa96ec6d58c2141b82cae6d3764664e312ada254fe7f45476e6cb5b55
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dddf4370cdff6041fc2a0ceb338aa387ddcca76b65e135838cd0c3a1bfcf0bd0fcae37ea7504052b89b505b8c5478fb6d11e260e2349e25131b01853d42eae2d
|
7
|
+
data.tar.gz: 8d2f7087f39d05a4e8ccf72e675a07a38d9f371bdcfef33d96589a085f13abef53feb6986668fb12c75886ff9db301c0b7753b36e72177ef33944f08ce347734
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
2023-08-16 - 1.5.0
|
2
|
+
|
3
|
+
- FEATURE: add to_sql for easy conversion of builder to sql
|
4
|
+
- FEATURE: improve active record compat
|
5
|
+
- FEATURE: change builder to use gsub vs sub, which allows repeat clauses
|
6
|
+
|
1
7
|
2022-03-07 - 1.4.0
|
2
8
|
|
3
9
|
- PERF: Optimize multiple use param in prepared postgres sql
|
data/README.md
CHANGED
@@ -77,23 +77,34 @@ builder.query.each do |t|
|
|
77
77
|
end
|
78
78
|
```
|
79
79
|
|
80
|
+
The same builder's statement may occur multiple times.
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
builder = conn.build('(/*select*/ from books) union (/*select*/ from movies)').select('title').query
|
84
|
+
|
85
|
+
# => (SELECT title from books) union (SELECT title from movies)
|
86
|
+
```
|
87
|
+
|
80
88
|
The builder predefined next _SQL Literals_
|
81
89
|
|
82
|
-
| Method
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
90
|
+
| Method | SQL Literal |
|
91
|
+
|-------------|--------------|
|
92
|
+
| `select` | `/*select*/` |
|
93
|
+
| `count` | `/*select*/` |
|
94
|
+
| `where` | `/*where*/` |
|
95
|
+
| `where_or` | `/*where*/` |
|
96
|
+
| `where2` | `/*where2*/` |
|
97
|
+
| `where2_or` | `/*where2*/` |
|
98
|
+
| `join` | `/*join*/` |
|
99
|
+
| `left_join` | `/*left_join*/` |
|
100
|
+
| `group_by` | `/*group_by*/` |
|
101
|
+
| `order_by` | `/*order_by*/` |
|
102
|
+
| `limit` | `/*limit*/` |
|
103
|
+
| `offset` | `/*offset*/` |
|
104
|
+
| `set` | `/*set*/` |
|
94
105
|
|
95
106
|
### Custom SQL Literals
|
96
|
-
Use `sql_literal`
|
107
|
+
Use `sql_literal` to inject SQL into Builder from `String`, `Builder`, `ActiveRecord::Relation`, or any object that implements `to_sql` method.
|
97
108
|
|
98
109
|
```ruby
|
99
110
|
user_builder = conn
|
@@ -101,9 +112,9 @@ user_builder = conn
|
|
101
112
|
.where('type = ?', input_type)
|
102
113
|
.group_by("date_trunc('day', created_at)")
|
103
114
|
|
104
|
-
|
105
|
-
.
|
106
|
-
.where(
|
115
|
+
guest_relation = GuestTopic
|
116
|
+
.select("date_trunc('day', created_at) day, count(*)")
|
117
|
+
.where(state: input_state)
|
107
118
|
.group_by("date_trunc('day', created_at)")
|
108
119
|
|
109
120
|
conn
|
@@ -113,8 +124,8 @@ conn
|
|
113
124
|
from u
|
114
125
|
/*custom_join*/
|
115
126
|
SQL
|
116
|
-
.sql_literal(user: user_builder, guest:
|
117
|
-
.sql_literal(custom_join: "#{input_cond ? 'FULL' : 'LEFT'} JOIN g on g.day = u.day") # or
|
127
|
+
.sql_literal(user: user_builder, guest: guest_relation) # Builder and ActiveRecord::Relation
|
128
|
+
.sql_literal(custom_join: "#{input_cond ? 'FULL' : 'LEFT'} JOIN g on g.day = u.day") # or String
|
118
129
|
.query
|
119
130
|
```
|
120
131
|
|
data/lib/mini_sql/builder.rb
CHANGED
@@ -11,8 +11,13 @@ class MiniSql::Builder
|
|
11
11
|
@is_prepared = false
|
12
12
|
end
|
13
13
|
|
14
|
+
def initialize_copy(_original_builder)
|
15
|
+
@args = @args.transform_values { |v| v.dup }
|
16
|
+
@sections = @sections.transform_values { |v| v.dup }
|
17
|
+
end
|
18
|
+
|
14
19
|
literals1 =
|
15
|
-
[:set, :where2, :where, :order_by, :left_join, :join, :select, :group_by].each do |k|
|
20
|
+
[:set, :where2, :where2_or, :where, :where_or, :order_by, :left_join, :join, :select, :group_by].each do |k|
|
16
21
|
define_method k do |sql_part, *args|
|
17
22
|
if Hash === args[0]
|
18
23
|
@args.merge!(args[0])
|
@@ -48,7 +53,7 @@ class MiniSql::Builder
|
|
48
53
|
if PREDEFINED_SQL_LITERALS.include?(name)
|
49
54
|
raise "/*#{name}*/ is predefined, use method `.#{name}` instead `sql_literal`"
|
50
55
|
end
|
51
|
-
@sections[name] = part_sql.
|
56
|
+
@sections[name] = part_sql.respond_to?(:to_sql) ? part_sql.to_sql : part_sql
|
52
57
|
end
|
53
58
|
self
|
54
59
|
end
|
@@ -75,6 +80,10 @@ class MiniSql::Builder
|
|
75
80
|
@connection.param_encoder.encode(parametrized_sql, union_parameters(hash_args))
|
76
81
|
end
|
77
82
|
|
83
|
+
def count(field = '*')
|
84
|
+
dup.select("count(#{field})").query_single.first
|
85
|
+
end
|
86
|
+
|
78
87
|
private def connection_switcher
|
79
88
|
if @is_prepared
|
80
89
|
@connection.prepared
|
@@ -83,35 +92,43 @@ class MiniSql::Builder
|
|
83
92
|
end
|
84
93
|
end
|
85
94
|
|
95
|
+
WHERE_SECTIONS = [%i[where where_or], %i[where2 where2_or]]
|
86
96
|
private def parametrized_sql
|
87
97
|
sql = @sql.dup
|
88
98
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
joined = (+"SELECT ") << v.join(" , ")
|
94
|
-
when :where, :where2
|
95
|
-
joined = (+"WHERE ") << v.map { |c| (+"(") << c << ")" }.join(" AND ")
|
96
|
-
when :join
|
97
|
-
joined = v.map { |item| (+"JOIN ") << item }.join("\n")
|
98
|
-
when :left_join
|
99
|
-
joined = v.map { |item| (+"LEFT JOIN ") << item }.join("\n")
|
100
|
-
when :limit
|
101
|
-
joined = (+"LIMIT :mq_auto_limit")
|
102
|
-
when :offset
|
103
|
-
joined = (+"OFFSET :mq_auto_offset")
|
104
|
-
when :order_by
|
105
|
-
joined = (+"ORDER BY ") << v.join(" , ")
|
106
|
-
when :group_by
|
107
|
-
joined = (+"GROUP BY ") << v.join(" , ")
|
108
|
-
when :set
|
109
|
-
joined = (+"SET ") << v.join(" , ")
|
110
|
-
else # for sql_literal
|
111
|
-
joined = v
|
99
|
+
WHERE_SECTIONS.each do |section_and, section_or|
|
100
|
+
if (or_values = @sections.delete(section_or))
|
101
|
+
@sections[section_and] ||= []
|
102
|
+
@sections[section_and] << or_values.map { |c| "(#{c})" }.join(" OR ")
|
112
103
|
end
|
104
|
+
end
|
105
|
+
|
106
|
+
@sections.each do |k, v|
|
107
|
+
joined =
|
108
|
+
case k
|
109
|
+
when :select
|
110
|
+
"SELECT #{v.join(" , ")}"
|
111
|
+
when :where, :where2
|
112
|
+
"WHERE #{v.map { |c| "(#{c})" }.join(" AND ")}"
|
113
|
+
when :join
|
114
|
+
v.map { |item| "JOIN #{item}" }.join("\n")
|
115
|
+
when :left_join
|
116
|
+
v.map { |item| "LEFT JOIN #{item}" }.join("\n")
|
117
|
+
when :limit
|
118
|
+
"LIMIT :mq_auto_limit"
|
119
|
+
when :offset
|
120
|
+
"OFFSET :mq_auto_offset"
|
121
|
+
when :order_by
|
122
|
+
"ORDER BY #{v.join(" , ")}"
|
123
|
+
when :group_by
|
124
|
+
"GROUP BY #{v.join(" , ")}"
|
125
|
+
when :set
|
126
|
+
"SET #{v.join(" , ")}"
|
127
|
+
else # for sql_literal
|
128
|
+
v
|
129
|
+
end
|
113
130
|
|
114
|
-
unless sql.
|
131
|
+
unless sql.gsub!("/*#{k}*/", joined)
|
115
132
|
raise "The section for the /*#{k}*/ clause was not found!"
|
116
133
|
end
|
117
134
|
end
|
data/lib/mini_sql/connection.rb
CHANGED
@@ -57,6 +57,14 @@ module MiniSql
|
|
57
57
|
Builder.new(self, sql)
|
58
58
|
end
|
59
59
|
|
60
|
+
def to_sql(sql, *params)
|
61
|
+
if params.empty?
|
62
|
+
sql
|
63
|
+
else
|
64
|
+
param_encoder.encode(sql, *params)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
60
68
|
def escape_string(str)
|
61
69
|
raise NotImplementedError, "must be implemented by child connection"
|
62
70
|
end
|
@@ -51,18 +51,11 @@ module MiniSql
|
|
51
51
|
raw_connection.escape(str)
|
52
52
|
end
|
53
53
|
|
54
|
-
def build(sql)
|
55
|
-
Builder.new(self, sql)
|
56
|
-
end
|
57
|
-
|
58
54
|
private
|
59
55
|
|
60
56
|
def run(sql, as, params)
|
61
|
-
if params && params.length > 0
|
62
|
-
sql = param_encoder.encode(sql, *params)
|
63
|
-
end
|
64
57
|
raw_connection.query(
|
65
|
-
sql,
|
58
|
+
to_sql(sql, *params),
|
66
59
|
as: as,
|
67
60
|
database_timezone: :utc,
|
68
61
|
application_timezone: :utc,
|
@@ -192,10 +192,6 @@ module MiniSql
|
|
192
192
|
result.clear if result
|
193
193
|
end
|
194
194
|
|
195
|
-
def build(sql)
|
196
|
-
Builder.new(self, sql)
|
197
|
-
end
|
198
|
-
|
199
195
|
def escape_string(str)
|
200
196
|
raw_connection.escape_string(str)
|
201
197
|
end
|
@@ -203,10 +199,7 @@ module MiniSql
|
|
203
199
|
private
|
204
200
|
|
205
201
|
def run(sql, params)
|
206
|
-
|
207
|
-
sql = param_encoder.encode(sql, *params)
|
208
|
-
end
|
209
|
-
raw_connection.async_exec(sql)
|
202
|
+
raw_connection.async_exec(to_sql(sql, *params))
|
210
203
|
end
|
211
204
|
|
212
205
|
end
|
@@ -78,10 +78,6 @@ module MiniSql
|
|
78
78
|
run(sql, params).to_a
|
79
79
|
end
|
80
80
|
|
81
|
-
def build(sql)
|
82
|
-
Builder.new(self, sql)
|
83
|
-
end
|
84
|
-
|
85
81
|
def escape_string(str)
|
86
82
|
raw_connection.escape_string(str)
|
87
83
|
end
|
@@ -89,12 +85,9 @@ module MiniSql
|
|
89
85
|
private
|
90
86
|
|
91
87
|
def run(sql, params)
|
92
|
-
if params && params.length > 0
|
93
|
-
sql = param_encoder.encode(sql, *params)
|
94
|
-
end
|
95
88
|
conn = raw_connection
|
96
89
|
conn.typemap = self.class.typemap
|
97
|
-
conn.execute(sql)
|
90
|
+
conn.execute(to_sql(sql, *params))
|
98
91
|
ensure
|
99
92
|
# Force unsetting of typemap since we don't want mixed AR usage to continue to use these extra converters.
|
100
93
|
conn.typemap = nil
|
@@ -21,12 +21,12 @@ module MiniSql
|
|
21
21
|
|
22
22
|
def query_single(sql, *params)
|
23
23
|
# a bit lazy can be optimized
|
24
|
-
run(sql,
|
24
|
+
run(sql, params).flatten!
|
25
25
|
end
|
26
26
|
|
27
27
|
def query_hash(sql, *params)
|
28
28
|
r = []
|
29
|
-
run(sql,
|
29
|
+
run(sql, params) do |set|
|
30
30
|
set.each_hash do |h|
|
31
31
|
r << h
|
32
32
|
end
|
@@ -35,14 +35,14 @@ module MiniSql
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def query_array(sql, *params)
|
38
|
-
run(sql,
|
38
|
+
run(sql, params)
|
39
39
|
end
|
40
40
|
|
41
41
|
def exec(sql, *params)
|
42
42
|
|
43
43
|
start = raw_connection.total_changes
|
44
44
|
|
45
|
-
r = run(sql,
|
45
|
+
r = run(sql, params)
|
46
46
|
# this is not safe for multithreading, also for DELETE from TABLE will return
|
47
47
|
# incorrect data
|
48
48
|
if r.length > 0
|
@@ -53,13 +53,13 @@ module MiniSql
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def query(sql, *params)
|
56
|
-
run(sql,
|
56
|
+
run(sql, params) do |set|
|
57
57
|
deserializer_cache.materialize(set)
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
61
|
def query_decorator(decorator, sql, *params)
|
62
|
-
run(sql,
|
62
|
+
run(sql, params) do |set|
|
63
63
|
deserializer_cache.materialize(set, decorator)
|
64
64
|
end
|
65
65
|
end
|
@@ -70,10 +70,8 @@ module MiniSql
|
|
70
70
|
|
71
71
|
private
|
72
72
|
|
73
|
-
def run(sql,
|
74
|
-
|
75
|
-
sql = param_encoder.encode(sql, *params)
|
76
|
-
end
|
73
|
+
def run(sql, params)
|
74
|
+
sql = to_sql(sql, *params)
|
77
75
|
if block_given?
|
78
76
|
stmt = SQLite3::Statement.new(raw_connection, sql)
|
79
77
|
result = yield stmt.execute
|
@@ -28,7 +28,7 @@ module MiniSql
|
|
28
28
|
end
|
29
29
|
|
30
30
|
private def run(sql, params)
|
31
|
-
prepared_sql, binds, _bind_names = @param_binder.bind(sql, params)
|
31
|
+
prepared_sql, binds, _bind_names = @param_binder.bind(sql, *params)
|
32
32
|
statement = @prepared_cache.prepare_statement(prepared_sql)
|
33
33
|
statement.bind_params(binds)
|
34
34
|
if block_given?
|
data/lib/mini_sql/version.rb
CHANGED
data/mini_sql.gemspec
CHANGED
@@ -47,7 +47,7 @@ Gem::Specification.new do |spec|
|
|
47
47
|
else
|
48
48
|
spec.add_development_dependency "pg", "> 1"
|
49
49
|
spec.add_development_dependency "mysql2"
|
50
|
-
spec.add_development_dependency "sqlite3", "~> 1.
|
50
|
+
spec.add_development_dependency "sqlite3", "~> 1.4.4"
|
51
51
|
spec.add_development_dependency "activerecord", "~> 7.0.0"
|
52
52
|
end
|
53
53
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mini_sql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam Saffron
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-08-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -170,14 +170,14 @@ dependencies:
|
|
170
170
|
requirements:
|
171
171
|
- - "~>"
|
172
172
|
- !ruby/object:Gem::Version
|
173
|
-
version:
|
173
|
+
version: 1.4.4
|
174
174
|
type: :development
|
175
175
|
prerelease: false
|
176
176
|
version_requirements: !ruby/object:Gem::Requirement
|
177
177
|
requirements:
|
178
178
|
- - "~>"
|
179
179
|
- !ruby/object:Gem::Version
|
180
|
-
version:
|
180
|
+
version: 1.4.4
|
181
181
|
- !ruby/object:Gem::Dependency
|
182
182
|
name: activerecord
|
183
183
|
requirement: !ruby/object:Gem::Requirement
|