knjrbfw 0.0.110 → 0.0.111

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +2 -2
  4. data/VERSION +1 -1
  5. data/knjrbfw.gemspec +8 -36
  6. data/lib/knj/autoload.rb +1 -2
  7. data/lib/knj/gtk2_window.rb +7 -7
  8. data/lib/knj/unix_proc.rb +35 -35
  9. metadata +33 -62
  10. data/lib/knj/db.rb +0 -1
  11. data/lib/knj/knjdb/dbtime.rb +0 -35
  12. data/lib/knj/knjdb/drivers/mysql/knjdb_mysql.rb +0 -604
  13. data/lib/knj/knjdb/drivers/mysql/knjdb_mysql_columns.rb +0 -155
  14. data/lib/knj/knjdb/drivers/mysql/knjdb_mysql_indexes.rb +0 -69
  15. data/lib/knj/knjdb/drivers/mysql/knjdb_mysql_sqlspecs.rb +0 -5
  16. data/lib/knj/knjdb/drivers/mysql/knjdb_mysql_tables.rb +0 -443
  17. data/lib/knj/knjdb/drivers/sqlite3/knjdb_sqlite3.rb +0 -184
  18. data/lib/knj/knjdb/drivers/sqlite3/knjdb_sqlite3_columns.rb +0 -177
  19. data/lib/knj/knjdb/drivers/sqlite3/knjdb_sqlite3_indexes.rb +0 -29
  20. data/lib/knj/knjdb/drivers/sqlite3/knjdb_sqlite3_sqlspecs.rb +0 -5
  21. data/lib/knj/knjdb/drivers/sqlite3/knjdb_sqlite3_tables.rb +0 -449
  22. data/lib/knj/knjdb/dump.rb +0 -122
  23. data/lib/knj/knjdb/idquery.rb +0 -109
  24. data/lib/knj/knjdb/libknjdb.rb +0 -797
  25. data/lib/knj/knjdb/libknjdb_java_sqlite3.rb +0 -83
  26. data/lib/knj/knjdb/libknjdb_row.rb +0 -153
  27. data/lib/knj/knjdb/libknjdb_sqlite3_ironruby.rb +0 -69
  28. data/lib/knj/knjdb/query_buffer.rb +0 -87
  29. data/lib/knj/knjdb/revision.rb +0 -342
  30. data/lib/knj/knjdb/sqlspecs.rb +0 -5
  31. data/lib/knj/objects.rb +0 -957
  32. data/lib/knj/process.rb +0 -480
  33. data/lib/knj/process_meta.rb +0 -569
  34. data/spec/db_spec.rb +0 -282
  35. data/spec/db_spec_encoding_test_file.txt +0 -1
  36. data/spec/objects_spec.rb +0 -394
  37. data/spec/process_meta_spec.rb +0 -172
  38. data/spec/process_spec.rb +0 -115
