fluent-query-sql 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +22 -0
- data/Gemfile.lock +26 -0
- data/LICENSE.txt +20 -0
- data/README.md +33 -0
- data/Rakefile +31 -0
- data/VERSION +1 -0
- data/fluent-query-sql.gemspec +74 -0
- data/lib/fluent-query/drivers/shared/tokens/sql.rb +128 -0
- data/lib/fluent-query/drivers/shared/tokens/sql/delete.rb +58 -0
- data/lib/fluent-query/drivers/shared/tokens/sql/from.rb +103 -0
- data/lib/fluent-query/drivers/shared/tokens/sql/groupby.rb +117 -0
- data/lib/fluent-query/drivers/shared/tokens/sql/having.rb +100 -0
- data/lib/fluent-query/drivers/shared/tokens/sql/insert.rb +60 -0
- data/lib/fluent-query/drivers/shared/tokens/sql/join.rb +98 -0
- data/lib/fluent-query/drivers/shared/tokens/sql/orderby.rb +148 -0
- data/lib/fluent-query/drivers/shared/tokens/sql/select.rb +147 -0
- data/lib/fluent-query/drivers/shared/tokens/sql/set.rb +94 -0
- data/lib/fluent-query/drivers/shared/tokens/sql/truncate.rb +59 -0
- data/lib/fluent-query/drivers/shared/tokens/sql/union.rb +65 -0
- data/lib/fluent-query/drivers/shared/tokens/sql/update.rb +58 -0
- data/lib/fluent-query/drivers/shared/tokens/sql/where.rb +100 -0
- data/lib/fluent-query/drivers/sql.rb +559 -0
- data/lib/fluent-query/queries/sql.rb +54 -0
- metadata +135 -0
@@ -0,0 +1,117 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "fluent-query/drivers/shared/tokens/sql"
|
3
|
+
require "hash-utils/object" # >= 0.17.0
|
4
|
+
|
5
|
+
module FluentQuery
|
6
|
+
module Drivers
|
7
|
+
module Shared
|
8
|
+
module Tokens
|
9
|
+
module SQL
|
10
|
+
|
11
|
+
##
|
12
|
+
# Generic SQL query GROUP BY token.
|
13
|
+
#
|
14
|
+
|
15
|
+
class GroupBy < FluentQuery::Drivers::Shared::Tokens::SQLToken
|
16
|
+
|
17
|
+
##
|
18
|
+
# Renders this token.
|
19
|
+
#
|
20
|
+
|
21
|
+
public
|
22
|
+
def render!(mode = :build)
|
23
|
+
stack = [ ]
|
24
|
+
unknown = [ ]
|
25
|
+
fields = [ ]
|
26
|
+
aliases = { }
|
27
|
+
distinct = false
|
28
|
+
|
29
|
+
result = "GROUP BY "
|
30
|
+
processor = @_query.processor
|
31
|
+
|
32
|
+
_class = self.unknown_token
|
33
|
+
|
34
|
+
# Process subtokens
|
35
|
+
|
36
|
+
@_subtokens.each do |token|
|
37
|
+
arguments = token.arguments
|
38
|
+
name = token.name
|
39
|
+
|
40
|
+
# Known select process
|
41
|
+
if name == :groupBy
|
42
|
+
length = arguments.length
|
43
|
+
|
44
|
+
if length > 0
|
45
|
+
first = arguments.first
|
46
|
+
|
47
|
+
if first.symbol?
|
48
|
+
stack << arguments
|
49
|
+
elsif first.string?
|
50
|
+
stack << processor.process_formatted(arguments, mode)
|
51
|
+
else
|
52
|
+
arguments.each do |argument|
|
53
|
+
if argument.array?
|
54
|
+
fields += argument
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Closes opened native token with unknown tokens
|
61
|
+
if unknown.length > 0
|
62
|
+
native = _class::new(@_driver, @_query, unknown)
|
63
|
+
stack << native.render!
|
64
|
+
unknown = [ ]
|
65
|
+
end
|
66
|
+
|
67
|
+
# Unknowns arguments pushes to the general native token
|
68
|
+
else
|
69
|
+
unknown << token
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Closes opened native token with unknown tokens
|
74
|
+
if unknown.length > 0
|
75
|
+
native = _class::new(@_driver, @_query, unknown)
|
76
|
+
stack << native.render!
|
77
|
+
unknown = [ ]
|
78
|
+
end
|
79
|
+
|
80
|
+
# Process stack with results
|
81
|
+
|
82
|
+
first = true
|
83
|
+
|
84
|
+
if not fields.empty?
|
85
|
+
stack.unshift(fields.uniq)
|
86
|
+
end
|
87
|
+
|
88
|
+
stack.each do |item|
|
89
|
+
|
90
|
+
if item.array?
|
91
|
+
if not first
|
92
|
+
result << ", "
|
93
|
+
end
|
94
|
+
|
95
|
+
result << processor.process_identifiers(item)
|
96
|
+
first = false
|
97
|
+
|
98
|
+
elsif item.string?
|
99
|
+
if not first
|
100
|
+
result << ", "
|
101
|
+
end
|
102
|
+
|
103
|
+
result << item.strip!
|
104
|
+
first = false
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
return result
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "fluent-query/drivers/shared/tokens/sql"
|
3
|
+
require "hash-utils/object" # >= 0.17.0
|
4
|
+
|
5
|
+
module FluentQuery
|
6
|
+
module Drivers
|
7
|
+
module Shared
|
8
|
+
module Tokens
|
9
|
+
module SQL
|
10
|
+
|
11
|
+
##
|
12
|
+
# Generic SQL query HAVING token.
|
13
|
+
#
|
14
|
+
|
15
|
+
class Having < FluentQuery::Drivers::Shared::Tokens::SQLToken
|
16
|
+
|
17
|
+
##
|
18
|
+
# Renders this token.
|
19
|
+
#
|
20
|
+
|
21
|
+
public
|
22
|
+
def render!(mode = :build)
|
23
|
+
_class = self.unknown_token
|
24
|
+
|
25
|
+
stack = [ ]
|
26
|
+
unknown = [ ]
|
27
|
+
|
28
|
+
operator = @_driver.quote_operator(:and)
|
29
|
+
processor = @_query.processor
|
30
|
+
|
31
|
+
result = "HAVING "
|
32
|
+
|
33
|
+
# Process subtokens
|
34
|
+
|
35
|
+
@_subtokens.each do |token|
|
36
|
+
arguments = token.arguments
|
37
|
+
|
38
|
+
# Known process
|
39
|
+
if token.name == :having
|
40
|
+
length = arguments.length
|
41
|
+
first = arguments.first
|
42
|
+
|
43
|
+
if length > 0
|
44
|
+
if (length > 1) or (first.string?)
|
45
|
+
stack << processor.process_formatted(arguments, mode)
|
46
|
+
elsif first.array?
|
47
|
+
stack << first.join(operator)
|
48
|
+
elsif first.hash?
|
49
|
+
stack << processor.process_hash(first, operator)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Closes opened native token with unknown tokens
|
54
|
+
if unknown.length > 0
|
55
|
+
native = _class::new(@_driver, @_query, unknown)
|
56
|
+
stack << native
|
57
|
+
unknown = [ ]
|
58
|
+
end
|
59
|
+
|
60
|
+
# Unknowns arguments pushes to the general native token
|
61
|
+
else
|
62
|
+
unknown << token
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
# Closes opened native token with unknown tokens
|
68
|
+
if unknown.length > 0
|
69
|
+
native = _class::new(@_driver, @_query, unknown)
|
70
|
+
stack << native
|
71
|
+
unknown = [ ]
|
72
|
+
end
|
73
|
+
|
74
|
+
# Process stack with results
|
75
|
+
first = true
|
76
|
+
|
77
|
+
stack.each do |item|
|
78
|
+
if item.kind_of? _class
|
79
|
+
result << item.render!
|
80
|
+
elsif item.string?
|
81
|
+
if not first
|
82
|
+
result << operator << " "
|
83
|
+
else
|
84
|
+
first = false
|
85
|
+
end
|
86
|
+
|
87
|
+
result << item
|
88
|
+
end
|
89
|
+
|
90
|
+
result << " "
|
91
|
+
end
|
92
|
+
|
93
|
+
return result
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "fluent-query/drivers/shared/tokens/sql"
|
3
|
+
require "fluent-query/drivers/exception"
|
4
|
+
require "hash-utils/object" # >= 0.17.0
|
5
|
+
require "hash-utils/array"
|
6
|
+
|
7
|
+
module FluentQuery
|
8
|
+
module Drivers
|
9
|
+
module Shared
|
10
|
+
module Tokens
|
11
|
+
module SQL
|
12
|
+
|
13
|
+
##
|
14
|
+
# Generic SQL query INSERT token.
|
15
|
+
#
|
16
|
+
|
17
|
+
class Insert < FluentQuery::Drivers::Shared::Tokens::SQLToken
|
18
|
+
|
19
|
+
##
|
20
|
+
# Renders this token.
|
21
|
+
#
|
22
|
+
|
23
|
+
public
|
24
|
+
def render!(mode = nil)
|
25
|
+
processor = @_query.processor
|
26
|
+
result = "INSERT INTO "
|
27
|
+
|
28
|
+
@_subtokens.each do |token|
|
29
|
+
arguments = token.arguments
|
30
|
+
|
31
|
+
# INSERT token
|
32
|
+
if token.name == :insert
|
33
|
+
|
34
|
+
# Checks for arguments
|
35
|
+
if (not arguments.first.symbol?) or (not arguments.second.hash?)
|
36
|
+
raise FluentQuery::Drivers::Exception::new("Symbol and Hash arguments expected for #insert method.")
|
37
|
+
end
|
38
|
+
|
39
|
+
# Process
|
40
|
+
table = processor.quote_identifier(arguments.first)
|
41
|
+
fields = processor.process_identifiers(arguments.second.keys)
|
42
|
+
values = processor.process_array(arguments.second.values)
|
43
|
+
|
44
|
+
result << table << " (" << fields << ") VALUES (" << values << ")"
|
45
|
+
|
46
|
+
# Unknown tokens renders directly
|
47
|
+
else
|
48
|
+
result = self.unknown_token::new(@_driver, @_query, token).render!
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
return result
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "fluent-query/drivers/shared/tokens/sql"
|
3
|
+
require "hash-utils/object" # >= 0.17.0
|
4
|
+
|
5
|
+
module FluentQuery
|
6
|
+
module Drivers
|
7
|
+
module Shared
|
8
|
+
module Tokens
|
9
|
+
module SQL
|
10
|
+
|
11
|
+
##
|
12
|
+
# Generic SQL query [LEFT|RIGHT|INNER|OUTER] JOIN token.
|
13
|
+
#
|
14
|
+
|
15
|
+
class Join < FluentQuery::Drivers::Shared::Tokens::SQLToken
|
16
|
+
|
17
|
+
##
|
18
|
+
# Renders this token.
|
19
|
+
#
|
20
|
+
|
21
|
+
public
|
22
|
+
def render!(mode = :build)
|
23
|
+
stack = [ ]
|
24
|
+
unknown = [ ]
|
25
|
+
|
26
|
+
_class = self.unknown_token
|
27
|
+
processor = @_query.processor
|
28
|
+
result = ""
|
29
|
+
|
30
|
+
@_subtokens.each do |token|
|
31
|
+
arguments = token.arguments
|
32
|
+
|
33
|
+
# JOIN token
|
34
|
+
if token.name == :join
|
35
|
+
|
36
|
+
original_name = token.original_name
|
37
|
+
stack << self._transform_token(original_name.to_s)
|
38
|
+
|
39
|
+
##
|
40
|
+
|
41
|
+
length = arguments.length
|
42
|
+
first = arguments.first
|
43
|
+
|
44
|
+
if length > 0
|
45
|
+
if first.symbol?
|
46
|
+
stack << processor.process_identifiers(arguments)
|
47
|
+
elsif (length > 1) or (first.string?)
|
48
|
+
stack << processor.process_formatted(arguments, mode)
|
49
|
+
elsif first.hash?
|
50
|
+
t_name = first.keys.first
|
51
|
+
t_alias = first.values.first
|
52
|
+
stack << (processor.quote_identifier(t_name) + " AS " + processor.quote_identifier(t_alias))
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Closes opened native token with unknown tokens
|
57
|
+
if unknown.length > 0
|
58
|
+
native = _class::new(@_driver, @_query, unknown)
|
59
|
+
stack << native
|
60
|
+
unknown = [ ]
|
61
|
+
end
|
62
|
+
|
63
|
+
# Unknown arguments pushes to the general native token
|
64
|
+
else
|
65
|
+
unknown << token
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
# Closes opened native token with unknown tokens
|
71
|
+
if unknown.length > 0
|
72
|
+
native = _class::new(@_driver, @_query, unknown)
|
73
|
+
stack << native
|
74
|
+
unknown = [ ]
|
75
|
+
end
|
76
|
+
|
77
|
+
# Process stack with results
|
78
|
+
first = true
|
79
|
+
|
80
|
+
stack.each do |item|
|
81
|
+
if item.kind_of? _class
|
82
|
+
result << item.render!
|
83
|
+
elsif item.string?
|
84
|
+
result << item
|
85
|
+
end
|
86
|
+
|
87
|
+
result << " "
|
88
|
+
end
|
89
|
+
|
90
|
+
return result
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
@@ -0,0 +1,148 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "fluent-query/drivers/shared/tokens/sql"
|
3
|
+
require "hash-utils/object" # >= 0.17.0
|
4
|
+
|
5
|
+
module FluentQuery
|
6
|
+
module Drivers
|
7
|
+
module Shared
|
8
|
+
module Tokens
|
9
|
+
module SQL
|
10
|
+
|
11
|
+
##
|
12
|
+
# Generic SQL query ORDER BY token.
|
13
|
+
#
|
14
|
+
|
15
|
+
class OrderBy < FluentQuery::Drivers::Shared::Tokens::SQLToken
|
16
|
+
|
17
|
+
##
|
18
|
+
# Renders this token.
|
19
|
+
#
|
20
|
+
|
21
|
+
public
|
22
|
+
def render!(mode = :build)
|
23
|
+
|
24
|
+
stack = [ ]
|
25
|
+
custom = [ ]
|
26
|
+
unknown = [ ]
|
27
|
+
fields = [ ]
|
28
|
+
distinct = false
|
29
|
+
|
30
|
+
result = "ORDER BY "
|
31
|
+
processor = @_query.processor
|
32
|
+
_class = self.unknown_token
|
33
|
+
|
34
|
+
|
35
|
+
# Process subtokens
|
36
|
+
|
37
|
+
@_subtokens.each do |token|
|
38
|
+
arguments = token.arguments
|
39
|
+
name = token.name
|
40
|
+
|
41
|
+
# Known select process
|
42
|
+
if name == :orderBy
|
43
|
+
length = arguments.length
|
44
|
+
close_custom = false
|
45
|
+
|
46
|
+
if length > 0
|
47
|
+
if (length > 1) or (arguments.first.string?)
|
48
|
+
value = processor.process_formatted(arguments, mode).dup
|
49
|
+
custom.push(value)
|
50
|
+
|
51
|
+
# Closes fields if they are set
|
52
|
+
if not fields.empty?
|
53
|
+
stack << (processor.process_identifiers(fields) << ", ")
|
54
|
+
fields = [ ]
|
55
|
+
end
|
56
|
+
|
57
|
+
elsif arguments.first.array?
|
58
|
+
fields += arguments.first
|
59
|
+
close_custom = true
|
60
|
+
|
61
|
+
elsif arguments.first.symbol?
|
62
|
+
fields += arguments
|
63
|
+
close_custom = true
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
# Closes custom formulations if they are set
|
68
|
+
# and it's required.
|
69
|
+
if close_custom and not custom.empty?
|
70
|
+
stack << (self._close_custom(custom) << ", ")
|
71
|
+
custom = [ ]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Closes opened native token with unknown tokens
|
76
|
+
if unknown.length > 0
|
77
|
+
native = _class::new(@_driver, @_query, unknown)
|
78
|
+
stack << (native.render! + ", ")
|
79
|
+
unknown = [ ]
|
80
|
+
end
|
81
|
+
|
82
|
+
# Unknowns arguments pushes to the general native token
|
83
|
+
else
|
84
|
+
unknown << token
|
85
|
+
|
86
|
+
if not fields.empty?
|
87
|
+
stack << processor.process_identifiers(fields)
|
88
|
+
fields = [ ]
|
89
|
+
elsif not custom.empty?
|
90
|
+
stack << self._close_custom(custom)
|
91
|
+
custom = [ ]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Closes
|
97
|
+
|
98
|
+
# Opened native token with unknown tokens
|
99
|
+
if unknown.length > 0
|
100
|
+
native = _class::new(@_driver, @_query, unknown)
|
101
|
+
value = native.render!
|
102
|
+
unknown = [ ]
|
103
|
+
|
104
|
+
if (not fields.empty?) or (not custom.empty?)
|
105
|
+
value << ", "
|
106
|
+
end
|
107
|
+
|
108
|
+
stack << value
|
109
|
+
end
|
110
|
+
|
111
|
+
# Fields list
|
112
|
+
if not fields.empty?
|
113
|
+
value = processor.process_identifiers(fields)
|
114
|
+
|
115
|
+
if not custom.empty?
|
116
|
+
value << ", "
|
117
|
+
end
|
118
|
+
|
119
|
+
stack << value
|
120
|
+
end
|
121
|
+
|
122
|
+
# Custom list
|
123
|
+
if not custom.empty?
|
124
|
+
stack << self._close_custom(custom)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Process stack with results
|
128
|
+
result << stack.join(" ")
|
129
|
+
|
130
|
+
return result
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
##
|
135
|
+
# Closes array of custom (formatted) strings.
|
136
|
+
#
|
137
|
+
|
138
|
+
protected
|
139
|
+
def _close_custom(custom)
|
140
|
+
custom.join(", ")
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|