rebel 0.2.0 → 0.3.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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rebel/sql.rb +137 -37
  3. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: aa3b3e1d946d65b40349085c1f02503587f2f3fd
4
- data.tar.gz: e7923044d3c6f76a81eda0001941bb978adf85f5
3
+ metadata.gz: 10809e6c0a432430cd14bff789a33f4e931d8d19
4
+ data.tar.gz: f09ec1c343f3202fdec996cbea89cc8b5c88eccc
5
5
  SHA512:
6
- metadata.gz: 5992df606d5eba47645c9301729488d4114f1d4278542d7476521675aaed788427d7a6f4e9673a32bd88f1238a06ee3bfa7ea9f14d6136d7a49805846cae8516
7
- data.tar.gz: d44f06d4f085bee06d81b3db9a609a34dfdba2e6d191c003e316eca27bc154c8c7ffaa57c962f28b6e1ed46177ad04344fc5aa5cf72c5e6f2620849c7fc193b4
6
+ metadata.gz: bb6c20a31bac4c52a5b2dba793608c53544b5abe713540b733e614009747a4f7e216e6bf998aee9b56985d4becc7c3b9552f35f93241c9cd50b462696a2a8c5a
7
+ data.tar.gz: dac1d09cbbc44bc324441295848757be87f77b48e362eda69417d15c770e8ceb8dd9a359bead9072c2d2173cc0a7d45320da7cbc4cc9888c43013c7c0acebeef
@@ -51,6 +51,24 @@ module Rebel::SQL
51
51
  end
52
52
 
53
53
  class Raw < String
54
+ def wants_parens!
55
+ @wants_parens = true
56
+ self
57
+ end
58
+
59
+ def wants_parens?
60
+ @wants_parens = false unless instance_variable_defined?(:@wants_parens)
61
+ @wants_parens
62
+ end
63
+
64
+ def parens
65
+ Raw.new("(#{self})")
66
+ end
67
+
68
+ def parens?
69
+ wants_parens? ? parens : self
70
+ end
71
+
54
72
  def as(n)
55
73
  Raw.new(self + " AS #{Rebel::SQL.name(n)}")
56
74
  end
@@ -59,48 +77,117 @@ module Rebel::SQL
59
77
  n ? as(n) : self
60
78
  end
61
79
 
62
- def on(clause)
63
- Raw.new(self + " ON #{Rebel::SQL.and_clause(clause)}")
80
+ def on(*clause)
81
+ Raw.new(self + " ON #{Rebel::SQL.and_clause(*clause)}")
82
+ end
83
+
84
+ def on?(*clause)
85
+ clause.any? ? on(clause) : self
86
+ end
87
+
88
+ def and(*clause)
89
+ Raw.new("#{self.parens?} AND #{Rebel::SQL.and_clause(*clause)}")
64
90
  end
65
91
 
66
- def on?(clause)
67
- clause ? on(clause) : self
92
+ def or(*clause)
93
+ Raw.new("#{self} OR #{Rebel::SQL.and_clause(*clause)}").wants_parens!
94
+ end
95
+
96
+ def eq(n)
97
+ case n
98
+ when nil
99
+ Raw.new("#{self} IS NULL")
100
+ else
101
+ Raw.new("#{self} = #{Rebel::SQL.name_or_value(n)}")
102
+ end
103
+ end
104
+ alias == eq
105
+ alias is eq
106
+
107
+ def ne(n)
108
+ case n
109
+ when nil
110
+ Raw.new("#{self} IS NOT NULL")
111
+ else
112
+ Raw.new("#{self} != #{Rebel::SQL.name_or_value(n)}")
113
+ end
114
+ end
115
+ alias != ne
116
+
117
+ def lt(n)
118
+ Raw.new("#{self} < #{Rebel::SQL.name_or_value(n)}")
119
+ end
120
+ alias < lt
121
+
122
+ def gt(n)
123
+ Raw.new("#{self} > #{Rebel::SQL.name_or_value(n)}")
124
+ end
125
+ alias > gt
126
+
127
+ def le(n)
128
+ Raw.new("#{self} <= #{Rebel::SQL.name_or_value(n)}")
129
+ end
130
+ alias <= le
131
+
132
+ def ge(n)
133
+ Raw.new("#{self} >= #{Rebel::SQL.name_or_value(n)}")
134
+ end
135
+ alias >= ge
136
+
137
+ def in(*v)
138
+ Raw.new("#{self} IN (#{Rebel::SQL.values(*v)})")
68
139
  end
