File tree Expand file tree Collapse file tree 11 files changed +177
-21
lines changed
Expand file tree Collapse file tree 11 files changed +177
-21
lines changed Original file line number Diff line number Diff line change 11# frozen_string_literal: true
22
3+ require "sql/composer/statement"
4+ require "sql/composer/tokens"
5+
36module SQL
47 module Composer
58 class Compiler
9+ include ::Dry ::Effects ::Handler . State ( :tokens )
10+
611 attr_reader :backend
712
813 attr_reader :nodes
914
10- def initialize ( backend )
15+ attr_reader :options
16+
17+ attr_reader :tokens
18+
19+ def initialize ( backend , options )
1120 @backend = backend
12- @nodes = [ ]
21+ @options = options
22+ @nodes = options [ :nodes ] || [ ]
23+ @tokens = options [ :tokens ]
1324 end
1425
1526 def call ( ast )
16- ast . map { |node | visit ( node ) }
17- freeze
27+ with_tokens ( tokens ) { ast . map { |node | visit ( node ) } }
28+ Statement . new ( compiler : freeze )
29+ end
30+
31+ def with ( new_options )
32+ self . class . new ( backend , options . merge ( new_options ) . merge ( nodes : nodes ) )
1833 end
1934
2035 def to_s
21- nodes . map ( &:to_s ) . join ( "\n " )
36+ with_tokens ( tokens ) { nodes . map ( &:to_s ) . join ( "\n " ) } . last
2237 end
2338
2439 def visit ( node )
Original file line number Diff line number Diff line change 11# frozen_string_literal: true
22
3+ require "dry/effects"
4+
35require "sql/composer/compiler"
6+ require "sql/composer/tokens"
47
58module SQL
69 module Composer
710 class DSL < BasicObject
11+ include ::Dry ::Effects ::Handler . State ( :tokens )
12+
813 attr_reader :options
914
1015 attr_reader :ast
1116
17+ attr_reader :tokens
18+
1219 def initialize ( options , &block )
13- @ast = [ ]
1420 @options = options
15- instance_exec ( *options [ :args ] , &block )
21+ @ast = [ ]
22+ @tokens = options [ :tokens ] || Tokens . new
23+
24+ with_tokens ( tokens ) do
25+ instance_exec ( *options [ :args ] , &block )
26+ end
1627 end
1728
1829 def call
19- compiler = Compiler . new ( options . fetch ( :backend ) )
30+ compiler = Compiler . new ( options . fetch ( :backend ) , tokens : tokens )
2031 compiler . ( ast )
2132 end
2233
Original file line number Diff line number Diff line change 11# frozen_string_literal: true
22
3+ require "dry/effects"
4+
35module SQL
46 module Composer
57 module Nodes
68 class Core
9+ include Dry ::Effects . State ( :tokens )
10+
11+ attr_reader :id
12+
713 attr_reader :options
814
915 def initialize ( options )
1016 @options = options
17+ @id = tokens . next_id
1118 end
1219
13- def fetch ( name )
14- @options . fetch ( name )
20+ def fetch ( name , default = nil )
21+ @options . fetch ( name , default )
1522 end
1623
1724 def backend
Original file line number Diff line number Diff line change @@ -32,7 +32,15 @@ def qualify?
3232
3333 # this is probably a stupid idea lol
3434 def ==( other )
35- Operations ::Eql . new ( self , Nodes ::Value . new ( input : other , backend : backend ) )
35+ value = Nodes ::Value . new ( input : other , backend : backend )
36+
37+ operation = Operations ::Eql . new ( left : self , right : value )
38+
39+ if other . start_with? ( "%" ) && other . end_with? ( "%" )
40+ tokens . add ( other , value )
41+ end
42+
43+ operation
3644 end
3745 end
3846 end
Original file line number Diff line number Diff line change 11# frozen_string_literal: true
22
3+ require "sql/composer/nodes/core"
4+
35module SQL
46 module Composer
57 module Nodes
68 module Operations
7- class Eql
8- attr_reader :left , :right
9+ class Eql < Core
10+ def left
11+ fetch ( :left )
12+ end
913
10- def initialize ( left , right )
11- @left , @ right = left , right
14+ def right
15+ fetch ( : right)
1216 end
1317
1418 def or ( other )
15- Operations ::Or . new ( self , other )
19+ Operations ::Or . new ( left : self , right : other )
1620 end
1721 alias_method :OR , :or
1822
Original file line number Diff line number Diff line change 11# frozen_string_literal: true
22
3+ require "sql/composer/nodes/core"
4+
35module SQL
46 module Composer
57 module Nodes
68 module Operations
7- class Or
8- attr_reader :left , :right
9+ class Or < Core
10+ def left
11+ fetch ( :left )
12+ end
913
10- def initialize ( left , right )
11- @left , @ right = left , right
14+ def right
15+ fetch ( : right)
1216 end
1317
1418 def to_s
Original file line number Diff line number Diff line change @@ -7,7 +7,7 @@ module Composer
77 module Nodes
88 class Value < Core
99 def input
10- fetch ( :input )
10+ tokens . value ( id , fetch ( :input ) )
1111 end
1212
1313 def to_s
Original file line number Diff line number Diff line change 1+ # frozen_string_literal: true
2+
3+ module SQL
4+ module Composer
5+ class Statement
6+ include Enumerable
7+
8+ attr_reader :options
9+
10+ def initialize ( options )
11+ @options = options
12+ end
13+
14+ def each ( &block )
15+ nodes . each ( &block )
16+ end
17+
18+ def set ( values )
19+ tokens = compiler . tokens . new
20+
21+ values . each do |key , value |
22+ tokens . set ( key , value )
23+ end
24+
25+ compiler . with ( tokens : tokens )
26+ end
27+
28+ def to_s
29+ compiler . to_s
30+ end
31+
32+ def compiler
33+ options . fetch ( :compiler )
34+ end
35+
36+ def nodes
37+ compiler . nodes
38+ end
39+ end
40+ end
41+ end
Original file line number Diff line number Diff line change 1+ # frozen_string_literal: true
2+
3+ module SQL
4+ module Composer
5+ class Tokens
6+ include Dry ::Core ::Constants
7+
8+ attr_reader :data
9+
10+ def initialize ( data : { } , counter : 0 )
11+ @data = data
12+ @counter = counter
13+ end
14+
15+ def add ( key , node )
16+ data [ key [ 1 ..-2 ] . to_sym ] = [ node . id , Undefined ]
17+ self
18+ end
19+
20+ def set ( key , value )
21+ tuple = [ data [ key ] [ 0 ] , value ]
22+ data [ key ] = tuple
23+ self
24+ end
25+
26+ def new
27+ self . class . new ( data : data . dup , counter : @counter )
28+ end
29+
30+ def value ( id , default )
31+ entry = data . detect { |_ , ( node_id , value ) | node_id . equal? ( id ) }
32+ entry ? entry [ 1 ] [ 1 ] : default
33+ end
34+
35+ def next_id
36+ @counter += 1
37+ end
38+ end
39+ end
40+ end
Original file line number Diff line number Diff line change @@ -85,6 +85,30 @@ def compose(&block)
8585 end
8686 end
8787
88+ context "with a dynamic WHERE" do
89+ let ( :query ) do
90+ compose { |users |
91+ SELECT users . id , users . name
92+ FROM users . table
93+ WHERE users . name == "%name%"
94+ }
95+ end
96+
97+ let ( :result ) do
98+ query . set ( name : "Jane" ) . to_s
99+ end
100+
101+ specify do
102+ expect ( result ) . to eql (
103+ <<~SQL . strip
104+ SELECT "users"."id", "users"."name"
105+ FROM "users"
106+ WHERE "users"."name" == 'Jane'
107+ SQL
108+ )
109+ end
110+ end
111+
88112 context "without ORDER" do
89113 let ( :query ) do
90114 compose { |users |
You can’t perform that action at this time.
0 commit comments