lilit-sql 0.0.1 → 0.0.2

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/lilit_sql.rb +364 -224
  3. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8055fa9bdd9f4c7dd21d9e1036ca22ebd423637994ec0aeda7894062a8c3b2fa
4
- data.tar.gz: 2683c306cb68f4d0e7b2e17fd678e8951a67c92a28acdafc87ffbf0c2b466ba0
3
+ metadata.gz: 387d30110c85b2e4c85aef31d108675aaba18405d13f8b84984f3ce237a11caa
4
+ data.tar.gz: 342b105a73a26c3dc3507fddb2c3adccacc69ef23afea327a1f3fc9ba15c0671
5
5
  SHA512:
6
- metadata.gz: 67a42477621655368a38a0ef15c55af70046b859b69f7bddd780546debd7bb8b81267112896a358effb95ae0b5820ec73618bd8f074412b0f10ebda78ff177b4
7
- data.tar.gz: bab58672731d51626c65ee9855aa7fc7ba88c11bec2d917dbdfb6349923dc60424bbc9fee0e591e4b556224959a28315a0b259b68e956a5a51cab6899095b019
6
+ metadata.gz: f83a531e2aa9b9a1a03be86374555e21a1fff1115a06b36db492a3c56b3f2d398e91e8ea38b0bca0767b48b0861fe43cc5979f285bc52637cbccc218b09bd278
7
+ data.tar.gz: b2c571325ddc399f639c68b291f16df4db25cdadfa2d4320b2456f771aa2a9c4e8a4a95fb9b7d5a39858c27c715cb1e79e4f3721f32967acd426ded134464452
data/lib/lilit_sql.rb CHANGED
@@ -4,10 +4,146 @@ require 'ruby2ruby'
4
4
  require 'ruby_parser'
5
5
  require 'sourcify'
6
6
 
7
+ class Expr
8
+ def and(other)
9
+ BinaryOperation.new(self, :and, other)
10
+ end
11
+
12
+ def eq(other)
13
+ BinaryOperation.new(self, :'=', other)
14
+ end
15
+
16
+ def not
17
+ UnaryOperation.new(:not, self)
18
+ end
19
+
20
+ def minus
21
+ UnaryOperation.new(:-, self)
22
+ end
23
+
24
+ def plus
25
+ UnaryOperation.new(:+, self)
26
+ end
27
+
28
+ def ne(other)
29
+ BinaryOperation.new(self, :'!=', other)
30
+ end
31
+
32
+ def in(list)
33
+ BinaryOperation.new(self, :in, list)
34
+ end
35
+
36
+ def *(other)
37
+ BinaryOperation.new(self, :*, other)
38
+ end
39
+
40
+ def +(other)
41
+ BinaryOperation.new(self, :+, other)
42
+ end
43
+
44
+ def >=(other)
45
+ BinaryOperation.new(self, :'>=', other)
46
+ end
47
+
48
+ def <=(other)
49
+ BinaryOperation.new(self, :<=, other)
50
+ end
51
+
52
+ def >(other)
53
+ BinaryOperation.new(self, :'>', other)
54
+ end
55
+
56
+ def <(other)
57
+ BinaryOperation.new(self, :<, other)
58
+ end
59
+
60
+ def asc
61
+ OrderedByExpr.new(self, :asc)
62
+ end
63
+
64
+ def desc
65
+ OrderedByExpr.new(self, :desc)
66
+ end
67
+ end
68
+
69
+ class OrderedByExpr
70
+ attr_accessor :expr, :direction
71
+
72
+ def initialize(expr, direction = nil)
73
+ @expr = expr
74
+ @direction = direction
75
+ end
76
+
77
+ def sql
78
+ s = @expr.ref_sql
79
+
80
+ if @direction
81
+ s += " #{direction}"
82
+ end
83
+ end
84
+ end
85
+
86
+ class UnaryOperation < Expr
87
+ attr_accessor :op
88
+
89
+ def initialize(op, value)
90
+ @op = op
91
+ @value = value
92
+ end
93
+
94
+ def ref_sql
95
+ "#{@op} (#{@value.ref_sql})"
96
+ end
97
+
98
+ def ==(other)
99
+ other.class == self.class && other.state == state
100
+ end
101
+
102
+ def state
103
+ instance_variables.map { |variable| instance_variable_get variable }
104
+ end
105
+ end
106
+
107
+ class BinaryOperation < Expr
108
+ attr_accessor :left, :op, :right
109
+
110
+ def initialize(left, op, right)
111
+ @left = left
112
+ @op = op
113
+ @right = lit(right)
114
+ end
115
+
116
+ def ref_sql
117
+ if @right.is_a?(Literal) && @right.value.nil?
118
+ return (
119
+ if @op == :'='
120
+ "#{@left.ref_sql} is #{@right.ref_sql}"
121
+ elsif @op == :!=
122
+ "#{@left.ref_sql} is not #{@right.ref_sql}"
123
+ else
124
+ raise ArgumentError.new("Nil doesn't support the operator: #{@op}")
125
+ end
126
+ )
127
+ end
128
+
129
+ if @op == :in
130
+ return "#{@left.ref_sql} in (#{@right.map(&:ref_sql).join(', ')})"
131
+ end
132
+
133
+ "#{@left.ref_sql} #{@op} #{@right.ref_sql}"
134
+ end
135
+
136
+ def ==(other)
137
+ other.class == self.class && other.state == state
138
+ end
139
+
140
+ def state
141
+ instance_variables.map { |variable| instance_variable_get variable }
142
+ end
143
+ end
144
+
7
145
  class From
