baza 0.0.13 → 0.0.14

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.
@@ -1,50 +1,50 @@
1
1
  class Baza::Driver::Sqlite3::Tables
2
2
  attr_reader :db, :driver
3
-
3
+
4
4
  def initialize(args)
5
5
  @args = args
6
6
  @db = @args[:db]
7
-
7
+
8
8
  @list_mutex = Mutex.new
9
9
  @list = Wref_map.new
10
10
  end
11
-
11
+
12
12
  def [](table_name)
13
13
  table_name = table_name.to_sym
14
-
14
+
15
15
  begin
16
16
  ret = @list[table_name]
17
17
  return ret
18
18
  rescue Wref::Recycled
19
19
  #ignore.
20
20
  end
21
-
21
+
22
22
  self.list do |table_obj|
23
23
  return table_obj if table_obj.name == table_name
24
24
  end
25
-
25
+
26
26
  raise Errno::ENOENT, "Table was not found: #{table_name}."
27
27
  end
28
-
28
+
29
29
  def list
30
30
  ret = {} unless block_given?
31
-
31
+
32
32
  @list_mutex.synchronize do
33
33
  q_tables = @db.select("sqlite_master", {"type" => "table"}, {:orderby => "name"}) do |d_tables|
34
34
  next if d_tables[:name] == "sqlite_sequence"
35
-
35
+
36
36
  tname = d_tables[:name].to_sym
37
37
  obj = @list.get!(tname)
38
-
38
+
39
39
  if !obj
40
40
  obj = Baza::Driver::Sqlite3::Tables::Table.new(
41
- :db => @db,
42
- :data => d_tables,
43
- :tables => self
41
+ db: @db,
42
+ data: d_tables,
43
+ tables: self
44
44
  )
45
45
  @list[tname] = obj
46
46
  end
47
-
47
+
48
48
  if block_given?
49
49
  yield(obj)
50
50
  else
@@ -52,56 +52,61 @@ class Baza::Driver::Sqlite3::Tables
52
52
  end
53
53
  end
54
54
  end
55
-
55
+
56
56
  if block_given?
57
57
  return nil
58
58
  else
59
59
  return ret
60
60
  end
61
61
  end
62
-
62
+
63
+ def exists_in_list? table
64
+ @list.key?(table.name)
65
+ end
66
+
63
67
  def remove_from_list(table)
68
+ raise "Table doesnt exist: '#{table.name}'." unless @list.key?(table.name)
64
69
  @list.delete(table.name)
65
70
  end
66
-
71
+
67
72
  def add_to_list(table)
68
- raise "Already exists: '#{table.name}'." if @list.key?(table.name) and @list[table.name].__id__ != table.__id__
73
+ raise "Already exists: '#{table.name}'." if @list.key?(table.name) && @list[table.name].__id__ != table.__id__
69
74
  @list[table.name] = table
70
75
  end
71
-
76
+
72
77
  CREATE_ALLOWED_KEYS = [:indexes, :columns]
73
78
  def create(name, data, args = nil)
74
79
  data.each do |key, val|
75
80
  raise "Invalid key: '#{key}' (#{key.class.name})." if !CREATE_ALLOWED_KEYS.include?(key)
76
81
  end
77
-
82
+
78
83
  sql = "CREATE TABLE `#{name}` ("
79
-
84
+
80
85
  first = true
81
86
  data[:columns].each do |col_data|
82
87
  sql << ", " if !first
83
88
  first = false if first
84
89
  sql << @db.cols.data_sql(col_data)
85
90
  end
86
-
91
+
87
92
  sql << ")"
88
-
93
+
89
94
  if args and args[:return_sql]
90
95
  ret = [sql]
91
96
  else
92
97
  @db.query(sql)
93
98
  end
94
-
99
+
95
100
  if data.key?(:indexes) and data[:indexes]
96
101
  table_obj = self[name]
97
-
102
+
98
103
  if args and args[:return_sql]
99
104
  ret += table_obj.create_indexes(data[:indexes], :return_sql => true)
100
105
  else
101
106
  table_obj.create_indexes(data[:indexes])
102
107
  end
103
108
  end
