lilit-sql 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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