8
- attr_accessor :source
9
- attr_accessor :join_type
10
- attr_accessor :condition
146
+ attr_accessor :source, :join_type, :condition
11
147
 
12
148
  def initialize(source, join_type = nil, condition = nil, alias_name = nil)
13
149
  @source = source
@@ -16,9 +152,7 @@ class From
16
152
  @alias_name = alias_name
17
153
  end
18
154
 
19
- def alias_name=(value)
20
- @alias_name = value
21
- end
155
+ attr_writer :alias_name
22
156
 
23
157
  def raw_alias_name
24
158
  @alias_name
@@ -33,9 +167,26 @@ class From
33
167
  end
34
168
  end
35
169
 
170
+ class CrossJoinUnnest
171
+ attr_accessor :from, :row, :ordinality
172
+
173
+ def initialize(from, row, ordinality)
174
+ @from = from
175
+ @row = row
176
+ @ordinality = ordinality
177
+ end
178
+
179
+ def rows
180
+ [@row].map {|r| r.with_from(@from)}
181
+ end
182
+
183
+ def alias_name
184
+ @from.source.table_name
185
+ end
186
+ end
187
+
36
188
  class GroupBy
37
- attr_accessor :query
38
- attr_accessor :keys
189
+ attr_accessor :query, :keys
39
190
 
40
191
  def initialize(query, keys)
41
192
  @query = query
@@ -43,12 +194,13 @@ class GroupBy
43
194
  end
44
195
 
45
196
  def aggregate(&blk)
46
- result = blk.call(@keys, *@query.rows)
197
+ result = expr(&blk).call(@keys, *@query.rows)
47
198
 
48
199
  Query.new(
49
- @query.froms + [],
50
- @query.conditions + [],
200
+ @query.froms,
201
+ @query.conditions,
51
202
  @keys,
203
+ @query.order_bys,
52
204
  Row.new(result.class.members, result)
53
205
  )
54
206
  end
@@ -70,37 +222,44 @@ class Row
70
222
  end
71
223
 
72
224
  def col(name)
73
- found = @columns.select {|c| c.name == name}.first
225
+ found = @columns.select { |c| c.name == name }.first
74
226
 
75
- raise ArgumentError.new("#{name} is not found in the columns: #{@columns.map {|c|c.name}.inspect}") if found.nil?
227
+ raise ArgumentError, "#{name} is not found in the columns: #{@columns.map(&:name).inspect}" if found.nil?
76
228
 
77
229
  found
78
230
  end
79
231
 
80
232
  def with_from(from)
81
- Row.new(@columns.map {|c| c.with_from(from)})
82
- end
83
-
84
- private def method_missing(symbol, *args)
85
- begin
86
- col(symbol)
87
- rescue ArgumentError
88
- super
89
- end
233
+ Row.new(@columns.map { |c| c.with_from(from) })
90
234
  end
91
235
 
92
236
  def has?(name)
93
- @columns.any? {|c| c.name == name}
237
+ @columns.any? { |c| c.name == name }
94
238
  end
95
239
 
96
240
  def decl_sql
