fluent-query-sql 0.9.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.
- 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
|
+
|