baza 0.0.13 → 0.0.14

Sign up to get free protection for your applications and to get access to all the features.
@@ -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