97
- @columns.map {|c|c.decl_sql}.join(', ')
241
+ @columns.map(&:decl_sql).join(', ')
242
+ end
243
+
244
+ private
245
+
246
+ def method_missing(symbol, *args)
247
+ col(symbol)
248
+ rescue ArgumentError
249
+ super
250
+ end
251
+
252
+ def respond_to_missing?(method_name, include_private = false)
253
+ !col(method_name).nil?
254
+ rescue ArgumentError
255
+ super
98
256
  end
99
257
  end
100
258
 
101
- class Column
102
- attr_accessor :name
103
- attr_accessor :origin
259
+
260
+
261
+ class Column < Expr
262
+ attr_accessor :name, :origin
104
263
 
105
264
  def initialize(name, origin = nil, from = nil)
106
265
  @name = name
@@ -112,22 +271,6 @@ class Column
112
271
  Column.new(@name, @origin, from)
113
272
  end
114
273
 
115
- def eq(other)
116
- Expr.new(self, :eq, other)
117
- end
118
-
119
- def in(list)
120
- Expr.new(self, :in, list)
121
- end
122
-
123
- def *(other)
124
- Expr.new(self, :*, other)
125
- end
126
-
127
- def <=(other)
128
- Expr.new(self, :<=, other)
129
- end
130
-
131
274
  def ref_sql
132
275
  "#{@from.alias_name}.#{@name}"
133
276
  end
@@ -140,25 +283,22 @@ class Column
140
283
  else
141
284
  origin.ref_sql
142
285
  end
143
- if origin_sql != @name.to_s
144
- s += "#{origin_sql} as "
145
- end
286
+ s += "#{origin_sql} as " if origin_sql != @name.to_s
146
287
  end
147
288
  s += @name.to_s
148
289
  s
149
290
  end
150
291
 
151
292
  def ==(other)
152
- other.class == self.class && other.state == self.state
293
+ other.class == self.class && other.state == state
153
294
  end
154
295
 
155
296
  def state
156
- self.instance_variables.map { |variable| self.instance_variable_get variable }
297
+ instance_variables.map { |variable| instance_variable_get variable }
157
298
  end
158
299
  end
159
300
 
160
301
  class Count < Column
161
-
162
302
  def initialize
163
303
  super(nil)
164
304
  end
@@ -168,12 +308,11 @@ class Count < Column
168
308
  end
169
309
 
170
310
  def decl_sql
171
- "count(*)"
311
+ 'count(*)'
172
312
  end
173
313
  end
174
314
 
175
315
  class Sum < Column
176
-
177
316
  def initialize(col)
178
317
  super(nil, col)
179
318
  end
@@ -197,7 +336,7 @@ module Aggregate
197
336
  end
198
337
  end
199
338
 
200
- class Literal
339
+ class Literal < Expr
201
340
  attr_accessor :value
202
341
 
203
342
  def initialize(value)
@@ -210,78 +349,39 @@ class Literal
210
349
 
211
350
  def decl_sql
212
351
  if @value.nil?
213
- "null"
352
+ 'null'
214
353
  elsif @value.is_a?(Integer) || @value.is_a?(Float)
215
- "#{@value}"
354
+ @value.to_s
216
355
  elsif @value.is_a?(String)
217
356
  "'#{@value}'"
218
357
  else
219
- raise NotImplementedError.new("Literal doesn't support render #{@value.class} (#{@value})")
358
+ raise NotImplementedError, "Literal doesn't support render #{@value.class} (#{@value})"
220
359
  end
221
360
  end
222
361
 
223
362
  def ==(other)
224
- other.class == self.class && other.state == self.state
363
+ other.class == self.class && other.state == state
225
364
  end
226
365
 
227
366
  def state
228
- self.instance_variables.map { |variable| self.instance_variable_get variable }
367
+ instance_variables.map { |variable| instance_variable_get variable }
229
368
  end
230
369
  end
231
370
 
232
- class Expr
233
- attr_accessor :left
234
- attr_accessor :op
235
- attr_accessor :right
236
-
237
- def initialize(left, op, right)
238
- @left = left
239
- @op = op
240
- @right = right
241
- end
371
+ def lit(value)
372
+ return value if value.is_a?(Literal)
242
373
 
