knjrbfw 0.0.39 → 0.0.40

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,6 +1,8 @@
1
+ #This class handels various MySQL-table-specific behaviour.
1
2
  class KnjDB_mysql::Tables
2
3
  attr_reader :db, :list
3
4
 
5
+ #Constructor. This should not be called manually.
4
6
  def initialize(args)
5
7
  @args = args
6
8
  @db = @args[:db]
@@ -10,6 +12,7 @@ class KnjDB_mysql::Tables
10
12
  @list_should_be_reloaded = true
11
13
  end
12
14
 
15
+ #Cleans the wref-map.
13
16
  def clean
14
17
  @list.clean
15
18
  end
@@ -31,6 +34,7 @@ class KnjDB_mysql::Tables
31
34
  raise Knj::Errors::NotFound.new("Table was not found: #{table_name}.")
32
35
  end
33
36
 
37
+ #Yields the tables of the current database.
34
38
  def list(args = {})
35
39
  ret = {} unless block_given?
36
40
 
@@ -66,7 +70,8 @@ class KnjDB_mysql::Tables
66
70
  end
67
71
  end
68
72
 
69
- def create(name, data)
73
+ #Creates a new table by the given name and data.
74
+ def create(name, data, args = nil)
70
75
  raise "No columns was given for '#{name}'." if !data["columns"] or data["columns"].empty?
71
76
 
72
77
  sql = "CREATE TABLE `#{name}` ("
@@ -91,6 +96,8 @@ class KnjDB_mysql::Tables
91
96
  end
92
97
 
93
98
  sql << ")"
99
+
100
+ return [sql] if args and args[:return_sql]
94
101
  @db.query(sql)
95
102
  end
96
103
  end
@@ -106,7 +113,7 @@ class KnjDB_mysql::Tables::Table
106
113
  @list = Wref_map.new
107
114
  @indexes_list = Wref_map.new
108
115
 
109
- raise "Could not figure out name from: '#{@data}'." if !@data[:Name]
116
+ raise "Could not figure out name from: '#{@data}'." if @data[:Name].to_s.strip.length <= 0
110
117
  end
111
118
 
112
119
  def reload
@@ -321,7 +328,7 @@ class KnjDB_mysql::Tables::Table
321
328
 
322
329
  def data
323
330
  ret = {
324
- "name" => name,
331
+ "name" => self.name,
325
332
  "columns" => [],
326
333
  "indexes" => []
327
334
  }
@@ -1,7 +1,9 @@
1
+ #This class handels SQLite3-specific behaviour.
1
2
  class KnjDB_sqlite3
2
3
  attr_reader :knjdb, :conn, :escape_table, :escape_col, :escape_val, :esc_table, :esc_col, :symbolize
3
4
  attr_accessor :tables, :cols, :indexes
4
5
 
6
+ #Constructor. This should not be called manually.
5
7
  def initialize(knjdb_ob)
6
8
  @escape_table = "`"
7
9
  @escape_col = "`"
@@ -37,6 +39,7 @@ class KnjDB_sqlite3
37
39
  end
38
40
  end
39
41
 
42
+ #Executes a query against the driver.
40
43
  def query(string)
41
44
  begin
42
45
  if @knjdb.opts[:subtype] == "rhodes"
@@ -60,12 +63,17 @@ class KnjDB_sqlite3
60
63
  end
61
64
  end
62
65
 
66
+ #SQLite3 driver doesnt support unbuffered queries??
67
+ alias query_ubuf query
68
+
69
+ #Escapes a string to be safe to used in a query.
63
70
  def escape(string)
64
71
  #This code is taken directly from the documentation so we dont have to rely on the SQLite3::Database class. This way it can also be used with JRuby and IronRuby...
65
72
  #http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html