104
-
109
+
105
110
  if args and args[:return_sql]
106
111
  return ret
107
112
  else
@@ -112,111 +117,115 @@ end
112
117
 
113
118
  class Baza::Driver::Sqlite3::Tables::Table
114
119
  attr_reader :name, :type
115
-
120
+
116
121
  def initialize(args)
117
122
  @db = args[:db]
118
123
  @data = args[:data]
119
124
  @name = @data[:name].to_sym
120
125
  @type = @data[:type].to_sym
121
126
  @tables = args[:tables]
122
-
127
+
123
128
  @list = Wref_map.new
124
129
  @indexes_list = Wref_map.new
125
130
  end
126
-
131
+
127
132
  def maxlength
128
133
  return @data[:maxlength]
129
134
  end
130
-
135
+
131
136
  def reload
132
- @data = @db.select("sqlite_master", {"type" => "table", "name" => self.name}, {:orderby => "name"}).fetch
137
+ @data = @db.select("sqlite_master", {type: "table", name: name}, {:orderby => "name"}).fetch
133
138
  end
134
-
139
+
135
140
  def rows_count
136
- data = @db.q("SELECT COUNT(*) AS count FROM `#{self.name}`").fetch
141
+ data = @db.q("SELECT COUNT(*) AS count FROM `#{name}`").fetch
137
142
  return data[:count].to_i
138
143
  end
139
-
144
+
140
145
  #Drops the table from the database.
141
146
  def drop
142
- raise "Cant drop native table: '#{self.name}'." if self.native?
143
- @db.query("DROP TABLE `#{self.name}`")
144
- @tables.remove_from_list(self)
147
+ raise "Cant drop native table: '#{name}'." if native?
148
+ @db.query("DROP TABLE `#{name}`")
149
+ @tables.remove_from_list(self) if @tables.exists_in_list?(self)
145
150
  end
146
-
151
+
147
152
  #Returns true if the table is safe to drop.
148
153
  def native?
149
- return true if self.name.to_s == "sqlite_sequence"
154
+ return true if name.to_s == "sqlite_sequence"
150
155
  return false
151
156
  end
152
-
157
+
153
158
  def optimize
154
- raise "stub!"
159
+ # Not possible in SQLite3.
155
160
  end
156
-
161
+
157
162
  def rename(newname)
158
163
  newname = newname.to_sym
159
-
164
+
160
165
  @tables.remove_from_list(self)
161
- self.clone(newname, :return_table => false)
162
- self.drop
166
+ newtable = clone(newname)
167
+ @db.tables.remove_from_list(newtable)
168
+ drop
163
169
  @data[:name] = newname
164
170
  @name = newname
165
171
  @tables.add_to_list(self)
166
-
167
- #Rename table on all columns.
168
- #FIXME: This should only be done for columns that exists in memory. However a reference to the table should not be set, at this would force the table to stay in memory, when the column is still referenced...
169
- self.columns.each do |name, col|
170
- col.args[:table_name] = newname
172
+
173
+ #Rename table on all columns and indexes.
174
+ @list.each do |name, column|
175
+ column.args[:table_name] = newname
176
+ end
177
+
178
+ @indexes_list.each do |name, index|
179
+ index.args[:table_name] = newname
171
180
  end
172
181
  end
173
-
182
+
174
183
  def truncate
175
- @db.query("DELETE FROM `#{self.name}` WHERE 1=1")
184
+ @db.query("DELETE FROM `#{name}` WHERE 1=1")
176
185
  return nil
177
186
  end
178
-
187
+
179
188
  def table
180
189
  return @db.tables[@table_name]
181
190
  end
182
-
191
+
183
192
  def column(name)
184
193
  list = self.columns
185
194
  return list[name] if list[name]
186
195
  raise Errno::ENOENT.new("Column not found: #{name}.")
187
196
  end
188
-
197
+
189
198
  def columns
190
199
  @db.cols
191
200
  ret = {}
192
-
201
+
193
202
  @db.q("PRAGMA table_info(`#{@db.esc_table(self.name)}`)") do |d_cols|
194
203
  name = d_cols[:name].to_sym
195
204
  obj = @list.get!(name)