243
- def and(other)
244
- Expr.new(self, :and, other)
245
- end
246
-
247
- def ref_sql
248
- if op == :and
249
- "#{left.ref_sql} and #{right.ref_sql}"
250
- elsif op == :eq
251
- if right.is_a?(Literal) && right.value.nil?
252
- "#{left.ref_sql} is #{right.ref_sql}"
253
- else
254
- "#{left.ref_sql} = #{right.ref_sql}"
255
- end
256
- elsif op == :ne
257
- if right.is_a?(Literal) && right.value.nil?
258
- "#{left.ref_sql} is not #{right.ref_sql}"
259
- else
260
- "#{left.ref_sql} != #{right.ref_sql}"
261
- end
262
- elsif op == :*
263
- "#{left.ref_sql} * #{right.ref_sql}"
264
- elsif op == :<=
265
- "#{left.ref_sql} <= #{right.ref_sql}"
266
- elsif op == :in
267
- "#{left.ref_sql} in (#{right.map {|r|r.ref_sql}.join(', ')})"
268
- else
269
- raise ArgumentError.new("#{op} is not supported by Expr")
270
- end
271
- end
272
-
273
- def ==(other)
274
- other.class == self.class && other.state == self.state
275
- end
276
-
277
- def state
278
- self.instance_variables.map { |variable| self.instance_variable_get variable }
374
+ if value.is_a?(String) || value.is_a?(Integer) || value.is_a?(Float) || value.nil?
375
+ Literal.new(value)
376
+ elsif value.is_a?(Array)
377
+ value.map { |v| lit(v) }
378
+ else
379
+ value
279
380
  end
280
381
  end
281
382
 
282
383
  class Table
283
- attr_accessor :table_name
284
- attr_accessor :rows
384
+ attr_accessor :table_name, :rows
285
385
 
286
386
  def initialize(struct, table_name)
287
387
  @table_name = table_name
@@ -294,16 +394,16 @@ class Table
294
394
  end
295
395
 
296
396
  class Query
297
- attr_accessor :froms
298
- attr_accessor :conditions
299
- attr_accessor :grouped_keys
300
- attr_accessor :row
397
+ attr_accessor :froms, :conditions, :grouped_keys, :order_bys, :row, :_limit, :_offset
301
398
 
302
- def initialize(froms, conditions = [], grouped_keys = [], row = nil)
399
+ def initialize(froms, conditions = [], grouped_keys = [], order_bys = [], row = nil, limit = nil, offset = nil)
303
400
  @froms = froms + []
304
401
  @conditions = conditions + []
305
402
  @grouped_keys = grouped_keys + []
403
+ @order_bys = order_bys + []
306
404
  @row = row
405
+ @_limit = limit
406
+ @_offset = offset
307
407
  @subquery_name = nil
308
408
  end
309
409
 
@@ -316,36 +416,65 @@ class Query
316
416
  end
317
417
 
318
418
  def map(&blk)
319
- if @row
320
- return Query.from(self).map(&blk)
321
- end
419
+ return Query.from(self).map(&blk) if @row
322
420
 
323
421
  result = expr(&blk).call(*get_from_rows)
324
422
  Query.new(
325
423
  @froms,
326
424
  @conditions,
327
425
  @grouped_keys,
328
- Row.new(result.class.members, result)
426
+ @order_bys,
427
+ Row.new(result.class.members, result),
428
+ @_limit,
429
+ @_offset
329
430
  )
330
431
  end
331
432
 
332
433
  def has?(column_name)
333
- rows.any? {|r| r.has?(column_name)}
434
+ rows.any? { |r| r.has?(column_name) }
334
435
  end
335
436
 
336
437
  def rows
337
- if @row
338
- return [@row]
339
- end
438
+ return [@row] if @row
340
439
 
341
440
  get_from_rows
342
441
  end
343
442
 
344
- def group_by(&blk)
345
- if @row
346
- return Query.from(self).group_by(&blk)
443
+ def order_by(&blk)
444
+ return Query.from(self).order_by(&blk) if @row
445
+
446
+ result = expr(&blk).call(*get_from_rows)
447
+
448
+ if result.is_a?(OrderedByExpr)
449
+ result = [result]
450
+ elsif result.is_a?(Expr)
451
+ result = OrderedByExpr.new(result)
347
452
  end
348
453
 
