fluent-query 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 +22 -0
- data/LICENSE.txt +20 -0
- data/README.md +230 -0
- data/Rakefile +29 -0
- data/VERSION +1 -0
- data/fluent-query.gemspec +75 -0
- data/lib/fluent-query.rb +2 -0
- data/lib/fluent-query/compiler.rb +182 -0
- data/lib/fluent-query/compilers/result.rb +33 -0
- data/lib/fluent-query/connection.rb +316 -0
- data/lib/fluent-query/data.rb +17 -0
- data/lib/fluent-query/driver.rb +279 -0
- data/lib/fluent-query/drivers/exception.rb +13 -0
- data/lib/fluent-query/drivers/result.rb +98 -0
- data/lib/fluent-query/exception.rb +12 -0
- data/lib/fluent-query/queries/abstract.rb +169 -0
- data/lib/fluent-query/queries/compiled.rb +51 -0
- data/lib/fluent-query/queries/prepared.rb +50 -0
- data/lib/fluent-query/queries/processor.rb +392 -0
- data/lib/fluent-query/query.rb +118 -0
- data/lib/fluent-query/result.rb +153 -0
- data/lib/fluent-query/token.rb +73 -0
- data/lib/fluent-query/tokens/raw.rb +26 -0
- metadata +136 -0
data/.document
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
gem "hash-utils", ">= 0.18.0"
|
5
|
+
gem "abstract", ">= 1.0.0"
|
6
|
+
gem "hashie", ">= 1.0.0"
|
7
|
+
|
8
|
+
# Add dependencies to develop your gem here.
|
9
|
+
# Include everything needed to run rake, tests, features, etc.
|
10
|
+
group :development do
|
11
|
+
gem "bundler", "~> 1.0.13"
|
12
|
+
gem "jeweler", "~> 1.6.0"
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
|
17
|
+
# fluent-query-sql
|
18
|
+
# fluent-query-dbh
|
19
|
+
# fluent-query-mysql
|
20
|
+
# fluent-query-sqlite
|
21
|
+
# fluent-query-postgresql
|
22
|
+
# native-query
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
abstract (1.0.0)
|
5
|
+
git (1.2.5)
|
6
|
+
hash-utils (0.18.0)
|
7
|
+
hashie (1.0.0)
|
8
|
+
jeweler (1.6.3)
|
9
|
+
bundler (~> 1.0)
|
10
|
+
git (>= 1.2.5)
|
11
|
+
rake
|
12
|
+
rake (0.9.2)
|
13
|
+
|
14
|
+
PLATFORMS
|
15
|
+
ruby
|
16
|
+
|
17
|
+
DEPENDENCIES
|
18
|
+
abstract (>= 1.0.0)
|
19
|
+
bundler (~> 1.0.13)
|
20
|
+
hash-utils (>= 0.18.0)
|
21
|
+
hashie (>= 1.0.0)
|
22
|
+
jeweler (~> 1.6.0)
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 - 2011 Martin Kozák (martinkozak@martinkozak.net)
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,230 @@
|
|
1
|
+
Fluent Query
|
2
|
+
============
|
3
|
+
|
4
|
+
**Fluent Query** is cool way how to write SQL queries and general way
|
5
|
+
how to convert series of method calls to string query in an universal
|
6
|
+
and system independent manner. It may sounds like a piece of magic, but
|
7
|
+
it works. It's inspired by [Dibi][1].
|
8
|
+
|
9
|
+
|
10
|
+
### General Principle
|
11
|
+
|
12
|
+
Some example:
|
13
|
+
|
14
|
+
connection.select("[id], [name]").from("[maintainers]").orderBy("[code] ASC")
|
15
|
+
|
16
|
+
Will be rendered to:
|
17
|
+
|
18
|
+
SELECT `id`, `name` FROM `maintainers` ORDER BY `code` ASC
|
19
|
+
|
20
|
+
It looks trivial, but for example call `connection.heyReturnMeSomething("[yeah]")`
|
21
|
+
will be transformed to:
|
22
|
+
|
23
|
+
HEY RETURN ME SOMETHING `yeah`
|
24
|
+
|
25
|
+
Which gives big potential. Of sure, escaping, aggregation and chaining
|
26
|
+
of chunks for example for `WHERE` directive or another is necessary.
|
27
|
+
It's ensured by appropriate *language* (e.g. database) *driver*.
|
28
|
+
|
29
|
+
And what a more: order of tokens isn't mandatory, so with exception
|
30
|
+
of initial world (`SELECT`, `INSERT` etc.) you can add them according to
|
31
|
+
your needs.
|
32
|
+
|
33
|
+
### Connecting
|
34
|
+
|
35
|
+
# Include it!
|
36
|
+
require "fluent-query/mysql"
|
37
|
+
require "fluent-query"
|
38
|
+
|
39
|
+
# Setup it!
|
40
|
+
driver = FluentQuery::Drivers::MySQL
|
41
|
+
settings = {
|
42
|
+
:username => "wikistatistics.net",
|
43
|
+
:password => "alfabeta",
|
44
|
+
:server => "localhost",
|
45
|
+
:port => 5432,
|
46
|
+
:database => "wikistatistics.net",
|
47
|
+
:schema => "public"
|
48
|
+
}
|
49
|
+
|
50
|
+
# Create it!
|
51
|
+
connection = FluentQuery::Connection::new(driver, settings)
|
52
|
+
|
53
|
+
Now we have connection prepared for use.
|
54
|
+
|
55
|
+
### Placeholders
|
56
|
+
|
57
|
+
Simple translation calls to queries isn't the only functionality. Very
|
58
|
+
helpful are also *placeholders*. They works principially by the same way
|
59
|
+
as `#printf` method, but are more suitable for use in queries and
|
60
|
+
supports automatic quoting. Available are:
|
61
|
+
|
62
|
+
* `%%s` which quotes string,
|
63
|
+
* `%%i` which quotes integer,
|
64
|
+
* `%%b` which quotes boolean,
|
65
|
+
* `%%f` which quotes float,
|
66
|
+
* `%%d` which quotes date,
|
67
|
+
* `%%t` which quotes date-time,
|
68
|
+
|
69
|
+
And also three special:
|
70
|
+
|
71
|
+
* `%%sql` which quotes subquery (expects query object),
|
72
|
+
* `%%and` which joins input by `AND` operator (expects hash),
|
73
|
+
* `%%or` which joins input by `OR` operator (expects hash).
|
74
|
+
|
75
|
+
An example:
|
76
|
+
|
77
|
+
connection.select("[id], [name]") \
|
78
|
+
.from("[maintainers]") \
|
79
|
+
.where("[id] = %%i AND company = %%s", 5, "Wikia") \
|
80
|
+
.where("[language] IN %%l", ["cz", "en"]) \
|
81
|
+
.or \
|
82
|
+
.where("[active] IS %%b", true)
|
83
|
+
|
84
|
+
Will be transformed to:
|
85
|
+
|
86
|
+
SELECT `id`, `name` FROM `maintainers`
|
87
|
+
WHERE `id` = 5
|
88
|
+
AND `company` = "Wikia"
|
89
|
+
AND `language` IN ("cz", "en")
|
90
|
+
OR `active` IS TRUE
|
91
|
+
|
92
|
+
It's way how to write complex or special queries. But **direct values
|
93
|
+
assigning is supported**, so for example:
|
94
|
+
|
95
|
+
connection.select(:id, :name) \
|
96
|
+
.from(:maintainers) \
|
97
|
+
.where(:id => 5, :company => "Wikia") \
|
98
|
+
.where("[language] IN %%l", ["cz", "en"]) # %l will join items by commas
|
99
|
+
.or \
|
100
|
+
.where(:active => true)
|
101
|
+
|
102
|
+
Will give you expected result too and as you can see, it's much more
|
103
|
+
readable, flexible, thus it's preferred.
|
104
|
+
|
105
|
+
### Checking Out the Results
|
106
|
+
|
107
|
+
Query results can be executed by `#execute` which returns result object
|
108
|
+
or by `#do` which returns count of affected rows. Following methods for
|
109
|
+
checking out the results are available:
|
110
|
+
|
111
|
+
* `#each` which iterates through all returned rows,
|
112
|
+
* `#one` which returns first row only,
|
113
|
+
* `#single` which returns first value fo first row,
|
114
|
+
* `#assoc` which allows building complex Hashes (see below).
|
115
|
+
|
116
|
+
#### Associative Fetching
|
117
|
+
|
118
|
+
Special associative method is the `assoc` one which is directly inspired
|
119
|
+
by appropriate feature of the [Dibi][1] layer. It's aim is automatic
|
120
|
+
aggregation of returned rows to multidimensional Hashes.
|
121
|
+
|
122
|
+
Simply give it key names from your dataset. Be warn, only one or two
|
123
|
+
levels (e.g. dimesions in resultant Hash) are supported:
|
124
|
+
|
125
|
+
records = connection.select(:maintainer_id, :language) \
|
126
|
+
.from(:sites) \
|
127
|
+
.execute.assoc(:maintainer_id, :language)
|
128
|
+
|
129
|
+
Will transform the dataset:
|
130
|
+
|
131
|
+
# maintainer_id, language, name
|
132
|
+
[1, "en", "English Wikipedia"],
|
133
|
+
[1, "es", "Spain Wikipedia"],
|
134
|
+
[2, "cs", "Czech Wikihow"],
|
135
|
+
[2, "ja", "Japan Wikihow"],
|
136
|
+
|
137
|
+
To the following structure:
|
138
|
+
|
139
|
+
1 => {
|
140
|
+
"en" => "English Wikipedia",
|
141
|
+
"es" => "Spain Wikipedia"
|
142
|
+
},
|
143
|
+
|
144
|
+
2 => {
|
145
|
+
"cs" => "Czech Wikihow",
|
146
|
+
"ja" => "Japan Wikihow"
|
147
|
+
}
|
148
|
+
|
149
|
+
### Inserts, Updates and Deletes
|
150
|
+
|
151
|
+
Inserting, updating and deleteing the records works by the same way as
|
152
|
+
selecting. Some examples:
|
153
|
+
|
154
|
+
connection.insert(:maintainers, :name => "Wikimedia", :country => "United States")
|
155
|
+
|
156
|
+
# Will be:
|
157
|
+
# INSERT INTO `maintainers` (`name`, `country`) VALUES ("Wikimedia", "United States")
|
158
|
+
|
159
|
+
connection.update(:maintainers).set(:country => "Czech Republic").where(:id => 10).limit(1)
|
160
|
+
|
161
|
+
# Will be:
|
162
|
+
# UPDATE `maintainers` SET `country` = "Czech Republic" WHERE `id` = 10 LIMIT 1
|
163
|
+
|
164
|
+
connection.delete(:maintainers).where(:id => 10).limit(1)
|
165
|
+
|
166
|
+
# Will be:
|
167
|
+
# DELETE FROM `maintainers` WHERE `id` = 10 LIMIT 1
|
168
|
+
|
169
|
+
|
170
|
+
#### Transactions
|
171
|
+
|
172
|
+
Transactions support is available manual:
|
173
|
+
|
174
|
+
* `connection.begin`,
|
175
|
+
* `connection.commit`,
|
176
|
+
* `connection.rollback`.
|
177
|
+
|
178
|
+
Or by automatic way:
|
179
|
+
|
180
|
+
connection.transaction do
|
181
|
+
#...
|
182
|
+
end
|
183
|
+
|
184
|
+
### Compiled and Prepared Queries
|
185
|
+
|
186
|
+
Queries can be pre-prepared and pre-optimized by two different methods:
|
187
|
+
|
188
|
+
* `#compile` which compiles query to form of array of direct callbacks,
|
189
|
+
so builds it and quotes all identifiers, keeps intact placeholders only,
|
190
|
+
* `#prepare` which transforms compiled query to prepared form as it's
|
191
|
+
known from DBD or PDO if it's supported by driver.
|
192
|
+
|
193
|
+
Simply call one of these methods upon the query and use resultant query
|
194
|
+
as usuall (of sure, without methods which would change it because it's
|
195
|
+
compiled so cannot be further changed).
|
196
|
+
|
197
|
+
Also note, SQL token calls cannot be called by mandatory way (e.g. you
|
198
|
+
can call `#order` before `#where` etc.), but they will be reordered
|
199
|
+
in resultant both compiled and prepared query, so arguments given to
|
200
|
+
execute must be taken to call in correct order according to resultant
|
201
|
+
SQL query. So in case of using compiled or prepared statements, it's
|
202
|
+
good idea to write calls in the same order as SQL requires.
|
203
|
+
|
204
|
+
### Examples
|
205
|
+
|
206
|
+
More examples or tutorials than these above aren't available. It's in
|
207
|
+
development, although stable and production ready state. For well
|
208
|
+
documented and fully usable application see [Native Query][4].
|
209
|
+
|
210
|
+
|
211
|
+
Contributing
|
212
|
+
------------
|
213
|
+
|
214
|
+
1. Fork it.
|
215
|
+
2. Create a branch (`git checkout -b 20101220-my-change`).
|
216
|
+
3. Commit your changes (`git commit -am "Added something"`).
|
217
|
+
4. Push to the branch (`git push origin 20101220-my-change`).
|
218
|
+
5. Create an [Issue][2] with a link to your branch.
|
219
|
+
6. Enjoy a refreshing Diet Coke and wait.
|
220
|
+
|
221
|
+
Copyright
|
222
|
+
---------
|
223
|
+
|
224
|
+
Copyright © 2009-2011 [Martin Kozák][3]. See `LICENSE.txt` for
|
225
|
+
further details.
|
226
|
+
|
227
|
+
[1]: http://dibiphp.com/
|
228
|
+
[2]: http://github.com/martinkozak/fluent-query/issues
|
229
|
+
[3]: http://www.martinkozak.net/
|
230
|
+
[4]: http://github.com/martinkozak/native-query
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'rubygems'
|
3
|
+
require 'bundler'
|
4
|
+
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'rake'
|
14
|
+
require 'jeweler'
|
15
|
+
|
16
|
+
Jeweler::Tasks.new do |gem|
|
17
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
18
|
+
gem.name = "fluent-query"
|
19
|
+
gem.homepage = "http://github.com/martinkozak/fluent-query"
|
20
|
+
gem.license = "MIT"
|
21
|
+
gem.summary = 'Cool way how to write SQL queries and general way how to convert series of method calls to string query in an universal and system independent manner. This gem contains base libraries only. SQL implementation is available standalone.'
|
22
|
+
gem.email = "martinkozak@martinkozak.net"
|
23
|
+
gem.authors = ["Martin Kozák"]
|
24
|
+
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
25
|
+
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
|
26
|
+
# gem.add_runtime_dependency 'jabber4r', '> 0.1'
|
27
|
+
# gem.add_development_dependency 'rspec', '> 1.2.3'
|
28
|
+
end
|
29
|
+
Jeweler::RubygemsDotOrgTasks.new
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.9.0
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{fluent-query}
|
8
|
+
s.version = "0.9.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = [%q{Martin Kozák}]
|
12
|
+
s.date = %q{2011-07-14}
|
13
|
+
s.email = %q{martinkozak@martinkozak.net}
|
14
|
+
s.extra_rdoc_files = [
|
15
|
+
"LICENSE.txt",
|
16
|
+
"README.md"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".document",
|
20
|
+
"Gemfile",
|
21
|
+
"Gemfile.lock",
|
22
|
+
"LICENSE.txt",
|
23
|
+
"README.md",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"fluent-query.gemspec",
|
27
|
+
"lib/fluent-query.rb",
|
28
|
+
"lib/fluent-query/compiler.rb",
|
29
|
+
"lib/fluent-query/compilers/result.rb",
|
30
|
+
"lib/fluent-query/connection.rb",
|
31
|
+
"lib/fluent-query/data.rb",
|
32
|
+
"lib/fluent-query/driver.rb",
|
33
|
+
"lib/fluent-query/drivers/exception.rb",
|
34
|
+
"lib/fluent-query/drivers/result.rb",
|
35
|
+
"lib/fluent-query/exception.rb",
|
36
|
+
"lib/fluent-query/queries/abstract.rb",
|
37
|
+
"lib/fluent-query/queries/compiled.rb",
|
38
|
+
"lib/fluent-query/queries/prepared.rb",
|
39
|
+
"lib/fluent-query/queries/processor.rb",
|
40
|
+
"lib/fluent-query/query.rb",
|
41
|
+
"lib/fluent-query/result.rb",
|
42
|
+
"lib/fluent-query/token.rb",
|
43
|
+
"lib/fluent-query/tokens/raw.rb"
|
44
|
+
]
|
45
|
+
s.homepage = %q{http://github.com/martinkozak/fluent-query}
|
46
|
+
s.licenses = [%q{MIT}]
|
47
|
+
s.require_paths = [%q{lib}]
|
48
|
+
s.rubygems_version = %q{1.8.5}
|
49
|
+
s.summary = %q{Cool way how to write SQL queries and general way how to convert series of method calls to string query in an universal and system independent manner. This gem contains base libraries only. SQL implementation is available standalone.}
|
50
|
+
|
51
|
+
if s.respond_to? :specification_version then
|
52
|
+
s.specification_version = 3
|
53
|
+
|
54
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
55
|
+
s.add_runtime_dependency(%q<hash-utils>, [">= 0.18.0"])
|
56
|
+
s.add_runtime_dependency(%q<abstract>, [">= 1.0.0"])
|
57
|
+
s.add_runtime_dependency(%q<hashie>, [">= 1.0.0"])
|
58
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.13"])
|
59
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.6.0"])
|
60
|
+
else
|
61
|
+
s.add_dependency(%q<hash-utils>, [">= 0.18.0"])
|
62
|
+
s.add_dependency(%q<abstract>, [">= 1.0.0"])
|
63
|
+
s.add_dependency(%q<hashie>, [">= 1.0.0"])
|
64
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.13"])
|
65
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.0"])
|
66
|
+
end
|
67
|
+
else
|
68
|
+
s.add_dependency(%q<hash-utils>, [">= 0.18.0"])
|
69
|
+
s.add_dependency(%q<abstract>, [">= 1.0.0"])
|
70
|
+
s.add_dependency(%q<hashie>, [">= 1.0.0"])
|
71
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.13"])
|
72
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.0"])
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
data/lib/fluent-query.rb
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "date"
|
3
|
+
require "fluent-query/query"
|
4
|
+
require "fluent-query/compilers/result"
|
5
|
+
require "hash-utils/array" # >= 0.17.0
|
6
|
+
|
7
|
+
module FluentQuery
|
8
|
+
|
9
|
+
##
|
10
|
+
# Query compiler.
|
11
|
+
#
|
12
|
+
|
13
|
+
class Compiler
|
14
|
+
|
15
|
+
##
|
16
|
+
# Contains all possible formatting directives.
|
17
|
+
#
|
18
|
+
|
19
|
+
FORMATTING_DIRECTIVES = [:i, :s, :l, :b, :f, :d, :t, :sql, :and, :or]
|
20
|
+
|
21
|
+
##
|
22
|
+
# Indicates directive prefix.
|
23
|
+
#
|
24
|
+
|
25
|
+
DIRECTIVE_PREFIX = "%%"
|
26
|
+
|
27
|
+
##
|
28
|
+
# Compiling cache.
|
29
|
+
#
|
30
|
+
|
31
|
+
private
|
32
|
+
@__compile_cache
|
33
|
+
|
34
|
+
##
|
35
|
+
# Calls hash cache.
|
36
|
+
#
|
37
|
+
|
38
|
+
private
|
39
|
+
@__calls_cache
|
40
|
+
|
41
|
+
##
|
42
|
+
# Processor upon which compiler should work upon.
|
43
|
+
#
|
44
|
+
|
45
|
+
protected
|
46
|
+
@_processor
|
47
|
+
|
48
|
+
##
|
49
|
+
# Constructor.
|
50
|
+
#
|
51
|
+
|
52
|
+
public
|
53
|
+
def initialize(processor)
|
54
|
+
@_processor = processor
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# Compiles formatting.
|
59
|
+
#
|
60
|
+
|
61
|
+
public
|
62
|
+
def compile_formatting(directive)
|
63
|
+
self.calls[directive.to_sym]
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# Returns calls array.
|
68
|
+
#
|
69
|
+
|
70
|
+
public
|
71
|
+
def calls
|
72
|
+
if @__calls_cache.nil?
|
73
|
+
@__calls_cache = {
|
74
|
+
:i => Proc::new { |v| @_processor.quote_value(v.to_i) },
|
75
|
+
:s => Proc::new { |v| @_processor.quote_value(v.to_s) },
|
76
|
+
:b => Proc::new { |v| @_processor.quote_value(v ? true : false) },
|
77
|
+
:f => Proc::new { |v| @_processor.quote_value(v.to_f) },
|
78
|
+
|
79
|
+
:l => Proc::new do |v|
|
80
|
+
if v.array?
|
81
|
+
output = v
|
82
|
+
elsif v.hash?
|
83
|
+
output = v.values
|
84
|
+
end
|
85
|
+
|
86
|
+
"(" << @_processor.process_array(output) << ")"
|
87
|
+
end,
|
88
|
+
|
89
|
+
:d => Proc::new do |v|
|
90
|
+
if v.string?
|
91
|
+
output = Date.parse(v)
|
92
|
+
elsif argument.kind_of? DateTime
|
93
|
+
output = Date.parse(v.to_s)
|
94
|
+
elsif argument.kind_of? Date
|
95
|
+
output = v
|
96
|
+
end
|
97
|
+
|
98
|
+
@_processor.quote_value(output)
|
99
|
+
end,
|
100
|
+
|
101
|
+
:t => Proc::new do |v|
|
102
|
+
if v.string?
|
103
|
+
output = DateTime.parse(v)
|
104
|
+
elsif argument.kind_of? Date
|
105
|
+
output = DateTime.parse(v.to_s)
|
106
|
+
elsif argument.kind_of? DateTime
|
107
|
+
output = v
|
108
|
+
end
|
109
|
+
|
110
|
+
@_processor.quote_value(output)
|
111
|
+
end,
|
112
|
+
|
113
|
+
:sql => Proc::new do |v|
|
114
|
+
if v.kind_of? MP::Fluent::Query
|
115
|
+
output = v.build!
|
116
|
+
end
|
117
|
+
|
118
|
+
@_processor.quote_subquery(output)
|
119
|
+
end,
|
120
|
+
|
121
|
+
:and => Proc::new do |v|
|
122
|
+
operator = @_processor.driver.quote_operator(:and)
|
123
|
+
@_processor.process_hash(v, operator)
|
124
|
+
end,
|
125
|
+
|
126
|
+
:or => Proc::new do |v|
|
127
|
+
operator = @_processor.driver.quote_operator(:or)
|
128
|
+
@_processor.process_hash(v, operator)
|
129
|
+
end,
|
130
|
+
}
|
131
|
+
end
|
132
|
+
|
133
|
+
@__calls_cache
|
134
|
+
end
|
135
|
+
|
136
|
+
##
|
137
|
+
# Compiles string.
|
138
|
+
#
|
139
|
+
|
140
|
+
public
|
141
|
+
def compile(string)
|
142
|
+
output = FluentQuery::Compilers::Result::new
|
143
|
+
prefix = self.class::DIRECTIVE_PREFIX
|
144
|
+
buffer = ""
|
145
|
+
|
146
|
+
# Builds compile informations
|
147
|
+
if not @__compile_cache
|
148
|
+
directives = self.class::FORMATTING_DIRECTIVES.map { |s| s.to_s }
|
149
|
+
regexp = Regexp::new("^(" << directives.join("|") << ")(?:[^\w]|$)")
|
150
|
+
|
151
|
+
@__compile_cache = regexp
|
152
|
+
else
|
153
|
+
regexp = @__compile_cache
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
# Splits to by directive separated parts
|
158
|
+
string.split(prefix).each do |part|
|
159
|
+
match = part.match(regexp)
|
160
|
+
|
161
|
+
if match
|
162
|
+
if not buffer.empty?
|
163
|
+
output << buffer
|
164
|
+
end
|
165
|
+
|
166
|
+
output << self.compile_formatting(match[1])
|
167
|
+
buffer = part[match[1].length..-1]
|
168
|
+
else
|
169
|
+
buffer << prefix << part
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
output << buffer
|
174
|
+
|
175
|
+
# Corrects and returns result
|
176
|
+
output.first.replace(output.first[prefix.length..-1]) # strips out initial "%%"
|
177
|
+
return output
|
178
|
+
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|