fluent-query 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ module FluentQuery
4
+ module Compilers
5
+
6
+ ##
7
+ # Query compiler result. Aka compiled string.
8
+ #
9
+
10
+ class Result < ::Array
11
+
12
+ ##
13
+ # Completes the compiled string to final one.
14
+ #
15
+
16
+ def complete(*args)
17
+ result = ""
18
+
19
+ self.each do |v|
20
+ if v.kind_of? Proc
21
+ result << v.call(args.shift)
22
+ else
23
+ result << v.to_s
24
+ end
25
+ end
26
+
27
+ return result
28
+ end
29
+
30
+ end
31
+ end
32
+ end
33
+
@@ -0,0 +1,316 @@
1
+ # encoding: utf-8
2
+ require "fluent-query/result"
3
+ require "fluent-query/driver"
4
+ require "fluent-query/exception"
5
+
6
+ module FluentQuery
7
+
8
+ ##
9
+ # Represents query target connection.
10
+ #
11
+
12
+ class Connection
13
+
14
+ ##
15
+ # Driver instance associated to the connection object.
16
+ #
17
+
18
+ @_driver
19
+
20
+ ##
21
+ # Holds driver class information.
22
+ #
23
+
24
+ @_driver_class
25
+
26
+ ##
27
+ # Connection settings.
28
+ #
29
+
30
+ @_settings
31
+
32
+ ##
33
+ # Indicates, connection is open.
34
+ #
35
+
36
+ @_open
37
+
38
+ ##
39
+ # Indicates debug mode.
40
+ #
41
+
42
+ @_debug
43
+
44
+ ##
45
+ # Initializes the connection.
46
+ #
47
+ # Be warn, initializer call opening the connection immediately on
48
+ # the driver, but if driver is lazy, it will open the connection
49
+ # at the moment in which it will want to do it.
50
+ #
51
+
52
+ public
53
+ def initialize(driver_class, settings = nil, open = true)
54
+
55
+ # Analyses
56
+
57
+ driver = driver_class::new(self)
58
+
59
+ if not driver.kind_of? FluentQuery::Driver
60
+ raise FluentQuery::Exception::new("Driver must be subclass of the 'FluentQuery::Driver' class.")
61
+ end
62
+
63
+ # Assigns
64
+
65
+ @_driver_class = driver_class
66
+ @_settings = settings
67
+ @_open = false
68
+ @_debug = false
69
+
70
+ # Opens if required
71
+
72
+ if open
73
+ @_driver = driver
74
+ self.open!
75
+ end
76
+
77
+ end
78
+
79
+ ##
80
+ # Catches missing methods calls.
81
+ #
82
+ # Asks the driver if method call is relevant for it, of it is,
83
+ # performs it on it.
84
+ #
85
+
86
+ public
87
+ def method_missing(sym, *args, &block)
88
+
89
+ # Checks if connection is in open state
90
+ if not @_open
91
+ raise FluentQuery::Exception::new("Connection is closed.")
92
+ end
93
+
94
+ ##
95
+
96
+ driver = self.driver
97
+
98
+ if driver.relevant_method? sym
99
+ return __query_call(sym, *args, &block)
100
+ else
101
+ raise FluentQuery::Exception::new("Method '" << sym.to_s << "' isn't implemented by associated FluentQuery::Driver or FluentQuery::Connection object.")
102
+ end
103
+ end
104
+
105
+ ##
106
+ # Sets debug mode.
107
+ #
108
+ # Currently two are supported:
109
+ # * false, which turn debugging of
110
+ # * :dump_all which puts all queries to the output
111
+ #
112
+
113
+ public
114
+ def set_debug(mode)
115
+ @_debug = mode
116
+ end
117
+
118
+ ##
119
+ # Generates query object from free query string.
120
+ #
121
+ # But this free query string still will be treated as string only
122
+ # in the final query.
123
+ #
124
+
125
+ public
126
+ def query(*args, &block)
127
+ query = self._new_query_object
128
+
129
+ # Calls given block in query context.
130
+ if block
131
+ result = query.instance_eval(&block)
132
+ else
133
+ result = query
134
+ end
135
+
136
+ return query
137
+ end
138
+
139
+ ##
140
+ # Returns the driver object.
141
+ #
142
+
143
+ public
144
+ def driver
145
+
146
+ # Checks if connection is in open state
147
+ if @_driver.nil?
148
+ @_driver = @_driver_class::new(self)
149
+ end
150
+
151
+ return @_driver
152
+ end
153
+
154
+ ##
155
+ # Opens the connection.
156
+ #
157
+
158
+ public
159
+ def open!(settings = nil)
160
+
161
+ if @_open
162
+ raise FluentQuery::Exception::new("Connection is already open.")
163
+ end
164
+
165
+ ##
166
+
167
+ if (settings == nil) and @_settings
168
+ settings = @_settings
169
+ elsif settings == nil
170
+ raise FluentQuery::Exception::new("Connection settings hasn't been set or given to the #open method.")
171
+ end
172
+
173
+ self.driver.open_connection(settings)
174
+
175
+ ##
176
+
177
+ @_open = true
178
+
179
+ end
180
+
181
+ ##
182
+ # Closes the connection.
183
+ #
184
+
185
+ public
186
+ def close!
187
+ if @_driver
188
+ self.driver.close_connection!
189
+ @_driver = nil
190
+ end
191
+
192
+ @_open = false
193
+ end
194
+
195
+ ##
196
+ # Executes query.
197
+ #
198
+
199
+ public
200
+ def execute(query)
201
+
202
+ # Checks if connection is in open state
203
+ if not @_open
204
+ raise FluentQuery::Exception::new("Connection is closed.")
205
+ end
206
+
207
+ # If query is fluent query object, executes it
208
+ if query.kind_of? FluentQuery::Query
209
+ result = query.execute!
210
+ else
211
+ if @_debug == :dump_all
212
+ puts query
213
+ end
214
+
215
+ result = self.driver.execute(query)
216
+ end
217
+
218
+ # Wraps driver result to result class
219
+ result = FluentQuery::Result::new(result)
220
+
221
+ return result
222
+
223
+ end
224
+
225
+ ##
226
+ # Executes query and returns count of changed/inserted rows.
227
+ #
228
+
229
+ public
230
+ def do(query)
231
+
232
+ # Checks if connection is in open state
233
+ if not @_open
234
+ raise FluentQuery::Exception::new("Connection is closed.")
235
+ end
236
+
237
+ # If query is fluent query object, executes it
238
+ if query.kind_of? FluentQuery::Query
239
+ result = query.do!
240
+ else
241
+ if @_debug == :dump_all
242
+ puts query
243
+ end
244
+
245
+ result = self.driver.do(query)
246
+ end
247
+
248
+ return result
249
+
250
+ end
251
+
252
+ ##
253
+ # Do in transaction context.
254
+ #
255
+
256
+ public
257
+ def transaction(&block)
258
+ self.begin
259
+ block.call
260
+ self.commit
261
+ end
262
+
263
+
264
+
265
+ #####
266
+
267
+ ##
268
+ # Handles built-in shortcut.
269
+ #
270
+
271
+ private
272
+ def __handle_shortcut(sym, *args, &block)
273
+ result = __query_call(sym, *args, &block)
274
+
275
+ if (not args) or (args.length <= 0)
276
+ result = result.execute!
277
+ end
278
+
279
+ return result
280
+ end
281
+
282
+ ##
283
+ # Performs query initiating call.
284
+ #
285
+
286
+ private
287
+ def __query_call(sym, *args, &block)
288
+ query = self._new_query_object
289
+
290
+ # Executes query conditionally. If query isn't suitable for
291
+ # executing, sends the symbol to it and returns call result.
292
+
293
+ query.send(sym, *args)
294
+
295
+ # Calls given block in query context.
296
+
297
+ if block
298
+ result = query.instance_eval(&block)
299
+ else
300
+ result = query
301
+ end
302
+
303
+ return result
304
+ end
305
+
306
+ ##
307
+ # Returns new query object.
308
+ #
309
+
310
+ protected
311
+ def _new_query_object
312
+ self.driver.query_class::new(self)
313
+ end
314
+ end
315
+ end
316
+
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+ require "hash-utils/string"
3
+ require "hashie/mash"
4
+
5
+ module FluentQuery
6
+
7
+ ##
8
+ # Represents data hash.
9
+ #
10
+ # In fact, it's common Hash class extended by method which allow
11
+ # access its fields by "object way".
12
+ #
13
+
14
+ class Data < ::Hashie::Mash
15
+ end
16
+
17
+ end
@@ -0,0 +1,279 @@
1
+ # encoding: utf-8
2
+ require "abstract"
3
+
4
+ module FluentQuery
5
+
6
+ ##
7
+ # Represents abstract query driver.
8
+ # @abstract
9
+ #
10
+
11
+ class Driver
12
+
13
+ ##
14
+ # Holds connection associated to this driver instance.
15
+ #
16
+
17
+ @connection
18
+ attr_reader :connection
19
+
20
+ ##
21
+ # Initializes driver.
22
+ #
23
+
24
+ public
25
+ def initialize(connection)
26
+ if self.instance_of? FluentQuery::Driver
27
+ not_implemented
28
+ end
29
+
30
+ @connection = connection
31
+ end
32
+
33
+ #####
34
+
35
+ ##
36
+ # Indicates, method is relevant for the driver.
37
+ # @abstract
38
+ #
39
+
40
+ public
41
+ def relevant_method?(name)
42
+ not_implemented
43
+ end
44
+
45
+
46
+ ##
47
+ # Indicates token is known.
48
+ # @abstract
49
+ #
50
+
51
+ public
52
+ def known_token?(group, token_name)
53
+ not_implemented
54
+ end
55
+
56
+ ##
57
+ # Indicates, token is operator.
58
+ # @abstract
59
+ #
60
+
61
+ public
62
+ def operator_token?(token_name)
63
+ not_implemented
64
+ end
65
+
66
+ ##
67
+ # Returns operator string according to operator symbol.
68
+ # @abstract
69
+ #
70
+
71
+ public
72
+ def quote_operator(operator)
73
+ not_implemented
74
+ end
75
+
76
+ ##
77
+ # Returns correct equality operator for given datatype.
78
+ #
79
+ # Must handle two modes:
80
+ # * "assigning" which classicaly keeps for example the '=' operator,
81
+ # * "comparing" which sets for example 'IS' operator for booleans.
82
+ #
83
+ # @abstract
84
+ #
85
+
86
+ public
87
+ def quote_equality(datatype, mode = :comparing)
88
+ not_implemented
89
+ end
90
+
91
+ ##
92
+ # Indicates which query subclass to use.
93
+ # @abstract
94
+ #
95
+
96
+ public
97
+ def query_class
98
+ not_implemented
99
+ end
100
+
101
+ ##
102
+ # Builds given query.
103
+ # @abstract
104
+ #
105
+
106
+ public
107
+ def build_query(query)
108
+ not_implemented
109
+ end
110
+
111
+ ##
112
+ # Returns preparation placeholder according to given
113
+ # library placeholder.
114
+ #
115
+ # @abstract
116
+ #
117
+
118
+ public
119
+ def quote_placeholder(placeholder)
120
+ not_implemented
121
+ end
122
+
123
+
124
+ ##### QUOTING
125
+
126
+ ##
127
+ # Quotes string.
128
+ # @abstract
129
+ #
130
+
131
+ public
132
+ def quote_string(string)
133
+ not_implemented
134
+ end
135
+
136
+ ##
137
+ # Quoting integer.
138
+ # @abstract
139
+ #
140
+
141
+ public
142
+ def quote_integer(integer)
143
+ not_implemented
144
+ end
145
+
146
+ ##
147
+ # Quotes float.
148
+ # @abstract
149
+ #
150
+
151
+ public
152
+ def quote_float(float)
153
+ not_implemented
154
+ end
155
+
156
+ ##
157
+ # Quotes field by field quoting.
158
+ # @abstract
159
+ #
160
+
161
+ public
162
+ def quote_identifier(field)
163
+ not_implemented
164
+ end
165
+
166
+ ##
167
+ # Creates system-dependent NULL.
168
+ # @abstract
169
+ #
170
+
171
+ public
172
+ def null
173
+ not_implemented
174
+ end
175
+
176
+ ##
177
+ # Quotes system-dependent boolean value.
178
+ # @abstract
179
+ #
180
+
181
+ public
182
+ def quote_boolean(boolean)
183
+ not_implemented
184
+ end
185
+
186
+ ##
187
+ # Quotes system-dependent date value.
188
+ # @abstract
189
+ #
190
+
191
+ public
192
+ def quote_date_time(date)
193
+ not_implemented
194
+ end
195
+
196
+ ##
197
+ # Quotes system-dependent subquery.
198
+ # @abstract
199
+ #
200
+
201
+ public
202
+ def quote_subquery(subquery)
203
+ not_implemented
204
+ end
205
+
206
+
207
+
208
+ ##### EXECUTING
209
+
210
+ ##
211
+ # Opens the connection.
212
+ #
213
+ # It's lazy, so it will open connection before first request through
214
+ # {@link native_connection()} method.
215
+ #
216
+ # @abstract
217
+ #
218
+
219
+ public
220
+ def open_connection(settings)
221
+ not_implemented
222
+ end
223
+
224
+ ##
225
+ # Returns native connection.
226
+ # @abstract
227
+ #
228
+
229
+ public
230
+ def native_connection
231
+ not_implemented
232
+ end
233
+
234
+ ##
235
+ # Closes the connection.
236
+ # @abstract
237
+ #
238
+
239
+ public
240
+ def close_connection!
241
+ not_implemented
242
+ end
243
+
244
+ ##
245
+ # Executes the query.
246
+ # @abstract
247
+ #
248
+
249
+ public
250
+ def execute(query)
251
+ not_implemented
252
+ end
253
+
254
+ ##
255
+ # Executes the query and returns count of the changed/inserted rows.
256
+ # @abstract
257
+ #
258
+
259
+ public
260
+ def do(query)
261
+ not_implemented
262
+ end
263
+
264
+ ##
265
+ # Generates prepared query. Should be noted, if driver doesn't
266
+ # support query preparing, it should be +not_implemented+ and
267
+ # unimplemented.
268
+ #
269
+ # @abstract
270
+ #
271
+
272
+ public
273
+ def prepare(query)
274
+ not_implemented
275
+ end
276
+
277
+ end
278
+ end
279
+