454
+ Query.new(
455
+ @froms,
456
+ @conditions,
457
+ @grouped_keys,
458
+ @order_bys + result,
459
+ @row,
460
+ @_limit,
461
+ @_offset
462
+ )
463
+ end
464
+
465
+ def limit(number)
466
+ @_limit = number
467
+ self
468
+ end
469
+
470
+ def offset(number)
471
+ @_offset = number
472
+ self
473
+ end
474
+
475
+ def group_by(&blk)
476
+ return Query.from(self).group_by(&blk) if @row
477
+
349
478
  result = expr(&blk).call(*get_from_rows)
350
479
 
351
480
  if result.is_a?(Column)
@@ -365,94 +494,125 @@ class Query
365
494
  perform_join(:left_join, other, &blk)
366
495
  end
367
496
 
497
+ def right_join(other, &blk)
498
+ perform_join(:right_join, other, &blk)
499
+ end
500
+
501
+ def cross_join(other)
502
+ perform_join(:cross_join, other)
503
+ end
504
+
505
+ def cross_join_unnest(ordinality = false, &blk)
506
+ return Query.from(self).cross_join_unnest(ordinality, &blk) if @row || @conditions.size.positive? || @order_bys.size.positive? || @_limit || @_offset
507
+
508
+ result = expr(&blk).call(*get_from_rows)
509
+ row = Row.new(result.class.members, result)
510
+ from = CrossJoinUnnest.new(From.new(Table.new(result.class, 't')), row, ordinality)
511
+ Query.new(
512
+ @froms + [from],
513
+ @conditions,
514
+ @grouped_keys,
515
+ )
516
+ end
517
+
368
518
  def where(&blk)
369
- if @row
370
- return Query.from(self).where(&blk)
371
- end
519
+ return Query.from(self).where(&blk) if @row
372
520
 
373
521
  condition = expr(&blk).call(*get_from_rows)
374
522
  Query.new(
375
523
  @froms,
376
524
  @conditions + [condition],
377
525
  @grouped_keys,
378
- @row
526
+ @order_bys,
527
+ @row,
528
+ @_limit,
529
+ @_offset
379
530
  )
380
531
  end
381
532
 
382
533
  def subquery_name
383
- if is_vanilla
384
- return @froms.first.source.subquery_name
385
- end
534
+ return @froms.first.source.subquery_name if is_vanilla
386
535
 
387
- if @subquery_name.nil?
388
- raise ArgumentError.new("The query #{self.inspect} doesn't have a subquery name")
389
- end
536
+ raise ArgumentError, "The query #{inspect} doesn't have a subquery name" if @subquery_name.nil?
390
537
 
391
538
  @subquery_name
392
539
  end
393
540
 
394
- def subquery_name=(value)
395
- @subquery_name = value
396
- end
541
+ attr_writer :subquery_name
397
542
 
398
543
  def sql
399
- s = "select "
400
- s += rows.map {|r| r.decl_sql}.join(', ')
401
- s += " from"
544
+ s = 'select '
545
+ s += rows.map(&:decl_sql).join(', ')
546
+ s += ' from'
402
547
 
403
548
  @froms.each_with_index do |from, index|
404
- if index >= 1
405
- if from.join_type == :join
406
- s += " join"
407
- elsif from.join_type == :left_join
408
- s += " left join"
409
- else
410
- raise ArgumentError.new("The join type #{from.join_type} is not supoprted.")
549
+ if from.is_a?(From)
550
+ if index >= 1
551
+ if from.join_type == :join
552
+ s += ' join'
553
+ elsif from.join_type == :left_join
554
+ s += ' left join'
555
+ elsif from.join_type == :right_join
556
+ s += ' right join'
557
+ elsif from.join_type == :cross_join
558
+ s += ' cross join'
559
+ else
560
+ raise ArgumentError, "The join type #{from.join_type} is not supoprted."
561
+ end
411
562
  end
412
- end
413
563
 
414
- s += " #{from.source.subquery_name}"
564
+ s += " #{from.source.subquery_name}"
415
565
 
416
- if from.source.subquery_name != from.alias_name
417
- s += " #{from.alias_name}"
418
- end
566
+ s += " #{from.alias_name}" if from.source.subquery_name != from.alias_name
419
567
 
420
- if from.condition
421
- s += " on #{from.condition.ref_sql}"
568
+ s += " on #{from.condition.ref_sql}" if from.condition
569
+ elsif from.is_a?(CrossJoinUnnest)
570
+ origins, cols = from.rows.first.columns.map {|c| [c.origin.ref_sql, c.name]}.transpose
571
+ s += " cross join unnest (#{origins.join(', ')})"
572
+ if from.ordinality
573
+ s += ' with ordinality'
574
+ cols.push('ordinal')
575
+ end
576
+ s += " as #{from.from.source.table_name} (#{cols.join(', ')})"
577
+ else
578
+ raise ArgumentError.new("From doesn't support #{from.inspect}")
422
579
  end