@@ -1,122 +0,0 @@
1
- #This class can be used to make SQL-dumps of databases, tables or however you want it.
2
- class Knj::Db::Dump
3
- #Constructor.
4
- #===Examples
5
- # dump = Knj::Db::Dump.new(:db => db)
6
- def initialize(args)
7
- @args = args
8
- @debug = @args[:debug]
9
- end
10
-
11
- #Method used to update the status.
12
- def update_status
13
- return nil if !@on_status
14
- rows_count = Knj::Locales.number_out(@rows_count, 0)
15
- rows_count_total = Knj::Locales.number_out(@rows_count_total, 0)
16
- percent = (@rows_count.to_f / @rows_count_total.to_f) * 100
17
- percent_text = Knj::Locales.number_out(percent, 1)
18
- @on_status.call(:text => "Dumping table: '#{@table_obj.name}' (#{rows_count}/#{rows_count_total} - #{percent_text}%).")
19
- end
20
-
21
- #Dumps all tables into the given IO.
22
- def dump(io)
23
- print "Going through tables.\n" if @debug
24
- @rows_count = 0
25
-
26
- if @args[:tables]
27
- tables = @args[:tables]
28
- else
29
- tables = @args[:db].tables.list.values
30
- end
31
-
32
- if @on_status
33
- @on_status.call(:text => "Preparing.")
34
-
35
- @rows_count_total = 0
36
- tables.each do |table_obj|
37
- @rows_count_total += table_obj.rows_count
38
- end
39
- end
40
-
41
- tables.each do |table_obj|
42
- table_obj = @args[:db].tables[table_obj] if table_obj.is_a?(String) or table_obj.is_a?(Symbol)
43
- next if table_obj.native?
44
-
45
- #Figure out keys.
46
- @keys = []
47
- table_obj.columns do |col|
48
- @keys << col.name
49
- end
50
-
51
- @table_obj = table_obj
52
- self.update_status
53
- print "Dumping table: '#{table_obj.name}'.\n" if @debug
54
- self.dump_table(io, table_obj)
55
- end
56
- end
57
-
58
- #A block can be executed when a new status occurs.
59
- def on_status(&block)
60
- @on_status = block
61
- end
62
-
63
- #Dumps the given table into the given IO.
64
- def dump_table(io, table_obj)
65
- #Get SQL for creating table and add it to IO.
66
- sqls = @args[:db].tables.create(table_obj.name, table_obj.data, :return_sql => true)
67
- sqls.each do |sql|
68
- io.write("#{sql};\n")
69
- end
70
-
71
-
72
- #Try to find a primary column in the table.
73
- prim_col = nil
74
- table_obj.columns do |col|
75
- if col.primarykey?
76
- prim_col = col
77
- break
78
- end
79
- end
80
-
81
-
82
- #Set up rows and way to fill rows.
83
- rows = []
84
- block_data = proc do |row|
85
- rows << row
86
- @rows_count += 1
87
-
88
- if rows.length >= 1000
89
- self.update_status
90
- self.dump_insert_multi(io, table_obj, rows)
91
- end
92
- end
93
-
94
-
95
- #If a primary column is found then use IDQuery. Otherwise use cloned unbuffered query.
96
- args = {:idquery => prim_col.name.to_sym} if prim_col
97
-
98
-
99
- #Clone the connecting with array-results and execute query.
100
- @args[:db].clone_conn(:result => "array") do |db|
101
- db.select(table_obj.name, nil, args, &block_data)
102
- end
103
-
104
-
105
- #Dump the last rows if any.
106
- self.dump_insert_multi(io, table_obj, rows) if !rows.empty?
107
- end
108
-
109
- #Dumps the given rows from the given table into the given IO.
110
- def dump_insert_multi(io, table_obj, rows)
111
- print "Inserting #{rows.length} into #{table_obj.name}.\n" if @debug
112
- sqls = @args[:db].insert_multi(table_obj.name, rows, :return_sql => true, :keys => @keys)
113
- sqls.each do |sql|
114
- io.write("#{sql};\n")
115
- end
116
-
117
- rows.clear
118
-
119
- #Ensure garbage collection or we might start using A LOT of memory.
120
- GC.start
121
- end
122
- end
@@ -1,109 +0,0 @@
1
- #This class takes a lot of IDs and runs a query against them.
2
- class Knj::Db::Idquery
3
- #An array containing all the IDs that will be looked up.
4
- attr_reader :ids
5
-
6
- #Constructor.
7
- #===Examples
8
- # idq = Knj::Db::Idquery(:db => db, :table => :users)
9
- # idq.ids + [1, 5, 9]
10
- # idq.each do |user|
11
- # print "Name: #{user[:name]}\n"
12
- # end
13
- def initialize(args, &block)
14
- @args = args
15
- @ids = []
16
- @debug = @args[:debug]
17
-
18
- if @args[:query]
19
- @args[:db].q(@args[:query]) do |data|
20
- @args[:col] = data.keys.first if !@args[:col]
21
-
22
- if data.is_a?(Array)
23
- @ids << data.first
24
- else
25
- @ids << data[@args[:col]]
26
- end
27
- end
28
- end
29
-
30
- @args[:col] = :id if !@args[:col]
31
- @args[:size] = 200 if !@args[:size]
32
-
33
- if block
34
- raise "No query was given but a block was." if !@args[:query]
35
- self.each(&block)
36
- end
37
- end
38
-
39
- #Fetches results.
40
- #===Examples
41
- # data = idq.fetch #=> Hash
42
- def fetch
43
- return nil if !@args
44
-
45
- if @res
46
- data = @res.fetch if @res
47
- @res = nil if !data
48
- return data if data
49
- end
50
-
51
- @res = new_res if !@res
52
- if !@res
53
- destroy
54
- return nil
55
- end
56
-
57
- data = @res.fetch
58
- if !data
59
- destroy
60
- return nil
61
- end
62
-
63
- return data
64
- end
65
-
66
- #Yields a block for every result.
67
- #===Examples
68
- # idq.each do |data|
69
- # print "Name: #{data[:name]}\n"
70
- # end
71
- def each
72
- while data = self.fetch
73
- yield(data)
74
- end
75
- end
76
-
77
- private
78
-
79
- #Spawns a new database-result to read from.
80
- def new_res
81
- table_esc = "`#{@args[:db].esc_table(@args[:table])}`"
82
- col_esc = "`#{@args[:db].esc_col(@args[:col])}`"
83
- ids = @ids.shift(@args[:size])
84
-
85
- if ids.empty?
86
- destroy
87
- return nil
88
- end
89
-
90
- ids_sql = Knj::ArrayExt.join(
91
- :arr => ids,
92
- :callback => proc{|val| @args[:db].esc(val)},
93
- :sep => ",",
94
- :surr => "'"
95
- )
96
-
97
- query_str = "SELECT * FROM #{table_esc} WHERE #{table_esc}.#{col_esc} IN (#{ids_sql})"
98
- print "Query: #{query_str}\n" if @debug
99
-
100
- return @args[:db].q(query_str)
101
- end
102
-
103
- #Removes all variables on the object. This is done when no more results are available.
104
- def destroy
105
- @args = nil
106
- @ids = nil
107
- @debug = nil
108
- end
109
- end
@@ -1,797 +0,0 @@
1
- Knj.gem_require([:wref, :datet])
2
-
3
- #A wrapper of several possible database-types.
4
- #
5
- #===Examples
6
- # db = Knj::Db.new(:type => "mysql", :subtype => "mysql2", :db => "mysql", :user => "user", :pass => "password")
7
- # mysql_table = db.tables['mysql']
8
- # name = mysql_table.name
9
- # cols = mysql_table.columns
10
- #
11
- # db = Knj::Db.new(:type => "sqlite3", :path => "some_db.sqlite3")
12
- #
13
- # db.q("SELECT * FROM users") do |data|
14
- # print data[:name]
15
- # end
16
- class Knj::Db
17
- #Autoloader for subclasses..
18
- def self.const_missing(name)
19
- require "#{$knjpath}knjdb/#{name.to_s.downcase}.rb"
20
- raise "Still not defined: '#{name}'." if !Knj::Db.const_defined?(name)
21
- return Knj::Db.const_get(name)
22
- end
23
-
24
- attr_reader :sep_col, :sep_table, :sep_val, :opts, :conn, :conns, :int_types
25
-
26
- def initialize(opts)
27
- require "#{$knjpath}threadhandler"
28
-
29
- self.setOpts(opts) if opts != nil
30
-
31
- @int_types = ["int", "bigint", "tinyint", "smallint", "mediumint"]
32
-
33
- if !@opts[:threadsafe]
34
- require "monitor"
35
- @mutex = Monitor.new
36
- end
37
-
38
- @debug = @opts[:debug]
39
-
40
- self.conn_exec do |driver|
41
- @sep_table = driver.sep_table
42
- @sep_col = driver.sep_col
43
- @sep_val = driver.sep_val
44
- @esc_driver = driver
45
- end
46
- end
47
-
48
- def args
49
- return @opts
50
- end
51
-
52
- def setOpts(arr_opts)
53
- @opts = {}
54
- arr_opts.each do |key, val|
55
- @opts[key.to_sym] = val
56
- end
57
-
58
- if RUBY_PLATFORM == "java"
59
- @opts[:subtype] = "java"
60
- elsif @opts[:type] == "sqlite3" and RUBY_PLATFORM.index("mswin32") != nil
61
- @opts[:subtype] = "ironruby"
62
- end
63
-
64
- self.connect
65
- end
66
-
67
- #Actually connects to the database. This is useually done automatically.
68
- def connect
69
- if @opts[:threadsafe]
70
- @conns = Knj::Threadhandler.new
71
-
72
- @conns.on_spawn_new do
73
- self.spawn
74
- end
75
-
76
- @conns.on_inactive do |data|
77
- data[:obj].close
78
- end
79
-
80
- @conns.on_activate do |data|
81
- data[:obj].reconnect
82
- end
83
- else
84
- @conn = self.spawn
85
- end
86
- end
87
-
88
- #Spawns a new driver (useally done automatically).
89
- #===Examples
90
- # driver_instance = db.spawn
91
- def spawn
92
- raise "No type given (#{@opts.keys.join(",")})." if !@opts[:type]
93
-
94
- fpaths = [
95
- "drivers/#{@opts[:type]}/knjdb_#{@opts[:type]}.rb",
96
- "libknjdb_#{@opts[:type]}.rb"
97
- ]
98
- fpaths.each do |fpath|
99
- rpath = "#{File.dirname(__FILE__)}/#{fpath}"
100
-
101
- if (!@opts.key?(:require) or @opts[:require]) and File.exists?(rpath)
102
- require rpath
103
- break
104
- end
105
- end
106
-
107
- return Kernel.const_get("KnjDB_#{@opts[:type]}").new(self)
108
- end
109
-
110
- #Registers a driver to the current thread.
111
- def get_and_register_thread
112
- raise "KnjDB-object is not in threadding mode." if !@conns
113
-
114
- thread_cur = Thread.current
115
- tid = self.__id__
116
- thread_cur[:knjdb] = {} if !thread_cur[:knjdb]
117
-
118
- if thread_cur[:knjdb][tid]
119
- #An object has already been spawned - free that first to avoid endless "used" objects.
120
- self.free_thread
121
- end
122
-
123
- thread_cur[:knjdb][tid] = @conns.get_and_lock if !thread_cur[:knjdb][tid]
124
-
125
- #If block given then be ensure to free thread after yielding.
126
- if block_given?
127
- begin
128
- yield
129
- ensure
130
- self.free_thread
131
- end
132
- end
133
- end
134
-
135
- #Frees the current driver from the current thread.
136
- def free_thread
137
- thread_cur = Thread.current
138
- tid = self.__id__
139
-
140
- if thread_cur[:knjdb] and thread_cur[:knjdb].key?(tid)
141
- db = thread_cur[:knjdb][tid]
142
- thread_cur[:knjdb].delete(tid)
143
- @conns.free(db) if @conns
144
- end
145
- end
146
-
147
- #Clean up various memory-stuff if possible.
148
- def clean
149
- if @conns
150
- @conns.objects.each do |data|
151
- data[:object].clean if data[:object].respond_to?("clean")
152
- end
153
- elsif @conn
154
- @conn.clean if @conn.respond_to?("clean")
155
- end
156
- end
157
-
158
- #The all driver-database-connections.
159
- def close
160
- @conn.close if @conn
161
- @conns.destroy if @conns
162
-
163
- @conn = nil
164
- @conns = nil
165
- end
166
-
167
- #Clones the current database-connection with possible extra arguments.
168
- def clone_conn(args = {})
169
- conn = Knj::Db.new(@opts.clone.merge(args))
170
-
171
- if block_given?
172
- begin
173
- yield(conn)
174
- ensure
175
- conn.close
176
- end
177
-
178
- return nil
179
- else
180
- return conn
181
- end
182
- end
183
-
184
- #Copies the content of the current database to another instance of Knj::Db.
185
- def copy_to(db, args = {})
186
- data["tables"].each do |table|
187
- table_args = nil
188
- table_args = args["tables"][table["name"].to_s] if args and args["tables"] and args["tables"][table["name"].to_s]
189
- next if table_args and table_args["skip"]
190
- table.delete("indexes") if table.key?("indexes") and args["skip_indexes"]
191
- db.tables.create(table["name"], table)
192
-
193
- limit_from = 0
194
- limit_incr = 1000
195
-
196
- loop do
197
- ins_arr = []
198
- q_rows = self.select(table["name"], {}, {"limit_from" => limit_from, "limit_to" => limit_incr})
199
- while d_rows = q_rows.fetch
200
- col_args = nil
201
-
202
- if table_args and table_args["columns"]
203
- d_rows.each do |col_name, col_data|
204
- col_args = table_args["columns"][col_name.to_s] if table_args and table_args["columns"]
205
- d_rows[col_name] = "" if col_args and col_args["empty"]
206
- end
207
- end
208
-
209
- ins_arr << d_rows
210
- end
211
-
212
- break if ins_arr.empty?
213
-
214
- db.insert_multi(table["name"], ins_arr)
215
- limit_from += limit_incr
216
- end
217
- end
218
- end
219
-
220
- #Returns the data of this database in a hash.
221
- #===Examples
222
- # data = db.data
223
- # tables_hash = data['tables']
224
- def data
225
- tables_ret = []
226
- tables.list.each do |name, table|
227
- tables_ret << table.data
228
- end
229
-
230
- return {
231
- "tables" => tables_ret
232
- }
233
- end
234
-
235
- #Simply inserts data into a table.
236
- #
237
- #===Examples
238
- # db.insert(:users, {:name => "John", :lastname => "Doe"})
239
- # id = db.insert(:users, {:name => "John", :lastname => "Doe"}, :return_id => true)
240
- # sql = db.insert(:users, {:name => "John", :lastname => "Doe"}, :return_sql => true) #=> "INSERT INTO `users` (`name`, `lastname`) VALUES ('John', 'Doe')"
241
- def insert(tablename, arr_insert, args = nil)
242
- sql = "INSERT INTO #{@sep_table}#{tablename}#{@sep_table}"
243
-
244
- if !arr_insert or arr_insert.empty?
245
- #This is the correct syntax for inserting a blank row in MySQL.
246
- if @opts[:type].to_s == "mysql"
247
- sql << " VALUES ()"
248
- elsif @opts[:type].to_s == "sqlite3"
249
- sql << " DEFAULT VALUES"
250
- else
251
- raise "Unknown database-type: '#{@opts[:type]}'."
252
- end
253
- else
254
- sql << " ("
255
-
256
- first = true
257
- arr_insert.each do |key, value|
258
- if first
259
- first = false
260
- else
261
- sql << ", "
262
- end
263
-
264
- sql << "#{@sep_col}#{key}#{@sep_col}"
265
- end
266
-
267
- sql << ") VALUES ("
268
-
269
- first = true
270
- arr_insert.each do |key, value|
271
- if first
272
- first = false
273
- else
274
- sql << ", "
275
- end
276
-
277
- sql << self.sqlval(value)
278
- end
279
-
280
- sql << ")"
281
- end
282
-
283
- return sql if args and args[:return_sql]
284
-
285
- self.conn_exec do |driver|
286
- driver.query(sql)
287
- return driver.lastID if args and args[:return_id]
288
- return nil
289
- end
290
- end
291
-
292
- #Returns the correct SQL-value for the given value. If it is a number, then just the raw number as a string will be returned. nil's will be NULL and strings will have quotes and will be escaped.
293
- def sqlval(val)
294
- return @conn.sqlval(val) if @conn.respond_to?(:sqlval)
295
-
296
- if val.is_a?(Fixnum) or val.is_a?(Integer)
297
- return val.to_s
298
- elsif val == nil
299
- return "NULL"
300
- elsif val.is_a?(Date)
301
- return "#{@sep_val}#{Datet.in(val).dbstr(:time => false)}#{@sep_val}"
302
- elsif val.is_a?(Time) or val.is_a?(DateTime)
303
- return "#{@sep_val}#{Datet.in(val).dbstr}#{@sep_val}"
304
- else
305
- return "#{@sep_val}#{self.escape(val)}#{@sep_val}"
306
- end
307
- end
308
-
309
- #Simply and optimal insert multiple rows into a table in a single query. Uses the drivers functionality if supported or inserts each row manually.
310
- #
311
- #===Examples
312
- # db.insert_multi(:users, [
313
- # {:name => "John", :lastname => "Doe"},
314
- # {:name => "Kasper", :lastname => "Johansen"}
315
- # ])
316
- def insert_multi(tablename, arr_hashes, args = nil)
317
- return false if arr_hashes.empty?
318
-
319
- if @esc_driver.respond_to?(:insert_multi)
320
- if args and args[:return_sql]
321
- return [@esc_driver.insert_multi(tablename, arr_hashes, args)]
322
- end
323
-
324
- self.conn_exec do |driver|
325
- return driver.insert_multi(tablename, arr_hashes, args)
326
- end
327
- else
328
- ret = [] if args and (args[:return_id] or args[:return_sql])
329
- arr_hashes.each do |hash|
330
- if ret
331
- ret << self.insert(tablename, hash, args)
332
- else
333
- self.insert(tablename, hash, args)
334
- end
335
- end
336
-
337
- if ret
338
- return ret
339
- else
340
- return nil
341
- end
342
- end
343
- end
344
-
345
- #Simple updates rows.
346
- #
347
- #===Examples
348
- # db.update(:users, {:name => "John"}, {:lastname => "Doe"})
349
- def update(tablename, arr_update, arr_terms = {}, args = nil)
350
- raise "'arr_update' was not a hash." if !arr_update.is_a?(Hash)
351
- return false if arr_update.empty?
352
-
353
- sql = ""
354
- sql << "UPDATE #{@sep_col}#{tablename}#{@sep_col} SET "
355
-
356
- first = true
357
- arr_update.each do |key, value|
358
- if first
359
- first = false
360
- else
361
- sql << ", "
362
- end
363
-
364
- #Convert dates to valid dbstr.
365
- value = self.date_out(value) if value.is_a?(Datet) or value.is_a?(Time)
366
-
367
- sql << "#{@sep_col}#{key}#{@sep_col} = "
368
- sql << "#{@sep_val}#{@esc_driver.escape(value)}#{@sep_val}"
369
- end
370
-
371
- if arr_terms and arr_terms.length > 0
372
- sql << " WHERE #{self.makeWhere(arr_terms)}"
373
- end
374
-
375
- return sql if args and args[:return_sql]
376
-
377
- self.conn_exec do |driver|
378
- driver.query(sql)
379
- end
380
- end
381
-
382
- #Checks if a given selector exists. If it does, updates it to match data. If not inserts the row.
383
- def upsert(table, selector, data)
384
- row = self.select(table, selector, "limit" => 1).fetch
385
-
386
- if row
387
- self.update(table, data, row)
388
- else
389
- self.insert(table, selector.merge(data))
390
- end
391
- end
392
-
393
- #Makes a select from the given arguments: table-name, where-terms and other arguments as limits and orders. Also takes a block to avoid raping of memory.
394
- def select(tablename, arr_terms = nil, args = nil, &block)
395
- #Set up vars.
396
- sql = ""
397
- args_q = nil
398
- select_sql = "*"
399
-
400
- #Give 'cloned_ubuf' argument to 'q'-method.
401
- if args and args[:cloned_ubuf]
402
- args_q = {:cloned_ubuf => true}
403
- end
404
-
405
- #Set up IDQuery-stuff if that is given in arguments.
406
- if args and args[:idquery]
407
- if args[:idquery] == true
408
- select_sql = "`id`"
409
- col = :id
410
- else
411
- select_sql = "`#{self.esc_col(args[:idquery])}`"
412
- col = args[:idquery]
413
- end
414
- end
415
-
416
- sql = "SELECT #{select_sql} FROM #{@sep_table}#{tablename}#{@sep_table}"
417
-
418
- if arr_terms != nil and !arr_terms.empty?
419
- sql << " WHERE #{self.makeWhere(arr_terms)}"
420
- end
421
-
422
- if args != nil
423
- if args["orderby"]
424
- sql << " ORDER BY #{args["orderby"]}"
425
- end
426
-
427
- if args["limit"]
428
- sql << " LIMIT #{args["limit"]}"
429
- end
430
-
431
- if args["limit_from"] and args["limit_to"]
432
- raise "'limit_from' was not numeric: '#{args["limit_from"]}'." if !(Float(args["limit_from"]) rescue false)
433
- raise "'limit_to' was not numeric: '#{args["limit_to"]}'." if !(Float(args["limit_to"]) rescue false)
434
- sql << " LIMIT #{args["limit_from"]}, #{args["limit_to"]}"
435
- end
436
- end
437
-
438
- #Do IDQuery if given in arguments.
439
- if args and args[:idquery]
440
- res = Knj::Db::Idquery.new(:db => self, :table => tablename, :query => sql, :col => col, &block)
441
- else
442
- res = self.q(sql, args_q, &block)
443
- end
444
-
445
- #Return result if a block wasnt given.
446
- if block
447
- return nil
448
- else
449
- return res
450
- end
451
- end
452
-
453
- #Returns a single row from a database.
454
- #
455
- #===Examples
456
- # row = db.single(:users, {:lastname => "Doe"})
457
- def single(tablename, arr_terms = nil, args = {})
458
- args["limit"] = 1
459
-
460
- #Experienced very weird memory leak if this was not done by block. Maybe bug in Ruby 1.9.2? - knj
461
- self.select(tablename, arr_terms, args) do |data|
462
- return data
463
- end
464
-
465
- return false
466
- end
467
-
468
- alias :selectsingle :single
469
-
470
- #Deletes rows from the database.
471
- #
472
- #===Examples
473
- # db.delete(:users, {:lastname => "Doe"})
474
- def delete(tablename, arr_terms, args = nil)
475
- sql = "DELETE FROM #{@sep_table}#{tablename}#{@sep_table}"
476
-
477
- if arr_terms != nil and !arr_terms.empty?
478
- sql << " WHERE #{self.makeWhere(arr_terms)}"
479
- end
480
-
481
- return sql if args and args[:return_sql]
482
-
483
- self.conn_exec do |driver|
484
- driver.query(sql)
485
- end
486
-
487
- return nil
488
- end
489
-
490
- #Internally used to generate SQL.
491
- #
492
- #===Examples
493
- # sql = db.makeWhere({:lastname => "Doe"}, driver_obj)
494
- def makeWhere(arr_terms, driver = nil)
495
- sql = ""
496
-
497
- first = true
498
- arr_terms.each do |key, value|
499
- if first
500
- first = false
501
- else
502
- sql << " AND "
503
- end
504
-
505
- if value.is_a?(Array)
506
- raise "Array for column '#{key}' was empty." if value.empty?
507
- sql << "#{@sep_col}#{key}#{@sep_col} IN (#{Knj::ArrayExt.join(:arr => value, :sep => ",", :surr => "'", :callback => proc{|ele| self.esc(ele)})})"
508
- elsif value.is_a?(Hash)
509
- raise "Dont know how to handle hash."
510
- else
511
- sql << "#{@sep_col}#{key}#{@sep_col} = #{@sep_val}#{@esc_driver.escape(value)}#{@sep_val}"
512
- end
513
- end
514
-
515
- return sql
516
- end
517
-
518
- #Returns a driver-object based on the current thread and free driver-objects.
519
- #
520
- #===Examples
521
- # db.conn_exec do |driver|
522
- # str = driver.escape('something̈́')
523
- # end
524
- def conn_exec
525
- if tcur = Thread.current and tcur[:knjdb]
526
- tid = self.__id__
527
-
528
- if tcur[:knjdb].key?(tid)
529
- yield(tcur[:knjdb][tid])
530
- return nil
531
- end
532
- end
533
-
534
- if @conns
535
- conn = @conns.get_and_lock
536
-
537
- begin
538
- yield(conn)
539
- return nil
540
- ensure
541
- @conns.free(conn)
542
- end
543
- elsif @conn
544
- @mutex.synchronize do
545
- yield(@conn)
546
- return nil
547
- end
548
- end
549
-
550
- raise "Could not figure out how to find a driver to use?"
551
- end
552
-
553
- #Executes a query and returns the result.
554
- #
555
- #===Examples
556
- # res = db.query('SELECT * FROM users')
557
- # while data = res.fetch
558
- # print data[:name]
559
- # end
560
- def query(string)
561
- if @debug
562
- print "SQL: #{string}\n"
563
-
564
- if @debug.is_a?(Fixnum) and @debug >= 2
565
- print caller.join("\n")
566
- print "\n"
567
- end
568
- end
569
-
570
- self.conn_exec do |driver|
571
- return driver.query(string)
572
- end
573
- end
574
-
575
- #Execute an ubuffered query and returns the result.
576
- #
577
- #===Examples
578
- # db.query_ubuf('SELECT * FROM users') do |data|
579
- # print data[:name]
580
- # end
581
- def query_ubuf(string, &block)
582
- ret = nil
583
-
584
- self.conn_exec do |driver|
585
- ret = driver.query_ubuf(string, &block)
586
- end
587
-
588
- if block
589
- ret.each(&block)
590
- return nil
591
- end
592
-
593
- return ret
594
- end
595
-
596
- #Clones the connection, executes the given block and closes the connection again.
597
- #
598
- #===Examples
599
- # db.cloned_conn do |conn|
600
- # conn.q('SELCET * FROM users') do |data|
601
- # print data[:name]
602
- # end
603
- # end
604
- def cloned_conn(args = nil, &block)
605
- clone_conn_args = {
606
- :threadsafe => false
607
- }
608
-
609
- clone_conn_args.merge!(args[:clone_args]) if args and args[:clone_args]
610
- dbconn = self.clone_conn(clone_conn_args)
611
-
612
- begin
613
- yield(dbconn)
614
- ensure
615
- dbconn.close
616
- end
617
- end
618
-
619
- #Executes a query and returns the result. If a block is given the result is iterated over that block instead and it returns nil.
620
- #
621
- #===Examples
622
- # db.q('SELECT * FROM users') do |data|
623
- # print data[:name]
624
- # end
625
- def q(str, args = nil, &block)
626
- #If the query should be executed in a new connection unbuffered.
627
- if args
628
- if args[:cloned_ubuf]
629
- raise "No block given." if !block
630
-
631
- self.cloned_conn(:clone_args => args[:clone_args]) do |cloned_conn|
632
- ret = cloned_conn.query_ubuf(str)
633
- ret.each(&block)
634
- end
635
-
636
- return nil
637
- else
638
- raise "Invalid arguments given: '#{args}'."
639
- end
640
- end
641
-
642
- ret = self.query(str)
643
-
644
- if block
645
- ret.each(&block)
646
- return nil
647
- end
648
-
649
- return ret
650
- end
651
-
652
- #Yields a query-buffer and flushes at the end of the block given.
653
- def q_buffer(&block)
654
- Knj::Db::Query_buffer.new(:db => self, &block)
655
- return nil
656
- end
657
-
658
- #Returns the last inserted ID.
659
- #
660
- #===Examples
661
- # id = db.last_id
662
- def lastID
663
- self.conn_exec do |driver|
664
- return driver.lastID
665
- end
666
- end
667
-
668
- alias :last_id :lastID
669
-
670
- #Escapes a string to be safe-to-use in a query-string.
671
- #
672
- #===Examples
673
- # db.q("INSERT INTO users (name) VALUES ('#{db.esc('John')}')")
674
- def escape(string)
675
- return @esc_driver.escape(string)
676
- end
677
-
678
- alias :esc :escape
679
-
680
- #Escapes the given string to be used as a column.
681
- def esc_col(str)
682
- return @esc_driver.esc_col(str)
683
- end
684
-
685
- #Escapes the given string to be used as a table.
686
- def esc_table(str)
687
- return @esc_driver.esc_table(str)
688
- end
689
-
690
- #Returns a string which can be used in SQL with the current driver.
691
- #===Examples
692
- # str = db.date_out(Time.now) #=> "2012-05-20 22:06:09"
693
- def date_out(date_obj = Datet.new, args = {})
694
- if @esc_driver.respond_to?(:date_out)
695
- return @esc_driver.date_out(date_obj, args)
696
- end
697
-
698
- return Datet.in(date_obj).dbstr(args)
699
- end
700
-
701
- #Takes a valid date-db-string and converts it into a Datet.
702
- #===Examples
703
- # db.date_in('2012-05-20 22:06:09') #=> 2012-05-20 22:06:09 +0200
704
- def date_in(date_obj)
705
- if @esc_driver.respond_to?(:date_in)
706
- return @esc_driver.date_in(date_obj)
707
- end
708
-
709
- return Datet.in(date_obj)
710
- end
711
-
712
- #Returns the table-module and spawns it if it isnt already spawned.
713
- def tables
714
- if !@tables
715
- require "#{File.dirname(__FILE__)}/drivers/#{@opts[:type]}/knjdb_#{@opts[:type]}_tables" if (!@opts.key?(:require) or @opts[:require])
716
- @tables = Kernel.const_get("KnjDB_#{@opts[:type]}".to_sym).const_get(:Tables).new(
717
- :db => self
718
- )
719
- end
720
-
721
- return @tables
722
- end
723
-
724
- #Returns the columns-module and spawns it if it isnt already spawned.
725
- def cols
726
- if !@cols
727
- require "#{File.dirname(__FILE__)}/drivers/#{@opts[:type]}/knjdb_#{@opts[:type]}_columns" if (!@opts.key?(:require) or @opts[:require])
728
- @cols = Kernel.const_get("KnjDB_#{@opts[:type]}".to_sym).const_get(:Columns).new(
729
- :db => self
730
- )
731
- end
732
-
733
- return @cols
734
- end
735
-
736
- #Returns the index-module and spawns it if it isnt already spawned.
737
- def indexes
738
- if !@indexes
739
- require "#{File.dirname(__FILE__)}/drivers/#{@opts[:type]}/knjdb_#{@opts[:type]}_indexes" if (!@opts.key?(:require) or @opts[:require])
740
- @indexes = Kernel.const_get("KnjDB_#{@opts[:type]}".to_sym).const_get(:Indexes).new(
741
- :db => self
742
- )
743
- end
744
-
745
- return @indexes
746
- end
747
-
748
- #Returns the SQLSpec-module and spawns it if it isnt already spawned.
749
- def sqlspecs
750
- if !@sqlspecs
751
- require "#{File.dirname(__FILE__)}/drivers/#{@opts[:type]}/knjdb_#{@opts[:type]}_sqlspecs" if (!@opts.key?(:require) or @opts[:require])
752
- @sqlspecs = Kernel.const_get("KnjDB_#{@opts[:type]}".to_sym).const_get(:Sqlspecs).new(
753
- :db => self
754
- )
755
- end
756
-
757
- return @sqlspecs
758
- end
759
-
760
- #Beings a transaction and commits when the block ends.
761
- #
762
- #===Examples
763
- # db.transaction do |db|
764
- # db.insert(:users, {:name => "John"})
765
- # db.insert(:users, {:name => "Kasper"})
766
- # end
767
- def transaction(&block)
768
- self.conn_exec do |driver|
769
- driver.transaction(&block)
770
- end
771
- end
772
-
773
- #Optimizes all tables in the database.
774
- def optimize(args = nil)
775
- STDOUT.puts "Beginning optimization of database." if @debug or (args and args[:debug])
776
- self.tables.list do |table|
777
- STDOUT.puts "Optimizing table: '#{table.name}'." if @debug or (args and args[:debug])
778
- table.optimize
779
- end
780
-
781
- return nil
782
- end
783
-
784
- #Proxies the method to the driver.
785
- #
786
- #===Examples
787
- # db.method_on_driver
788
- def method_missing(method_name, *args)
789
- self.conn_exec do |driver|
790
- if driver.respond_to?(method_name.to_sym)
791
- return driver.send(method_name, *args)
792
- end
793
- end
794
-
795
- raise "Method not found: #{method_name}"
796
- end
797
- end