66
73
  return string.to_s.gsub(/'/, "''")
67
74
  end
68
75
 
76
+ #Escapes a string to be used as a column.
69
77
  def esc_col(string)
70
78
  string = string.to_s
71
79
  raise "Invalid column-string: #{string}" if string.index(@escape_col) != nil
@@ -75,16 +83,26 @@ class KnjDB_sqlite3
75
83
  alias :esc_table :esc_col
76
84
  alias :esc :escape
77
85
 
86
+ #Returns the last inserted ID.
78
87
  def lastID
79
88
  return @conn.last_insert_row_id if @conn.respond_to?(:last_insert_row_id)
80
89
  return self.query("SELECT last_insert_rowid() AS id").fetch[:id].to_i
81
90
  end
82
91
 
92
+ #Closes the connection to the database.
83
93
  def close
84
94
  @conn.close
85
95
  end
96
+
97
+ #Starts a transaction, yields the database and commits.
98
+ def transaction
99
+ @conn.transaction do
100
+ yield(@knjdb)
101
+ end
102
+ end
86
103
  end
87
104
 
105
+ #This class handels results when running in JRuby.
88
106
  class KnjDB_sqlite3_result_java
89
107
  def initialize(driver, rs)
90
108
  @index = 0
@@ -108,6 +126,7 @@ class KnjDB_sqlite3_result_java
108
126
  end
109
127
  end
110
128
 
129
+ #Returns a single result.
111
130
  def fetch
112
131
  return false if !@rows
113
132
  ret = @rows[@index]
@@ -116,6 +135,7 @@ class KnjDB_sqlite3_result_java
116
135
  return ret
117
136
  end
118
137
 
138
+ #Loops over every result and yields them.
119
139
  def each
120
140
  while data = self.fetch
121
141
  yield(data)
@@ -123,7 +143,9 @@ class KnjDB_sqlite3_result_java
123
143
  end
124
144
  end
125
145
 
146
+ #This class handels the result when running MRI (or others).
126
147
  class KnjDB_sqlite3_result
148
+ #Constructor. This should not be called manually.
127
149
  def initialize(driver, result_array)
128
150
  @result_array = result_array
129
151
  @index = 0
@@ -135,6 +157,7 @@ class KnjDB_sqlite3_result
135
157
  end
136
158
  end
137
159
 
160
+ #Returns a single result.
138
161
  def fetch
139
162
  result_hash = @result_array[@index]
140
163
  return false if !result_hash
@@ -154,6 +177,7 @@ class KnjDB_sqlite3_result
154
177
  return ret
155
178
  end
156
179
 
180
+ #Loops over every result yielding them.
157
181
  def each
158
182
  while data = self.fetch
159
183
  yield(data)
@@ -1,12 +1,13 @@
1
+ #This class handels the SQLite3-specific behaviour for columns.
1
2
  class KnjDB_sqlite3::Columns
2
- attr_reader :db, :driver
3
+ attr_reader :db
3
4
 
5
+ #Constructor. This should not be called manually.
4
6
  def initialize(args)
5
7
  @args = args
6
- @db = @args[:db]
7
- @driver = @args[:driver]
8
8
  end
9
9
 
10
+ #Returns SQL for a knjdb-compatible hash.
10
11
  def data_sql(data)
11
12
  raise "No type given." if !data["type"]
12
13
  type = data["type"]
@@ -17,7 +18,7 @@ class KnjDB_sqlite3::Columns
17
18
  end
18
19
 
19
20
  data["maxlength"] = 255 if type == "varchar" and !data.key?("maxlength")
20
- type = "integer" if @db.int_types.index(type) and (data["autoincr"] or data["primarykey"])
21
+ type = "integer" if @args[:db].int_types.index(type) and (data["autoincr"] or data["primarykey"])
21
22
 
22
23
  sql = "`#{data["name"]}` #{type}"
23
24
  sql << "(#{data["maxlength"]})" if data["maxlength"] and !data["autoincr"]
@@ -28,29 +29,34 @@ class KnjDB_sqlite3::Columns
28
29
  if data.key?("default_func")
29
30
  sql << " DEFAULT #{data["default_func"]}"
30
31
  elsif data.key?("default") and data["default"] != false
31
- sql << " DEFAULT '#{@db.escape(data["default"])}'"
32
+ sql << " DEFAULT '#{@args[:db].escape(data["default"])}'"
32
33
  end
33
34
 
34
35
  return sql
35
36
  end
36
37
  end
37
38
 
39
+ #This class handels all the SQLite3-columns.
38
40
  class KnjDB_sqlite3::Columns::Column
39
41
  attr_reader :args
40
42
 
43
+ #Constructor. This should not be called manually.
41
44
  def initialize(args)
42
45
  @args = args
43
46
  @db = @args[:db]
44
47
  end
45
48
 
49
+ #Returns the name of the column.
46
50
  def name
47
51
  return @args[:data][:name]
48
52
  end
49
53
 
54
+ #Returns the columns table-object.
50
55
  def table
51
56
  return @db.tables[@args[:table_name]]
52
57
  end
53
58
 
59
+ #Returns the data of the column as a hash in knjdb-format.
54
60
  def data
55
61
  return {
56
62
  "type" => self.type,
@@ -63,6 +69,7 @@ class KnjDB_sqlite3::Columns::Column
63
69
  }
64
70
  end
65
71
 
72
+ #Returns the type of the column.
66
73
  def type
67
74
  if !@type
68
75
  if match = @args[:data][:type].match(/^([A-z]+)$/)
@@ -70,36 +77,41 @@ class KnjDB_sqlite3::Columns::Column
70
77
  type = match[0]
71
78
  elsif match = @args[:data][:type].match(/^decimal\((\d+),(\d+)\)$/)
72
79
  @maxlength = "#{match[1]},#{match[2]}"
73
- type = "decimal"
80
+ type = :decimal
74
81
  elsif match = @args[:data][:type].match(/^enum\((.+)\)$/)
75
82
  @maxlength = match[1]
76
- type = "enum"
83
+ type = :enum
77
84
  elsif match = @args[:data][:type].match(/^(.+)\((\d+)\)$/)
78
85
  @maxlength = match[2]
79
- type = match[1]
86
+ type = match[1].to_sym
80
87
  end
81
88
 
82
- if type == "integer"
83
- @type = "int"
89
+ if type == :integer
90
+ @type = :int
84
91
  else
85
92
  @type = type
86
93
  end
94
+
95
+ raise "Still not type?" if @type.to_s.strip.length <= 0
87
96
  end
88
97
 
89
98
  return @type
90
99
  end
91
100
 
101
+ #Returns true if the column allows null. Otherwise false.
92
102
  def null?
93
103
  return false if @args[:data][:notnull].to_i == 1
94
104
  return true
95
105
  end
96
106
 
107
+ #Returns the maxlength of the column.
97
108
  def maxlength
98
- self.type
109
+ self.type if !@maxlength
99
110
  return @maxlength if @maxlength
100
111
  return false
101
112
  end
102
113
 
114
+ #Returns the default value of the column.
103
115
  def default
104
116
  def_val = @args[:data][:dflt_value]
105
117
  if def_val.to_s.slice(0..0) == "'"
@@ -114,24 +126,26 @@ class KnjDB_sqlite3::Columns::Column
114
126
  return def_val
115
127
  end
116
128
 
129
+ #Returns true if the column is the primary key.
117
130
  def primarykey?
118
- return true if @args[:data][:name] == "id"
131
+ return true if self.name.to_s == "id"
119
132
  return false if @args[:data][:pk].to_i == 0
120
133
  return true
121
134
  end
122
135
 
136
+ #Returns true if the column is auto-increasing.
123
137
  def autoincr?
124
- return true if @args[:data][:name] == "id"
138
+ return true if self.name.to_s == "id"
125
139
  return true if @args[:data][:pk].to_i >= 1
126
140
  return false
127
141
  end
128
142
 
143
+ #Drops the column from the table.
129
144
  def drop
130
- @args[:table].copy(
131
- "drops" => self.name
132
- )
145
+ self.table.copy("drops" => self.name)
133
146
  end
134
147
 
148
+ #Changes data on the column. Like the name, type, maxlength or whatever.
135
149
  def change(data)
136
150
  newdata = data.clone
137
151
 
@@ -13,16 +13,17 @@ class KnjDB_sqlite3::Tables
13
13
  table_name = table_name.to_s
14
14
 
15
15
  begin
16
- return @list[table_name]
16
+ ret = @list[table_name]
17
+ return ret
17
18
  rescue Wref::Recycled
18
19
  #ignore.
19
20
  end
20
21
 
21
22
  self.list do |table_obj|
22
- return table_obj if table_obj.name.to_s == table_name
23
+ return table_obj if table_obj.name.to_s == table_name.to_s
23
24
  end
24
25
 
25
- raise Knj::Errors::NotFound.new("Table was not found: #{table_name}.")
26
+ raise Knj::Errors::NotFound, "Table was not found: #{table_name}."
26
27
  end
27
28
 
28
29
  def list
@@ -55,7 +56,7 @@ class KnjDB_sqlite3::Tables
55
56
  end
56
57
  end
57
58
 
58
- def create(name, data)
59
+ def create(name, data, args = nil)
59
60
  sql = "CREATE TABLE `#{name}` ("
60
61
 
61
62
  first = true
@@ -67,11 +68,26 @@ class KnjDB_sqlite3::Tables
67
68
 
68
69
  sql << ")"
69
70
 
70
- @db.query(sql)
71
+ if args and args[:return_sql]
72
+ ret = [sql]
73
+ else
74
+ @db.query(sql)
75
+ end
71
76
 
72
77
  if data.key?("indexes") and data["indexes"]
73
78
  table_obj = self[name]
74
- table_obj.create_indexes(data["indexes"])
79
+
80
+ if args and args[:return_sql]
81
+ ret += table_obj.create_indexes(data["indexes"], :return_sql => true)
82
+ else
83
+ table_obj.create_indexes(data["indexes"])
84
+ end
85
+ end
86
+
87
+ if args and args[:return_sql]
88
+ return ret
89
+ else
90
+ return nil
75
91
  end
76
92
  end
77
93
  end
@@ -89,6 +105,14 @@ class KnjDB_sqlite3::Tables::Table
89
105
  return @data[:name]
90
106
  end
91
107
 
108
+ def type
109
+ return @data[:type]
110
+ end
111
+
112
+ def maxlength
113
+ return @data[:maxlength]
114
+ end
115
+
92
116
  def drop
93
117
  sql = "DROP TABLE `#{self.name}`"
94
118
  @db.query(sql)
@@ -98,6 +122,11 @@ class KnjDB_sqlite3::Tables::Table
98
122
  raise "stub!"
99
123
  end
100
124
 
125
+ def truncate
126
+ @db.query("DELETE FROM `#{self.name}` WHERE 1=1")
127
+ return nil
128
+ end
129
+
101
130
  def table
102
131
  return @db.tables[@table_name]
103
132
  end
@@ -331,7 +360,11 @@ class KnjDB_sqlite3::Tables::Table
331
360
  end
332
361
  end
333
362
 
334
- def create_indexes(index_arr)
363
+ def create_indexes(index_arr, args = nil)
364
+ if args and args[:return_sql]
365
+ ret = []
366
+ end
367
+
335
368
  index_arr.each do |index_data|
336
369
  if index_data.is_a?(String)
337
370
  index_data = {"name" => index_data, "columns" => [index_data]}
@@ -355,7 +388,17 @@ class KnjDB_sqlite3::Tables::Table
355
388
 
356
389
  sql << ")"
357
390
 
358
- @db.query(sql)
391
+ if args and args[:return_sql]
392
+ ret << sql
393
+ else
394
+ @db.query(sql)
395
+ end
396
+ end
397
+
398
+ if args and args[:return_sql]
399
+ return ret
400
+ else
401
+ return nil
359
402
  end
360
403
  end
361
404
 
@@ -0,0 +1,121 @@
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
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_name, table_obj|
42
+ table_obj = @args[:db].tables[table_obj] if table_obj.is_a?(String) or table_obj.is_a?(Symbol)
43
+
44
+ #Figure out keys.
45
+ @keys = []
46
+ table_obj.columns do |col|
47
+ @keys << col.name
48
+ end
49
+
50
+ @table_obj = table_obj
51
+ self.update_status
52
+ print "Dumping table: '#{table_obj.name}'.\n" if @debug
53
+ self.dump_table(io, table_obj)
54
+ end
55
+ end
56
+
57
+ #A block can be executed when a new status occurs.
58
+ def on_status(&block)
59
+ @on_status = block
60
+ end
61
+
62
+ #Dumps the given table into the given IO.
63
+ def dump_table(io, table_obj)
64
+ #Get SQL for creating table and add it to IO.
65
+ sqls = @args[:db].tables.create(table_obj.name, table_obj.data, :return_sql => true)
66
+ sqls.each do |sql|
67
+ io.write("#{sql};\n")
68
+ end
69
+
70
+
71
+ #Try to find a primary column in the table.
72
+ prim_col = nil
73
+ table_obj.columns do |col|
74
+ if col.primarykey?
75
+ prim_col = col
76
+ break
77
+ end
78
+ end
79
+
80
+
81
+ #Set up rows and way to fill rows.
82
+ rows = []
83
+ block_data = proc do |row|
84
+ rows << row
85
+ @rows_count += 1
86
+
87
+ if rows.length >= 1000
88
+ self.update_status
89
+ self.dump_insert_multi(io, table_obj, rows)
90
+ end
91
+ end
92
+
93
+
94
+ #If a primary column is found then use IDQuery. Otherwise use cloned unbuffered query.
95
+ args = {:idquery => prim_col.name.to_sym} if prim_col
96
+
97
+
98
+ #Clone the connecting with array-results and execute query.
99
+ @args[:db].clone_conn(:result => "array") do |db|
100
+ db.select(table_obj.name, nil, args, &block_data)
101
+ end
102
+
103
+
104
+ #Dump the last rows if any.
105
+ self.dump_insert_multi(io, table_obj, rows) if !rows.empty?
106
+ end
107
+
108
+ #Dumps the given rows from the given table into the given IO.
109
+ def dump_insert_multi(io, table_obj, rows)
110
+ print "Inserting #{rows.length} into #{table_obj.name}.\n" if @debug
111
+ sqls = @args[:db].insert_multi(table_obj.name, rows, :return_sql => true, :keys => @keys)
112
+ sqls.each do |sql|
113
+ io.write("#{sql};\n")
114
+ end
115
+
116
+ rows.clear
117
+
118
+ #Ensure garbage collection or we might start using A LOT of memory.
119
+ GC.start
120
+ end
121
+ end
@@ -0,0 +1,109 @@
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