423
580
  end
424
581
 
425
- if @conditions.size > 0
426
- s += " where #{@conditions.map {|c| c.ref_sql}.join(' and ')}"
582
+ s += " where #{@conditions.map(&:ref_sql).join(' and ')}" if @conditions.size.positive?
583
+
584
+ s += " group by #{@grouped_keys.map(&:ref_sql).join(', ')}" if @grouped_keys.size.positive?
585
+
586
+ s += " order by #{@order_bys.map(&:sql).join(', ')}" if @order_bys.size.positive?
587
+
588
+ if @_offset
589
+ s += " offset #{@_offset}"
427
590
  end
428
591
 
429
- if @grouped_keys.size > 0
430
- s += " group by #{@grouped_keys.map {|k| k.ref_sql}.join(', ')}"
592
+ if @_limit
593
+ s += " limit #{@_limit}"
431
594
  end
432
595
 
433
596
  s
434
597
  end
435
598
 
436
599
  private
600
+
437
601
  def get_from_rows
438
- @froms.map {|f| f.rows.map {|r|r.with_from(f)}}.flatten
602
+ @froms.map { |f| f.rows.map { |r| r.with_from(f) } }.flatten
439
603
  end
440
604
 
441
605
  def get_next_alias
442
- alias_names = @froms.map {|f|f.raw_alias_name}.compact
606
+ alias_names = @froms.map(&:raw_alias_name).compact
443
607
  index = 0
444
608
  alias_names.sort.each do |name|
445
- if name == "alias#{index}"
446
- index += 1
447
- end
609
+ index += 1 if name == "alias#{index}"
448
610
  end
449
611
  "alias#{index}"
450
612
  end
451
613
 
452
614
  def perform_join(join_type, other, &blk)
453
- if @row || @conditions.size > 0
454
- return Query.from(self).send(:perform_join, join_type, other, &blk)
455
- end
615
+ return Query.from(self).send(:perform_join, join_type, other, &blk) if @row || @conditions.size.positive? || @order_bys.size.positive? || @_limit || @_offset
456
616
 
457
617
  alias_name = nil
458
618
  @froms.each do |from|
@@ -463,13 +623,16 @@ class Query
463
623
  end
464
624
 
465
625
  other_from = From.new(other, join_type, nil, alias_name)
466
- condition = expr(&blk).call(*(get_from_rows + other_from.rows.map {|r|r.with_from(other_from)}))
467
- other_from.condition = condition
626
+ if blk
627
+ condition = expr(&blk).call(*(get_from_rows + other_from.rows.map { |r| r.with_from(other_from) }))
628
+ other_from.condition = condition
629
+ end
468
630
 
469
631
  Query.new(
470
632
  @froms + [other_from],
471
633
  @conditions,
472
634
  @grouped_keys,
635
+ @order_bys,
473
636
  @row
474
637
  )
475
638
  end
@@ -477,9 +640,9 @@ end
477
640
 
478
641
  class IfElse
479
642
  def initialize(cond, true_result, false_result)
480
- @condition = cond
481
- @true_result = true_result
482
- @false_result = false_result
643
+ @condition = lit(cond)
644
+ @true_result = lit(true_result)
645
+ @false_result = lit(false_result)
483
646
  end
484
647
 
485
648
  def ref_sql
@@ -491,11 +654,11 @@ class IfElse
491
654
  end
492
655
 
493
656
  def ==(other)
494
- other.class == self.class && other.state == self.state
657
+ other.class == self.class && other.state == state
495
658
  end
496
659
 
497
660
  def state
498
- self.instance_variables.map { |variable| self.instance_variable_get variable }
661
+ instance_variables.map { |variable| instance_variable_get variable }
499
662
  end
500
663
  end
501
664
 
@@ -509,16 +672,12 @@ def generate_sql(query)
509
672
 
510
673
  sql = ''
511
674
 
512
- if queries.size > 0
513
- sql += 'with '
514
- end
675
+ sql += 'with ' if queries.size.positive?
515
676
 