196
-
205
+
197
206
  if !obj
198
207
  obj = Baza::Driver::Sqlite3::Columns::Column.new(
199
- :table_name => self.name,
200
- :db => @db,
201
- :data => d_cols
208
+ table_name: self.name,
209
+ db: @db,
210
+ data: d_cols
202
211
  )
203
212
  @list[name] = obj
204
213
  end
205
-
214
+
206
215
  if block_given?
207
216
  yield(obj)
208
217
  else
209
218
  ret[name] = obj
210
219
  end
211
220
  end
212
-
221
+
213
222
  if block_given?
214
223
  return nil
215
224
  else
216
225
  return ret
217
226
  end
218
227
  end
219
-
228
+
220
229
  def create_columns(col_arr)
221
230
  col_arr.each do |col_data|
222
231
  #if col_data.key?("after")
@@ -226,35 +235,35 @@ class Baza::Driver::Sqlite3::Tables::Table
226
235
  #end
227
236
  end
228
237
  end
229
-
238
+
230
239
  def create_column_programmatic(col_data)
231
240
  temp_name = "temptable_#{Time.now.to_f.to_s.hash}"
232
241
  cloned_tabled = self.clone(temp_name)
233
242
  cols_cur = self.columns
234
243
  @db.query("DROP TABLE `#{self.name}`")
235
-
244
+
236
245
  sql = "CREATE TABLE `#{self.name}` ("
237
246
  first = true
238
247
  cols_cur.each do |name, col|
239
248
  sql << ", " if !first
240
249
  first = false if first
241
250
  sql << @db.cols.data_sql(col.data)
242
-
251
+
243
252
  if col_data[:after] and col_data[:after] == name
244
253
  sql << ", #{@db.cols.data_sql(col_data)}"
245
254
  end
246
255
  end
247
256
  sql << ");"
248
257
  @db.query(sql)
249
-
258
+
250
259
  sql = "INSERT INTO `#{self.name}` SELECT "
251
260
  first = true
252
261
  cols_cur.each do |name, col|
253
262
  sql << ", " if !first
254
263
  first = false if first
255
-
264
+
256
265
  sql << "`#{name}`"
257
-
266
+
258
267
  if col_data[:after] and col_data[:after] == name
259
268
  sql << ", ''"
260
269
  end
@@ -263,52 +272,66 @@ class Baza::Driver::Sqlite3::Tables::Table
263
272
  @db.query(sql)
264
273
  @db.query("DROP TABLE `#{temp_name}`")
265
274
  end
266
-
275
+
267
276
  def clone(newname, args = nil)
268
277
  raise "Invalid name." if newname.to_s.strip.length <= 0
269
- cols_cur = self.columns
270
-
278
+
271
279
  sql = "CREATE TABLE `#{newname}` ("
272
280
  first = true
273
- cols_cur.each do |name, col|
274
- sql << ", " if !first
281
+ columns.each do |name, col|
282
+ sql << ", " unless first
275
283
  first = false if first
276
284
  sql << @db.cols.data_sql(col.data)
277
285
  end
278
-
286
+
279
287
  sql << ");"
280
288
  @db.query(sql)
281
-
282
- sql = "INSERT INTO `#{newname}` SELECT * FROM `#{self.name}`"
283
- @db.query(sql)
284
-
285
- if args and args[:return_table] == false
289
+ @db.query("INSERT INTO `#{newname}` SELECT * FROM `#{name}`")
290
+
291
+ indexes_to_create = []
292
+ new_table = @db.tables[newname.to_sym]
293
+ indexes.each do |name, index|
294
+ index_name = name.to_s
295
+
296
+ if @db.opts[:index_append_table_name] && match = index_name.match(/\A(.+?)__(.+)\Z/)
297
+ index_name = match[2]
298
+ end
299
+
300
+ create_data = index.data
301
+ create_data[:name] = index_name
302
+
303
+ indexes_to_create << create_data
304
+ end
305
+
306
+ new_table.create_indexes(indexes_to_create)
307
+
308
+ if args && args[:return_table] == false
286
309
  return nil
287
310
  else
288
- return @db.tables[newname]
311
+ return new_table
289
312
  end