69
140
  end
70
141
 
142
+ @identifier_quote = '"'
143
+ @string_quote = "'"
144
+ @escaped_string_quote = "''"
145
+
71
146
  class << self
147
+ def identifier_quote=(str)
148
+ @identifier_quote = str
149
+ end
150
+
151
+ def string_quote=(str)
152
+ @string_quote = str
153
+ end
154
+
155
+ def escaped_string_quote=(str)
156
+ @escaped_string_quote = str
157
+ end
158
+
72
159
  def raw(str)
73
160
  Raw.new(str)
74
161
  end
75
162
 
76
163
  def create_table(table_name, desc)
77
164
  <<-SQL
78
- CREATE TABLE #{Rebel::SQL.name(table_name)} (
79
- #{Rebel::SQL.list(desc.map { |k, v| "#{Rebel::SQL.name(k)} #{v}" })}
165
+ CREATE TABLE #{name(table_name)} (
166
+ #{list(desc.map { |k, v| "#{name(k)} #{v}" })}
80
167
  );
81
168
  SQL
82
169
  end
83
170
 
84
171
  def drop_table(table_name)
85
172
  <<-SQL
86
- DROP TABLE #{Rebel::SQL.name(table_name)};
173
+ DROP TABLE #{name(table_name)};
87
174
  SQL
88
175
  end
89
176
 
90
177
  def select(*fields, from: nil, where: nil, inner: nil, left: nil, right: nil)
91
178
  <<-SQL
92
179
  SELECT #{names(*fields)} FROM #{name(from)}
93
- #{Rebel::SQL.inner?(inner)}
94
- #{Rebel::SQL.left?(left)}
95
- #{Rebel::SQL.right?(right)}
96
- #{Rebel::SQL.where?(where)};
180
+ #{inner?(inner)}
181
+ #{left?(left)}
182
+ #{right?(right)}
183
+ #{where?(where)};
97
184
  SQL
98
185
  end
99
186
 
100
187
  def insert_into(table_name, *rows)
101
188
  <<-SQL
102
- INSERT INTO #{Rebel::SQL.name(table_name)} (#{Rebel::SQL.names(*rows.first.keys)})
103
- VALUES #{Rebel::SQL.list(rows.map { |r| "(#{Rebel::SQL.values(*r.values)})" })};
189
+ INSERT INTO #{name(table_name)} (#{names(*rows.first.keys)})
190
+ VALUES #{list(rows.map { |r| "(#{values(*r.values)})" })};
104
191
  SQL
105
192
  end
106
193
 
@@ -108,33 +195,38 @@ module Rebel::SQL
108
195
  raise ArgumentError if set.nil?
109
196
 
110
197
  <<-SQL
111
- UPDATE #{Rebel::SQL.name(table_name)}
112
- SET #{Rebel::SQL.assign_clause(set)}
113
- #{Rebel::SQL.inner?(inner)}
114
- #{Rebel::SQL.left?(left)}
115
- #{Rebel::SQL.right?(right)}
116
- #{Rebel::SQL.where?(where)};
198
+ UPDATE #{name(table_name)}
199
+ SET #{assign_clause(set)}
200
+ #{inner?(inner)}
201
+ #{left?(left)}
202
+ #{right?(right)}
203
+ #{where?(where)};
117
204
  SQL
118
205
  end
119
206
 
120
207
  def delete_from(table_name, where: nil, inner: nil, left: nil, right: nil)
121
208
  <<-SQL
122
- DELETE FROM #{Rebel::SQL.name(table_name)}
123
- #{Rebel::SQL.inner?(inner)}
124
- #{Rebel::SQL.left?(left)}
125
- #{Rebel::SQL.right?(right)}
126
- #{Rebel::SQL.where?(where)};
209
+ DELETE FROM #{name(table_name)}
210
+ #{inner?(inner)}
211
+ #{left?(left)}
212
+ #{right?(right)}
213
+ #{where?(where)};
127
214
  SQL