516
- queries.map.with_index do |query, index|
517
- if index > 0
518
- sql += ', '
519
- end
520
- query.subquery_name = "subquery#{index}"
521
- sql += "#{query.subquery_name} as (\n#{query.sql}\n)\n"
677
+ queries.map.with_index do |q, index|
678
+ sql += ', ' if index.positive?
679
+ q.subquery_name = "subquery#{index}"
680
+ sql += "#{q.subquery_name} as (\n#{q.sql}\n)\n"
522
681
  end
523
682
 
524
683
  sql += last_query.sql
@@ -531,11 +690,12 @@ def fill(query)
531
690
 
532
691
  queries = []
533
692
  query.froms.each do |from|
534
- if from.source.is_a?(Query)
535
- subqueries = fill(from.source)
536
- subqueries.each do |subquery|
537
- queries.push(subquery)
538
- end
693
+ next if from.is_a?(CrossJoinUnnest)
694
+ next unless from.source.is_a?(Query)
695
+
696
+ subqueries = fill(from.source)
697
+ subqueries.each do |subquery|
698
+ queries.push(subquery)
539
699
  end
540
700
  end
541
701
  queries.push(query)
@@ -544,22 +704,6 @@ end
544
704
 
545
705
  $ruby2ruby = Ruby2Ruby.new
546
706
 
547
- def search_for_expr_block(parsed)
548
- # s(:iter, s(:call, nil, :expr)
549
-
550
- if parsed[0] == :iter && parsed[1][0] == :call && parsed[1][1].nil? && parsed[1][2] == :expr
551
- return parsed[3]
552
- end
553
-
554
- parsed.each do |component|
555
- if component.is_a?(Sexp)
556
- return search_for_expr_block(component)
557
- end
558
- end
559
-
560
- nil
561
- end
562
-
563
707
  def rewrite(parsed)
564
708
  parsed = parsed.map do |component|
565
709
  if component.is_a?(Sexp)
@@ -569,8 +713,25 @@ def rewrite(parsed)
569
713
  end
570
714
  end
571
715
 
572
- if parsed[0] == :call && parsed[2] == :==
573
- parsed[2] = :eq
716
+ if parsed[0] == :call
717
+ if parsed[2] == :==
718
+ parsed[2] = :eq
719
+ elsif parsed[2] == :!=
720
+ parsed[2] = :ne
721
+ elsif parsed[2] == :!
722
+ parsed[2] = :not
723
+ elsif parsed[2] == :-@
724
+ parsed[2] = :minus
725
+ elsif parsed[2] == :+@
726
+ parsed[2] = :plus
727
+ elsif parsed[2] == :nil?
728
+ parsed = Sexp.new(
729
+ :call,
730
+ parsed[1],
731
+ :eq,
732
+ Sexp.new(:nil)
733
+ )
734
+ end
574
735
  elsif parsed[0] == :and
575
736
  parsed = Sexp.new(
576
737
  :call,
@@ -578,20 +739,6 @@ def rewrite(parsed)
578
739
  :and,
579
740
  parsed[2]
580
741
  )
581
- elsif parsed[0] == :str
582
- parsed = Sexp.new(
583
- :call,
584
- Sexp.new(:const, :Literal),
585
- :new,
586
- Sexp.new(:str, parsed[1])
587
- )
588
- elsif parsed[0] == :lit && (parsed[1].is_a?(Integer) || parsed[1].is_a?(Float))
589
- parsed = Sexp.new(
590
- :call,
591
- Sexp.new(:const, :Literal),
592
- :new,
593
- Sexp.new(:lit, parsed[1])
594
- )
595
742
  elsif parsed[0] == :case && parsed[2] && parsed[2][0] == :in
596
743
  parsed = Sexp.new(
597
744
  :call,
@@ -606,14 +753,7 @@ def rewrite(parsed)
606
753
  :ifElse,
607
754
  parsed[1],
608
755
  parsed[2],
609
- parsed[3],
610
- )
611
- elsif parsed[0] == :nil
612
- parsed = Sexp.new(
613
- :call,
614
- Sexp.new(:const, :Literal),
615
- :new,
616
- Sexp.new(:nil)
756
+ parsed[3]
617
757
  )
618
758
  end
619
759
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lilit-sql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tanin Na Nakorn
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-27 00:00:00.000000000 Z
11
+ date: 2023-06-29 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |-
14
14
  lilit-sql is a Ruby DSL for composing production-grade analytical SQLs