290
313
  end
291
-
314
+
292
315
  def copy(args = {})
293
316
  temp_name = "temptable_#{Time.now.to_f.to_s.hash}"
294
317
  cloned_tabled = self.clone(temp_name)
295
318
  cols_cur = self.columns
296
319
  @db.query("DROP TABLE `#{self.name}`")
297
-
320
+
298
321
  sql = "CREATE TABLE `#{self.name}` ("
299
322
  first = true
300
323
  cols_cur.each do |name, col|
301
324
  next if args[:drops] and args[:drops].index(name) != nil
302
-
325
+
303
326
  sql << ", " if !first
304
327
  first = false if first
305
-
328
+
306
329
  if args.key?(:alter_columns) and args[:alter_columns][name.to_sym]
307
330
  sql << @db.cols.data_sql(args[:alter_columns][name.to_sym])
308
331
  else
309
332
  sql << @db.cols.data_sql(col.data)
310
333
  end
311
-
334
+
312
335
  if args[:new]
313
336
  args[:new].each do |col_data|
314
337
  if col_data[:after] and col_data[:after] == name
@@ -319,17 +342,17 @@ class Baza::Driver::Sqlite3::Tables::Table
319
342
  end
320
343
  sql << ");"
321
344
  @db.query(sql)
322
-
345
+
323
346
  sql = "INSERT INTO `#{self.name}` SELECT "
324
347
  first = true
325
348
  cols_cur.each do |name, col|
326
349
  next if args[:drops] and args[:drops].index(name) != nil
327
-
350
+
328
351
  sql << ", " if !first
329
352
  first = false if first
330
-
353
+
331
354
  sql << "`#{name}`"
332
-
355
+
333
356
  if args[:news]
334
357
  args[:news].each do |col_data|
335
358
  if col_data[:after] and col_data[:after] == name
@@ -338,146 +361,152 @@ class Baza::Driver::Sqlite3::Tables::Table
338
361
  end
339
362
  end
340
363
  end
341
-
364
+
342
365
  sql << " FROM `#{temp_name}`"
343
366
  @db.query(sql)
344
367
  @db.query("DROP TABLE `#{temp_name}`")
345
368
  end
346
-
347
- def index(name)
348
- name = name.to_sym
349
-
369
+
370
+ def index index_name
371
+ index_name = index_name.to_sym
372
+
350
373
  begin
351
- return @indexes_list[name]
374
+ return @indexes_list[index_name]
352
375
  rescue Wref::Recycled
353
376
  if @db.opts[:index_append_table_name]
354
- tryname = "#{self.name}__#{name}"
355
-
377
+ tryname = "#{name}__#{index_name}"
378
+
356
379
  begin
357
380
  return @indexes_list[tryname]
358
381
  rescue Wref::Recycled
359
382
  #ignore.
360
383
  end
361
- else
362
- #ignore
363
384
  end
364
385
  end
365
-
366
- self.indexes do |index|
367
- return index if index.name.to_s == name
386
+
387
+ indexes do |index|
388
+ if index.name.to_s == "#{name}__#{index_name}"
389
+ return index
390
+ end
391
+
392
+ return index if index.name.to_s == index_name.to_s
368
393
  end
369
-
370
- raise Errno::ENOENT.new("Index not found: #{name}.")
394
+
395
+ raise Errno::ENOENT, "Index not found: #{index_name}."
371
396
  end
372
-
397
+
373
398
  def indexes
374
399
  @db.indexes
375
400
  ret = {} unless block_given?
376
-
377
- @db.q("PRAGMA index_list(`#{@db.esc_table(self.name)}`)") do |d_indexes|
401
+
402
+ @db.q("PRAGMA index_list(`#{@db.esc_table(name)}`)") do |d_indexes|
378
403
  next if d_indexes[:Key_name] == "PRIMARY"
379
-
380
404
  obj = @indexes_list.get!(d_indexes[:name])
