baza 0.0.0 → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -0
- data/Gemfile.lock +2 -0
- data/README.rdoc +106 -1
- data/VERSION +1 -1
- data/baza.gemspec +103 -0
- data/include/db.rb +108 -29
- data/include/drivers/mysql/mysql.rb +52 -47
- data/include/drivers/mysql/mysql_columns.rb +48 -41
- data/include/drivers/mysql/mysql_indexes.rb +2 -2
- data/include/drivers/mysql/mysql_tables.rb +91 -59
- data/include/drivers/sqlite3/sqlite3.rb +66 -45
- data/include/drivers/sqlite3/sqlite3_columns.rb +41 -39
- data/include/drivers/sqlite3/sqlite3_indexes.rb +2 -2
- data/include/drivers/sqlite3/sqlite3_tables.rb +86 -54
- data/include/dump.rb +5 -2
- data/include/revision.rb +130 -90
- data/spec/baza_spec.rb +312 -263
- data/spec/info_mysql_example.rb +6 -0
- data/spec/info_sqlite3.rb +20 -0
- metadata +22 -3
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
data/README.rdoc
CHANGED
@@ -1,6 +1,111 @@
|
|
1
1
|
= baza
|
2
2
|
|
3
|
-
|
3
|
+
A database abstraction layer for Ruby.
|
4
|
+
|
5
|
+
== Installation
|
6
|
+
|
7
|
+
Is fairly painless.
|
8
|
+
gem install baza
|
9
|
+
|
10
|
+
== Connection to a database.
|
11
|
+
|
12
|
+
=== MySQL
|
13
|
+
db = Baza::Db.new(:type => :mysql, :subtype => :mysql2, :host => "localhost", :user => "my_user", :pass => "my_password", :port => 3306, :db => "my_database")
|
14
|
+
|
15
|
+
=== SQLite3
|
16
|
+
db = Baza::Db.new(:type => :sqlite3, :path => "/path/to/file.sqlite3")
|
17
|
+
|
18
|
+
== Queries
|
19
|
+
|
20
|
+
=== Select
|
21
|
+
db.select(:users, {:name => "Kasper"}, {:orderby => "age"}) do |row|
|
22
|
+
puts "Row: #{row}"
|
23
|
+
end
|
24
|
+
|
25
|
+
name = "Kasper"
|
26
|
+
db.q("SELECT * FROM users WHERE name = '#{db.esc(name)}' ORDER BY age") do |row|
|
27
|
+
puts "Row: #{row}"
|
28
|
+
end
|
29
|
+
|
30
|
+
=== Inserting
|
31
|
+
db.insert(:users, {:name => "Kasper", :age => 27})
|
32
|
+
id = db.last_id
|
33
|
+
|
34
|
+
It can also return the ID at the same time
|
35
|
+
id = db.insert(:users, {:name => "Kasper", :age => 27}, :return_id => true)
|
36
|
+
|
37
|
+
Inserting multiple rows in one query is also fairly painless:
|
38
|
+
db.insert_multi(:users, [
|
39
|
+
{:name => "Kasper", :age => 27},
|
40
|
+
{:name => "Christina", :age => 25},
|
41
|
+
{:name => "Charlotte", :age => 23}
|
42
|
+
])
|
43
|
+
|
44
|
+
=== Update
|
45
|
+
db.update(:users, {:name => "Kasper Johansen"}, {:name => "Kasper"})
|
46
|
+
|
47
|
+
=== Delete
|
48
|
+
db.delete(:users, {:name => "Kasper"})
|
49
|
+
|
50
|
+
=== Upsert
|
51
|
+
The following example handels a row that will be inserted with {:name => "Kasper", :age => 27} if it doesnt exist or rows with {:name => "Kasper"} will have their their age updated to 27.
|
52
|
+
db.upsert(:users, {:name => "Kasper"}, {:age => 27})
|
53
|
+
|
54
|
+
== Structure
|
55
|
+
|
56
|
+
=== Table creation
|
57
|
+
db.tables.create(:users, {
|
58
|
+
:columns => [
|
59
|
+
{:name => :id, :type => :int, :autoincr => true, :primarykey => true},
|
60
|
+
{:name => :name, :type => :varchar}
|
61
|
+
],
|
62
|
+
:indexes => [
|
63
|
+
:name
|
64
|
+
]
|
65
|
+
})
|
66
|
+
|
67
|
+
=== Table dropping
|
68
|
+
table = db.tables[:users]
|
69
|
+
table.drop
|
70
|
+
|
71
|
+
=== Table listing
|
72
|
+
array_of_tables = db.tables.list
|
73
|
+
|
74
|
+
Or you can use blocks:
|
75
|
+
db.tables.list do |table|
|
76
|
+
puts "Table-name: #{table.name}"
|
77
|
+
end
|
78
|
+
|
79
|
+
=== Table renaming
|
80
|
+
table = db.tables[:users]
|
81
|
+
table.rename(:new_table_name)
|
82
|
+
|
83
|
+
=== Column listing
|
84
|
+
table = db.tables[:users]
|
85
|
+
cols = table.columns
|
86
|
+
|
87
|
+
Or a specific column:
|
88
|
+
col = table.column(:id)
|
89
|
+
puts "Column: #{col.name} #{col.type}(#{col.maxlength})"
|
90
|
+
|
91
|
+
== Copying databases
|
92
|
+
db_mysql = Baza::Db.new(:type => :mysql, :subtype => :mysql2, ...)
|
93
|
+
db_sqlite = Baza::Db.new(:type => :sqlite3, :path => ...)
|
94
|
+
|
95
|
+
db_mysql.copy_to(db_sqlite)
|
96
|
+
|
97
|
+
== Dumping SQL to an IO
|
98
|
+
db = Baza::Db.new(...)
|
99
|
+
dump = Baza::Dump.new(:db => db)
|
100
|
+
str_io = StringIO.new
|
101
|
+
dump.dump(str_io)
|
102
|
+
|
103
|
+
== Transactions
|
104
|
+
db.transaction do
|
105
|
+
1000.times do
|
106
|
+
db.insert(:users, {:name => "Kasper"})
|
107
|
+
end
|
108
|
+
end
|
4
109
|
|
5
110
|
== Contributing to baza
|
6
111
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.1
|
data/baza.gemspec
ADDED
@@ -0,0 +1,103 @@
|
|
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 = "baza"
|
8
|
+
s.version = "0.0.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Kasper Johansen"]
|
12
|
+
s.date = "2013-04-16"
|
13
|
+
s.description = "A database abstraction layer, model framework and database framework."
|
14
|
+
s.email = "kj@gfish.com"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".rspec",
|
22
|
+
"Gemfile",
|
23
|
+
"Gemfile.lock",
|
24
|
+
"LICENSE.txt",
|
25
|
+
"README.rdoc",
|
26
|
+
"Rakefile",
|
27
|
+
"VERSION",
|
28
|
+
"baza.gemspec",
|
29
|
+
"include/db.rb",
|
30
|
+
"include/dbtime.rb",
|
31
|
+
"include/drivers/.DS_Store",
|
32
|
+
"include/drivers/mysql/mysql.rb",
|
33
|
+
"include/drivers/mysql/mysql_columns.rb",
|
34
|
+
"include/drivers/mysql/mysql_indexes.rb",
|
35
|
+
"include/drivers/mysql/mysql_sqlspecs.rb",
|
36
|
+
"include/drivers/mysql/mysql_tables.rb",
|
37
|
+
"include/drivers/sqlite3/libknjdb_java_sqlite3.rb",
|
38
|
+
"include/drivers/sqlite3/libknjdb_sqlite3_ironruby.rb",
|
39
|
+
"include/drivers/sqlite3/sqlite3.rb",
|
40
|
+
"include/drivers/sqlite3/sqlite3_columns.rb",
|
41
|
+
"include/drivers/sqlite3/sqlite3_indexes.rb",
|
42
|
+
"include/drivers/sqlite3/sqlite3_sqlspecs.rb",
|
43
|
+
"include/drivers/sqlite3/sqlite3_tables.rb",
|
44
|
+
"include/dump.rb",
|
45
|
+
"include/idquery.rb",
|
46
|
+
"include/model.rb",
|
47
|
+
"include/model_custom.rb",
|
48
|
+
"include/model_handler.rb",
|
49
|
+
"include/model_handler_sqlhelper.rb",
|
50
|
+
"include/query_buffer.rb",
|
51
|
+
"include/revision.rb",
|
52
|
+
"include/row.rb",
|
53
|
+
"include/sqlspecs.rb",
|
54
|
+
"lib/baza.rb",
|
55
|
+
"spec/baza_spec.rb",
|
56
|
+
"spec/db_spec_encoding_test_file.txt",
|
57
|
+
"spec/info_mysql_example.rb",
|
58
|
+
"spec/info_sqlite3.rb",
|
59
|
+
"spec/spec_helper.rb"
|
60
|
+
]
|
61
|
+
s.homepage = "http://github.com/kaspernj/baza"
|
62
|
+
s.licenses = ["MIT"]
|
63
|
+
s.require_paths = ["lib"]
|
64
|
+
s.rubygems_version = "1.8.25"
|
65
|
+
s.summary = "A database abstraction layer, model framework and database framework."
|
66
|
+
|
67
|
+
if s.respond_to? :specification_version then
|
68
|
+
s.specification_version = 3
|
69
|
+
|
70
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
71
|
+
s.add_runtime_dependency(%q<datet>, [">= 0"])
|
72
|
+
s.add_runtime_dependency(%q<wref>, [">= 0"])
|
73
|
+
s.add_runtime_dependency(%q<knjrbfw>, [">= 0"])
|
74
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.8.0"])
|
75
|
+
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
76
|
+
s.add_development_dependency(%q<bundler>, [">= 1.0.0"])
|
77
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
|
78
|
+
s.add_development_dependency(%q<sqlite3>, [">= 0"])
|
79
|
+
s.add_development_dependency(%q<mysql2>, [">= 0"])
|
80
|
+
else
|
81
|
+
s.add_dependency(%q<datet>, [">= 0"])
|
82
|
+
s.add_dependency(%q<wref>, [">= 0"])
|
83
|
+
s.add_dependency(%q<knjrbfw>, [">= 0"])
|
84
|
+
s.add_dependency(%q<rspec>, ["~> 2.8.0"])
|
85
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
86
|
+
s.add_dependency(%q<bundler>, [">= 1.0.0"])
|
87
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
88
|
+
s.add_dependency(%q<sqlite3>, [">= 0"])
|
89
|
+
s.add_dependency(%q<mysql2>, [">= 0"])
|
90
|
+
end
|
91
|
+
else
|
92
|
+
s.add_dependency(%q<datet>, [">= 0"])
|
93
|
+
s.add_dependency(%q<wref>, [">= 0"])
|
94
|
+
s.add_dependency(%q<knjrbfw>, [">= 0"])
|
95
|
+
s.add_dependency(%q<rspec>, ["~> 2.8.0"])
|
96
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
97
|
+
s.add_dependency(%q<bundler>, [">= 1.0.0"])
|
98
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
99
|
+
s.add_dependency(%q<sqlite3>, [">= 0"])
|
100
|
+
s.add_dependency(%q<mysql2>, [">= 0"])
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
data/include/db.rb
CHANGED
@@ -17,10 +17,57 @@ Knj.gem_require([:wref, :datet])
|
|
17
17
|
class Baza::Db
|
18
18
|
attr_reader :sep_col, :sep_table, :sep_val, :opts, :conn, :conns, :int_types
|
19
19
|
|
20
|
-
|
21
|
-
|
20
|
+
#Returns an array containing hashes of information about each registered driver.
|
21
|
+
def self.drivers
|
22
|
+
path = "#{File.dirname(__FILE__)}/drivers"
|
23
|
+
drivers = []
|
24
|
+
|
25
|
+
Dir.foreach(path) do |file|
|
26
|
+
next if file.to_s.slice(0, 1) == "."
|
27
|
+
fp = "#{path}/#{file}"
|
28
|
+
next unless File.directory?(fp)
|
29
|
+
|
30
|
+
driver_file = "#{fp}/#{file}.rb"
|
31
|
+
class_name = "#{file.slice(0, 1).to_s.upcase}#{file.slice(1, file.length)}".to_sym
|
32
|
+
|
33
|
+
drivers << {
|
34
|
+
:name => file,
|
35
|
+
:driver_path => driver_file,
|
36
|
+
:class_name => class_name
|
37
|
+
}
|
38
|
+
end
|
22
39
|
|
23
|
-
|
40
|
+
return drivers
|
41
|
+
end
|
42
|
+
|
43
|
+
#Tries to create a database-object based on the given object which could be a SQLite3 object or a MySQL 2 object (or other supported).
|
44
|
+
def self.from_object(args)
|
45
|
+
args = {:object => args} if !args.is_a?(Hash)
|
46
|
+
raise "No :object was given." if !args[:object]
|
47
|
+
|
48
|
+
Baza::Db.drivers.each do |driver|
|
49
|
+
require driver[:driver_path]
|
50
|
+
|
51
|
+
const = Baza::Driver.const_get(driver[:class_name])
|
52
|
+
next unless const.respond_to?(:from_object)
|
53
|
+
|
54
|
+
obj = const.from_object(args)
|
55
|
+
if obj.is_a?(Hash) and obj[:type] == :success
|
56
|
+
if obj[:args]
|
57
|
+
return Baza::Db.new(obj[:args])
|
58
|
+
else
|
59
|
+
raise "Didnt know what to do."
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
raise "Could not figure out what to do what object of type: '#{args[:object].class.name}'."
|
65
|
+
end
|
66
|
+
|
67
|
+
def initialize(opts)
|
68
|
+
@conn = opts.delete(:driver) if opts[:driver]
|
69
|
+
self.opts = opts if opts != nil
|
70
|
+
@int_types = [:int, :bigint, :tinyint, :smallint, :mediumint]
|
24
71
|
|
25
72
|
if !@opts[:threadsafe]
|
26
73
|
require "monitor"
|
@@ -41,7 +88,7 @@ class Baza::Db
|
|
41
88
|
return @opts
|
42
89
|
end
|
43
90
|
|
44
|
-
def
|
91
|
+
def opts=(arr_opts)
|
45
92
|
@opts = {}
|
46
93
|
arr_opts.each do |key, val|
|
47
94
|
@opts[key.to_sym] = val
|
@@ -163,28 +210,36 @@ class Baza::Db
|
|
163
210
|
end
|
164
211
|
end
|
165
212
|
|
213
|
+
COPY_TO_ALLOWED_ARGS = [:tables, :debug]
|
166
214
|
#Copies the content of the current database to another instance of Baza::Db.
|
167
215
|
def copy_to(db, args = {})
|
168
|
-
|
216
|
+
debug = args[:debug]
|
217
|
+
raise "No tables given." if !data[:tables]
|
218
|
+
|
219
|
+
data[:tables].each do |table|
|
169
220
|
table_args = nil
|
170
|
-
table_args = args[
|
171
|
-
next if table_args and table_args[
|
172
|
-
table.delete(
|
173
|
-
|
221
|
+
table_args = args[:tables][table[:name.to_sym]] if args and args[:tables] and args[:tables][table[:name].to_sym]
|
222
|
+
next if table_args and table_args[:skip]
|
223
|
+
table.delete(:indexes) if table.key?(:indexes) and args[:skip_indexes]
|
224
|
+
|
225
|
+
table_name = table.delete(:name)
|
226
|
+
puts "Creating table: '#{table_name}'." if debug
|
227
|
+
db.tables.create(table_name, table)
|
174
228
|
|
175
229
|
limit_from = 0
|
176
230
|
limit_incr = 1000
|
177
231
|
|
178
232
|
loop do
|
233
|
+
puts "Copying rows (#{limit_from}, #{limit_incr})." if debug
|
179
234
|
ins_arr = []
|
180
|
-
q_rows = self.select(
|
235
|
+
q_rows = self.select(table_name, {}, {:limit_from => limit_from, :limit_to => limit_incr})
|
181
236
|
while d_rows = q_rows.fetch
|
182
237
|
col_args = nil
|
183
238
|
|
184
|
-
if table_args and table_args[
|
239
|
+
if table_args and table_args[:columns]
|
185
240
|
d_rows.each do |col_name, col_data|
|
186
|
-
col_args = table_args[
|
187
|
-
d_rows[col_name] = "" if col_args and col_args[
|
241
|
+
col_args = table_args[:columns][col_name.to_sym] if table_args and table_args[:columns]
|
242
|
+
d_rows[col_name] = "" if col_args and col_args[:empty]
|
188
243
|
end
|
189
244
|
end
|
190
245
|
|
@@ -193,7 +248,8 @@ class Baza::Db
|
|
193
248
|
|
194
249
|
break if ins_arr.empty?
|
195
250
|
|
196
|
-
|
251
|
+
puts "Insertering #{ins_arr.length} rows." if debug
|
252
|
+
db.insert_multi(table_name, ins_arr)
|
197
253
|
limit_from += limit_incr
|
198
254
|
end
|
199
255
|
end
|
@@ -210,7 +266,7 @@ class Baza::Db
|
|
210
266
|
end
|
211
267
|
|
212
268
|
return {
|
213
|
-
|
269
|
+
:tables => tables_ret
|
214
270
|
}
|
215
271
|
end
|
216
272
|
|
@@ -265,12 +321,22 @@ class Baza::Db
|
|
265
321
|
return sql if args and args[:return_sql]
|
266
322
|
|
267
323
|
self.conn_exec do |driver|
|
268
|
-
|
324
|
+
begin
|
325
|
+
driver.query(sql)
|
326
|
+
rescue => e
|
327
|
+
self.add_sql_to_error(e, sql) if @opts[:sql_to_error]
|
328
|
+
raise e
|
329
|
+
end
|
330
|
+
|
269
331
|
return driver.lastID if args and args[:return_id]
|
270
332
|
return nil
|
271
333
|
end
|
272
334
|
end
|
273
335
|
|
336
|
+
def add_sql_to_error(error, sql)
|
337
|
+
error.message << " (SQL: #{sql})"
|
338
|
+
end
|
339
|
+
|
274
340
|
#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.
|
275
341
|
def sqlval(val)
|
276
342
|
return @conn.sqlval(val) if @conn.respond_to?(:sqlval)
|
@@ -300,14 +366,21 @@ class Baza::Db
|
|
300
366
|
|
301
367
|
if @esc_driver.respond_to?(:insert_multi)
|
302
368
|
if args and args[:return_sql]
|
303
|
-
|
369
|
+
res = @esc_driver.insert_multi(tablename, arr_hashes, args)
|
370
|
+
if res.is_a?(String)
|
371
|
+
return [res]
|
372
|
+
elsif res.is_a?(Array)
|
373
|
+
return res
|
374
|
+
else
|
375
|
+
raise "Unknown result: '#{res.class.name}'."
|
376
|
+
end
|
304
377
|
end
|
305
378
|
|
306
379
|
self.conn_exec do |driver|
|
307
380
|
return driver.insert_multi(tablename, arr_hashes, args)
|
308
381
|
end
|
309
382
|
else
|
310
|
-
ret = []
|
383
|
+
ret = []
|
311
384
|
arr_hashes.each do |hash|
|
312
385
|
if ret
|
313
386
|
ret << self.insert(tablename, hash, args)
|
@@ -372,6 +445,7 @@ class Baza::Db
|
|
372
445
|
end
|
373
446
|
end
|
374
447
|
|
448
|
+
SELECT_ARGS_ALLOWED_KEYS = [:limit, :limit_from, :limit_to]
|
375
449
|
#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.
|
376
450
|
def select(tablename, arr_terms = nil, args = nil, &block)
|
377
451
|
#Set up vars.
|
@@ -402,18 +476,18 @@ class Baza::Db
|
|
402
476
|
end
|
403
477
|
|
404
478
|
if args != nil
|
405
|
-
if args[
|
406
|
-
sql << " ORDER BY #{args[
|
479
|
+
if args[:orderby]
|
480
|
+
sql << " ORDER BY #{args[:orderby]}"
|
407
481
|
end
|
408
482
|
|
409
|
-
if args[
|
410
|
-
sql << " LIMIT #{args[
|
483
|
+
if args[:limit]
|
484
|
+
sql << " LIMIT #{args[:limit]}"
|
411
485
|
end
|
412
486
|
|
413
|
-
if args[
|
414
|
-
raise "'limit_from' was not numeric: '#{args[
|
415
|
-
raise "'limit_to' was not numeric: '#{args[
|
416
|
-
sql << " LIMIT #{args[
|
487
|
+
if args[:limit_from] and args[:limit_to]
|
488
|
+
raise "'limit_from' was not numeric: '#{args[:limit_from]}'." if !(Float(args[:limit_from]) rescue false)
|
489
|
+
raise "'limit_to' was not numeric: '#{args[:limit_to]}'." if !(Float(args[:limit_to]) rescue false)
|
490
|
+
sql << " LIMIT #{args[:limit_from]}, #{args[:limit_to]}"
|
417
491
|
end
|
418
492
|
end
|
419
493
|
|
@@ -437,7 +511,7 @@ class Baza::Db
|
|
437
511
|
#===Examples
|
438
512
|
# row = db.single(:users, {:lastname => "Doe"})
|
439
513
|
def single(tablename, arr_terms = nil, args = {})
|
440
|
-
args[
|
514
|
+
args[:limit] = 1
|
441
515
|
|
442
516
|
#Experienced very weird memory leak if this was not done by block. Maybe bug in Ruby 1.9.2? - knj
|
443
517
|
self.select(tablename, arr_terms, args) do |data|
|
@@ -549,8 +623,13 @@ class Baza::Db
|
|
549
623
|
end
|
550
624
|
end
|
551
625
|
|
552
|
-
|
553
|
-
|
626
|
+
begin
|
627
|
+
self.conn_exec do |driver|
|
628
|
+
return driver.query(string)
|
629
|
+
end
|
630
|
+
rescue => e
|
631
|
+
e.message << " (SQL: #{string})" if @opts[:sql_to_error]
|
632
|
+
raise e
|
554
633
|
end
|
555
634
|
end
|
556
635
|
|