128
215
  end
129
216
 
130
217
  def truncate(table_name)
131
218
  <<-SQL
132
- TRUNCATE #{Rebel::SQL.name(table_name)};
219
+ TRUNCATE #{name(table_name)};
133
220
  SQL
134
221
  end
135
222
 
136
223
  ## Functions
137
224
 
225
+ def function(name, *args)
226
+ raw("#{name}(#{names_or_values(*args)})")
227
+ end
228
+ alias fn function
229
+
138
230
  def count(*n)
139
231
  raw("COUNT(#{names(*n)})")
140
232
  end
@@ -165,7 +257,7 @@ module Rebel::SQL
165
257
  return name if name.is_a?(Raw)
166
258
  return raw('*') if name == '*'
167
259
 
168
- name.to_s.split('.').map { |e| "\"#{e}\"" }.join('.')
260
+ raw(name.to_s.split('.').map { |e| "#{@identifier_quote}#{e}#{@identifier_quote}" }.join('.'))
169
261
  end
170
262
 
171
263
  def names(*names)
@@ -176,11 +268,17 @@ module Rebel::SQL
176
268
  items.join(', ')
177
269
  end
178
270
 
271
+ def escape_str(str)
272
+ str.tr(@string_quote, @escaped_string_quote)
273
+ end
274
+
179
275
  def value(v)
180
276
  case v
181
277
  when Raw then v
182
- when String then raw "'#{v.tr("'", "''")}'"
278
+ when String then raw "'#{escape_str(v)}'"
183
279
  when Integer then raw v.to_s
280
+ when TrueClass, FalseClass then raw(v ? 'TRUE' : 'FALSE')
281
+ when Date, Time, DateTime then value(v.iso8601)
184
282
  when nil then raw 'NULL'
185
283
  else raise NotImplementedError, v.inspect
186
284
  end
@@ -194,6 +292,10 @@ module Rebel::SQL
194
292
  item.is_a?(Symbol) ? name(item) : value(item)
195
293
  end
196
294
 
295
+ def names_or_values(*items)
296
+ list(items.map { |v| name_or_value(v) })
297
+ end
298
+
197
299
  def equal(l, r)
198
300
  "#{name_or_value(l)} = #{name_or_value(r)}"
199
301
  end
@@ -205,28 +307,26 @@ module Rebel::SQL
205
307
  def clause_term(left, right)
206
308
  case right
207
309
  when Array
208
- "#{name(left)} IN (#{values(*right)})"
310
+ name(left).in(*right)
209
311
  else
210
- "#{name(left)} = #{name_or_value(right)}"
312
+ name(left).eq(name_or_value(right))
211
313
  end
212
314
  end
213
315
 
214
- def and_clause(clause)
215
- return clause if clause.is_a?(Raw) || clause.is_a?(String)
216
-
316
+ def and_clause(*clause)
217
317
  clause.map do |e|
218
318
  case e
319
+ when Hash then and_clause(*e.to_a)
219
320
  when Array then clause_term(e[0], e[1])
220
- when Raw, String then e
321
+ when Raw then e.parens?
322
+ when String then e
221
323
  else raise NotImplementedError, e.class
222
324
  end
223
325
  end.join(' AND ')
224
326
  end
225
327
 
226
- def where?(clause)
227
- return "WHERE #{clause}" if clause.is_a?(Raw) || clause.is_a?(String)
228
-
229
- clause && clause.any? ? "WHERE #{Rebel::SQL.and_clause(clause)}" : nil
328
+ def where?(*clause)
329
+ clause.any? ? "WHERE #{and_clause(*clause)}" : nil
230
330
  end
231
331
 
232
332
  def inner?(join)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rebel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Loic Nageleisen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-01 00:00:00.000000000 Z
11
+ date: 2017-03-06 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: SQL-flavoured Ruby, or is it the other way around?
14
14
  email: loic.nageleisen@gmail.com
@@ -38,7 +38,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
38
38
  version: '0'
39
39
  requirements: []
40
40
  rubyforge_project:
41
- rubygems_version: 2.6.10
41
+ rubygems_version: 2.5.2
42
42
  signing_key:
43
43
  specification_version: 4
44
44
  summary: Fight against the Object tyranny