381
-
382
- if !obj
383
- if @db.opts[:index_append_table_name]
384
- match_name = d_indexes[:name].match(/__(.+)$/)
385
-
386
- if match_name
387
- name = match_name[1].to_sym
388
- else
389
- name = d_indexes[:name].to_sym
390
- end
391
- else
392
- name = d_indexes[:name].to_sym
393
- end
394
-
405
+
406
+ unless obj
395
407
  obj = Baza::Driver::Sqlite3::Indexes::Index.new(
396
- :table_name => self.name,
397
- :db => @db,
398
- :data => d_indexes
408
+ table_name: name,
409
+ db: @db,
410
+ data: d_indexes
399
411
  )
400
- obj.columns << name
412
+
401
413
  @indexes_list[d_indexes[:name].to_sym] = obj
414
+
415
+ # Get columns from index.
416
+ index_master_data = @db.single(:sqlite_master, type: "index", name: d_indexes[:name])
417
+ parse_columns_from_sql(index_master_data[:sql]).each do |column|
418
+ obj.columns << column
419
+ end
402
420
  end
403
-
421
+
404
422
  if block_given?
405
423
  yield(obj)
406
424
  else
407
425
  ret[d_indexes[:name].to_sym] = obj
408
426
  end
409
427
  end
410
-
428
+
411
429
  if block_given?
412
430
  return nil
413
431
  else
414
432
  return ret
415
433
  end
416
434
  end
417
-
435
+
418
436
  def create_indexes(index_arr, args = nil)
419
- if args and args[:return_sql]
437
+ if args && args[:return_sql]
420
438
  ret = []
421
439
  end
422
-
440
+
423
441
  index_arr.each do |index_data|
424
442
  if index_data.is_a?(String) or index_data.is_a?(Symbol)
425
- index_data = {:name => index_data, :columns => [index_data]}
443
+ index_data = {name: index_data, columns: [index_data]}
426
444
  end
427
-
445
+
428
446
  raise "No name was given in data: '#{index_data}'." if !index_data.key?(:name) or index_data[:name].to_s.strip.empty?
429
447
  raise "No columns was given on index #{index_data[:name]}." if index_data[:columns].empty?
430
-
448
+
431
449
  name = index_data[:name]
432
450
  name = "#{self.name}__#{name}" if @db.opts[:index_append_table_name]
433
-
451
+
434
452
  sql = "CREATE"
435
453
  sql << " UNIQUE" if index_data[:unique]
436
454
  sql << " INDEX '#{@db.esc_col(name)}' ON `#{@db.esc_table(self.name)}` ("
437
-
455
+
438
456
  first = true
439
457
  index_data[:columns].each do |col_name|
440
458
  sql << ", " if !first
441
459
  first = false if first
442
-
460
+
443
461
  sql << "`#{@db.esc_col(col_name)}`"
444
462
  end
445
-
463
+
446
464
  sql << ")"
447
-
448
- if args and args[:return_sql]
465
+
466
+ if args && args[:return_sql]
449
467
  ret << sql
450
468
  else
451
469
  @db.query(sql)
452
470
  end
453
471
  end
454
-
455
- if args and args[:return_sql]
472
+
473
+ if args && args[:return_sql]
456
474
  return ret
457
475
  else
458
476
  return nil
459
477
  end
460
478
  end
461
-
479
+
462
480
  def data
463
481
  ret = {
464
- :name => name,
465
- :columns => [],
466
- :indexes => []
482
+ name: name,
483
+ columns: [],
484
+ indexes: []
467
485
  }
468
-
486
+
469
487
  columns.each do |name, column|
470
488
  ret[:columns] << column.data
471
489
  end
472
-
490
+
473
491
  indexes.each do |name, index|
474
492
  ret[:indexes] << index.data if name != "PRIMARY"
475
493
  end
476
-
494
+
477
495
  return ret
478
496
  end
479
-
497
+
480
498
  def insert(data)
481
499
  @db.insert(self.name, data)
482
500
  end
483
- end
501
+
502
+ def to_s
503
+ "#<Baza::Driver::Sqlite3::Table name: \"#{name}\">"
504
+ end
505
+
506
+ private
507
+
508
+ def parse_columns_from_sql sql
509
+ columns_sql = sql.match(/\((.+?)\)\Z/)[1]
510
+ return columns_sql.split(",").map{ |column| column[1, column.length - 2] }
511
+ end
512
+ end