Module: DohDb
- Defined in:
- lib/doh/mysql/error.rb,
lib/doh/mysql/parse.rb,
lib/doh/mysql/types.rb,
lib/doh/mysql/handle.rb,
lib/doh/mysql/convert.rb,
lib/doh/mysql/db_date.rb,
lib/doh/mysql/migrate.rb,
lib/doh/mysql/version.rb,
lib/doh/mysql/virtual.rb,
lib/doh/mysql/hash_row.rb,
lib/doh/mysql/load_sql.rb,
lib/doh/mysql/unquoted.rb,
lib/doh/mysql/smart_row.rb,
lib/doh/mysql/abstract_row.rb,
lib/doh/mysql/current_date.rb,
lib/doh/mysql/readonly_row.rb,
lib/doh/mysql/writable_row.rb,
lib/doh/mysql/metadata_util.rb,
lib/doh/mysql/migrate_check.rb,
lib/doh/mysql/connector_util.rb,
lib/doh/mysql/cache_connector.rb,
lib/doh/mysql/raw_row_builder.rb,
lib/doh/mysql/require_dbtypes.rb,
lib/doh/mysql/database_creator.rb,
lib/doh/mysql/typed_row_builder.rb,
lib/doh/mysql/connector_instance.rb,
lib/doh/mysql/default_type_guesser.rb
Defined Under Namespace
Classes: AbstractRow, AbstractSmartRow, CacheConnector, CannotBeNull, CustomSmartRow, DatabaseCreator, DatabaseMigrator, DateTimeNow, DateToday, DefaultTypeGuesser, Handle, HashRow, LinkedRow, MigrateChecker, RawRowBuilder, ReadOnlyRow, RowDisplayProxy, SmartRow, TypedRowBuilder, UnexpectedQueryResult, UnknownColumn, Unquoted, WritableRow
Constant Summary
collapse
- NOW =
Unquoted.new('NOW()').freeze
- TODAY =
Unquoted.new('CURDATE()').freeze
- NULL =
Unquoted.new('NULL').freeze
- @@column_types =
{}
- @@row_types =
{}
- @@cached_column_info =
{}
- @@primary_keys =
{}
- @@tables_by_database =
{}
Class Method Summary
collapse
-
.all_tables(database = nil) ⇒ Object
-
.chop_character_fields(table, row) ⇒ Object
-
.chop_character_fields!(table, row) ⇒ Object
-
.column_info(table, database = nil) ⇒ Object
-
.connector_instance ⇒ Object
-
.convert(table, column, value) ⇒ Object
-
.create_and_connect(connector, new_default_database = nil, drop_first = true) ⇒ Object
-
.current_database_version(database = nil) ⇒ Object
-
.current_date_db ⇒ Object
-
.current_datetime_db ⇒ Object
-
.drop_create_and_connect(connector, new_default_database = nil) ⇒ Object
-
.field_character_size(table, field, database = nil) ⇒ Object
-
.field_exist?(table, field, database = nil) ⇒ Boolean
-
.field_list(table, database = nil) ⇒ Object
-
.find_column_type(database, table, column) ⇒ Object
-
.find_primary_key(table, database = nil) ⇒ Object
-
.find_row_type(table) ⇒ Object
-
.insert(statement) ⇒ Object
-
.insert_hash(hash, table, ignore = nil) ⇒ Object
-
.latest_database_version(database = nil) ⇒ Object
-
.link_database_types(dest_db, source_db) ⇒ Object
-
.load_sql(filenames, host, username, password, database) ⇒ Object
-
.load_sql_connector(filenames, connector = nil, alternate_database = nil) ⇒ Object
-
.locked_database_version(database = nil) ⇒ Object
-
.locked_filename(database) ⇒ Object
-
.locked_svn_revision(database = nil) ⇒ Object
-
.locked_version_info(database = nil) ⇒ Object
-
.migration_filename(database, version, upordown = 'up') ⇒ Object
-
.multi_select(statements) ⇒ Object
-
.mysql_arg(value, option_specifier) ⇒ Object
-
.now ⇒ Object
-
.parse_bool(str) ⇒ Object
-
.parse_date(str) ⇒ Object
-
.parse_datetime(str) ⇒ Object
-
.parse_decimal(str) ⇒ Object
-
.parse_int(str) ⇒ Object
-
.query(statement) ⇒ Object
-
.reconfigure_connector(cfg, connector = nil) ⇒ Object
-
.register_column_type(database, table, column, klass) ⇒ Object
-
.register_row_type(table, klass) ⇒ Object
-
.replace_hash(hash, table) ⇒ Object
-
.request_handle ⇒ Object
-
.require_dbtypes ⇒ Object
-
.select(statement, row_builder = nil) ⇒ Object
-
.select_field(statement, row_builder = nil) ⇒ Object
-
.select_list(statement, row_builder = nil) ⇒ Object
-
.select_optional_field(statement, row_builder = nil) ⇒ Object
-
.select_optional_row(statement, row_builder = nil) ⇒ Object
-
.select_row(statement, row_builder = nil) ⇒ Object
-
.select_transpose(statement, row_builder = nil) ⇒ Object
-
.select_values(statement, row_builder = nil) ⇒ Object
-
.server_datetime ⇒ Object
-
.set_connector_instance(conn) ⇒ Object
-
.table_exist?(table, database = nil) ⇒ Boolean
-
.today ⇒ Object
-
.unquoted(str) ⇒ Object
-
.update(statement) ⇒ Object
-
.update_hash(hash, table, primary_key_value, primary_key_name) ⇒ Object
-
.update_locked_file(database) ⇒ Object
-
.update_row(statement) ⇒ Object
Class Method Details
.all_tables(database = nil) ⇒ Object
67
68
69
70
71
|
# File 'lib/doh/mysql/metadata_util.rb', line 67
def self.all_tables(database = nil)
database ||= DohDb::connector_instance.database
@@tables_by_database[database] ||
@@tables_by_database[database] ||= DohDb::select_list("SELECT table_name FROM information_schema.tables WHERE table_schema = '#{database}'")
end
|
.chop_character_fields(table, row) ⇒ Object
29
30
31
|
# File 'lib/doh/mysql/metadata_util.rb', line 29
def self.chop_character_fields(table, row)
chop_character_fields!(table, row.dup)
end
|
.chop_character_fields!(table, row) ⇒ Object
19
20
21
22
23
24
25
26
27
|
# File 'lib/doh/mysql/metadata_util.rb', line 19
def self.chop_character_fields!(table, row)
column_info(table).each do |field, attribs|
maxlen = attribs['character_maximum_length']
if maxlen && row[field].to_s.size > maxlen
row[field] = row[field].to_s[0, maxlen]
end
end
row
end
|
.column_info(table, database = nil) ⇒ Object
7
8
9
10
11
12
13
|
# File 'lib/doh/mysql/metadata_util.rb', line 7
def self.column_info(table, database = nil)
database ||= DohDb::connector_instance.database
lookup_str = database + '.' + table
return @@cached_column_info[lookup_str] if @@cached_column_info[lookup_str]
stmt = "SELECT column_name, is_nullable, data_type, character_maximum_length, numeric_scale, column_type FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=#{database.to_sql} AND TABLE_NAME=#{table.to_sql}"
@@cached_column_info[lookup_str] = DohDb::select_transpose(stmt)
end
|
.connector_instance ⇒ Object
7
8
9
|
# File 'lib/doh/mysql/connector_instance.rb', line 7
def self.connector_instance
@@connector_instance
end
|
.convert(table, column, value) ⇒ Object
6
7
8
9
10
11
12
13
14
15
16
|
# File 'lib/doh/mysql/convert.rb', line 6
def self.convert(table, column, value)
info = column_info(table)[column]
return value if info.nil?
if value.nil?
raise CannotBeNull, "#{table}.#{column}" if info['is_nullable'] == 'NO'
return nil
end
return nil if value.is_a?(String) && value.empty? && info['is_nullable'] == 'YES'
value
end
|
.create_and_connect(connector, new_default_database = nil, drop_first = true) ⇒ Object
3
4
5
6
7
8
9
10
11
|
# File 'lib/doh/mysql/connector_util.rb', line 3
def self.create_and_connect(connector, new_default_database = nil, drop_first = true)
connector.reset
connector.database = new_default_database if new_default_database
dbh = connector.request_handle('')
dbh.query("DROP DATABASE IF EXISTS #{connector.database}") if drop_first
dbh.query("CREATE DATABASE IF NOT EXISTS #{connector.database}")
dbh.query("USE #{connector.database}")
dbh
end
|
.current_database_version(database = nil) ⇒ Object
15
16
17
18
19
20
21
22
|
# File 'lib/doh/mysql/version.rb', line 15
def self.current_database_version(database = nil)
if database.nil?
table = 'version'
else
table = database + '.version'
end
DohDb::select_field("SELECT version FROM #{table}").to_i
end
|
.drop_create_and_connect(connector, new_default_database = nil) ⇒ Object
13
14
15
|
# File 'lib/doh/mysql/connector_util.rb', line 13
def self.drop_create_and_connect(connector, new_default_database = nil)
create_and_connect(connector, new_default_database, true)
end
|
.field_character_size(table, field, database = nil) ⇒ Object
15
16
17
|
# File 'lib/doh/mysql/metadata_util.rb', line 15
def self.field_character_size(table, field, database = nil)
column_info(table, database).fetch(field, {}).fetch('character_maximum_length')
end
|
.field_exist?(table, field, database = nil) ⇒ Boolean
33
34
35
|
# File 'lib/doh/mysql/metadata_util.rb', line 33
def self.field_exist?(table, field, database = nil)
column_info(table, database).key?(field)
end
|
.field_list(table, database = nil) ⇒ Object
62
63
64
|
# File 'lib/doh/mysql/metadata_util.rb', line 62
def self.field_list(table, database = nil)
column_info(table, database).keys
end
|
.find_column_type(database, table, column) ⇒ Object
12
13
14
15
16
17
18
|
# File 'lib/doh/mysql/types.rb', line 12
def self.find_column_type(database, table, column)
database = '__global__' db_hash = @@column_types[database]; return nil unless db_hash
table = '__global__' if table.nil?
table_hash = db_hash[table]; return nil unless table_hash
table_hash[column]
end
|
.find_primary_key(table, database = nil) ⇒ Object
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
# File 'lib/doh/mysql/metadata_util.rb', line 38
def self.find_primary_key(table, database = nil)
if table.index('.')
database = table.before('.')
table = table.after('.')
else
database ||= DohDb::connector_instance.database
end
dbhash = @@primary_keys[database]
if dbhash.nil?
dbhash = DohDb::select_transpose("SELECT table_name, column_name FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=#{database.to_sql} AND ORDINAL_POSITION=1")
raise "no information found for database #{database}" if dbhash.empty?
@@primary_keys[database] = dbhash
end
retval = dbhash[table]
raise "attempting to find_primary_key for table that doesn't exist: #{database}.#{table}" if retval.nil?
retval
end
|
.find_row_type(table) ⇒ Object
29
30
31
|
# File 'lib/doh/mysql/types.rb', line 29
def self.find_row_type(table)
@@row_types[table]
end
|
.insert(statement) ⇒ Object
31
32
33
|
# File 'lib/doh/mysql/connector_instance.rb', line 31
def self.insert(statement)
request_handle.insert(statement)
end
|
.insert_hash(hash, table, ignore = nil) ⇒ Object
35
36
37
|
# File 'lib/doh/mysql/connector_instance.rb', line 35
def self.insert_hash(hash, table, ignore = nil)
request_handle.insert_hash(hash, table, ignore)
end
|
.latest_database_version(database = nil) ⇒ Object
24
25
26
27
28
29
30
31
32
33
|
# File 'lib/doh/mysql/version.rb', line 24
def self.latest_database_version(database = nil)
locked_version = locked_database_version(database)
unlocked_version = locked_version + 1
unlocked_migration_file = migration_filename(database, unlocked_version)
if File.exist?(unlocked_migration_file)
unlocked_version
else
locked_version
end
end
|
.link_database_types(dest_db, source_db) ⇒ Object
20
21
22
|
# File 'lib/doh/mysql/types.rb', line 20
def self.link_database_types(dest_db, source_db)
@@column_types[dest_db] = @@column_types[source_db]
end
|
.load_sql(filenames, host, username, password, database) ⇒ Object
10
11
12
13
14
15
16
17
18
|
# File 'lib/doh/mysql/load_sql.rb', line 10
def self.load_sql(filenames, host, username, password, database)
mysqlcmd = 'mysql' + mysql_arg(host, 'h') + mysql_arg(username, 'u') + mysql_arg(password, 'p') + ' ' + database
io = IO::popen(mysqlcmd, 'r+')
dohlog.debug("loading sql file: " + filenames.first) if filenames.size == 1
filenames.each do |elem|
open(elem) {|file| io << file.read}
end
io.close
end
|
.load_sql_connector(filenames, connector = nil, alternate_database = nil) ⇒ Object
20
21
22
23
|
# File 'lib/doh/mysql/load_sql.rb', line 20
def self.load_sql_connector(filenames, connector = nil, alternate_database = nil)
connector ||= DohDb::connector_instance
load_sql(filenames, connector.host, connector.username, connector.password, alternate_database || connector.database)
end
|
.locked_database_version(database = nil) ⇒ Object
42
43
44
|
# File 'lib/doh/mysql/version.rb', line 42
def self.locked_database_version(database = nil)
locked_version_info(database).first
end
|
.locked_filename(database) ⇒ Object
6
7
8
|
# File 'lib/doh/mysql/version.rb', line 6
def self.locked_filename(database)
File.join(DohApp::home, 'database', database, 'migrate/locked.yml')
end
|
.locked_svn_revision(database = nil) ⇒ Object
46
47
48
|
# File 'lib/doh/mysql/version.rb', line 46
def self.locked_svn_revision(database = nil)
locked_version_info(database).last
end
|
.locked_version_info(database = nil) ⇒ Object
35
36
37
38
39
40
|
# File 'lib/doh/mysql/version.rb', line 35
def self.locked_version_info(database = nil)
database ||= (DohDb::connector_instance && DohDb::connector_instance.database) || DohApp::config['primary_database']
filename = locked_filename(database)
return [0, nil] unless File.exist?(filename)
YAML.load_file(filename)
end
|
.migration_filename(database, version, upordown = 'up') ⇒ Object
10
11
12
13
|
# File 'lib/doh/mysql/version.rb', line 10
def self.migration_filename(database, version, upordown = 'up')
version_str = version.to_s.rjust(3, '0')
File.join(DohApp::home, 'database', database, "migrate/#{version_str}_#{upordown}.sql")
end
|
.multi_select(statements) ⇒ Object
75
76
77
|
# File 'lib/doh/mysql/connector_instance.rb', line 75
def self.multi_select(statements)
request_handle.multi_select(statements)
end
|
.mysql_arg(value, option_specifier) ⇒ Object
5
6
7
8
|
# File 'lib/doh/mysql/load_sql.rb', line 5
def self.mysql_arg(value, option_specifier)
return '' if value.to_s.strip.empty?
' -' + option_specifier + value
end
|
23
24
25
26
|
# File 'lib/doh/mysql/db_date.rb', line 23
def self.now
dt = DateTime.zow
DateTimeNow.new(dt.year, dt.month, dt.mday, dt.hour, dt.min, dt.sec, dt.zone)
end
|
.parse_bool(str) ⇒ Object
6
7
8
9
10
11
12
13
14
|
# File 'lib/doh/mysql/parse.rb', line 6
def self.parse_bool(str)
if str == '0'
false
elsif str == '1'
true
else
raise ArgumentError.new("unexpected value: " + str)
end
end
|
.parse_date(str) ⇒ Object
22
23
24
25
26
|
# File 'lib/doh/mysql/parse.rb', line 22
def self.parse_date(str)
raise ArgumentError.new("unexpected value: " + str) unless str.size == 10
return nil if str == '0000-00-00'
Date.new(str[0..3].to_i, str[5..6].to_i, str[8..9].to_i)
end
|
.parse_datetime(str) ⇒ Object
16
17
18
19
20
|
# File 'lib/doh/mysql/parse.rb', line 16
def self.parse_datetime(str)
raise ArgumentError.new("unexpected value: " + str) unless str.size == 19
return nil if str == '0000-00-00 00:00:00'
DateTime.parse(str)
end
|
.parse_decimal(str) ⇒ Object
28
29
30
|
# File 'lib/doh/mysql/parse.rb', line 28
def self.parse_decimal(str)
BigDecimal(str)
end
|
.parse_int(str) ⇒ Object
32
33
34
|
# File 'lib/doh/mysql/parse.rb', line 32
def self.parse_int(str)
str.to_i
end
|
.query(statement) ⇒ Object
15
16
17
|
# File 'lib/doh/mysql/connector_instance.rb', line 15
def self.query(statement)
request_handle.query(statement)
end
|
17
18
19
20
21
22
23
24
25
|
# File 'lib/doh/mysql/connector_util.rb', line 17
def self.reconfigure_connector(cfg, connector = nil)
connector ||= DohDb::connector_instance
connector.reset
connector.host = cfg['host'] if cfg.key?('host')
connector.username = cfg['username'] if cfg.key?('username')
connector.password = cfg['password'] if cfg.key?('password')
connector.database = cfg['database'] if cfg.key?('database')
connector.port = cfg['port'] if cfg.key?('port')
end
|
.register_column_type(database, table, column, klass) ⇒ Object
4
5
6
7
8
9
10
|
# File 'lib/doh/mysql/types.rb', line 4
def self.register_column_type(database, table, column, klass)
database = '__global__' @@column_types[database] ||= {}
table = '__global__' if table.nil?
@@column_types[database][table] ||= {}
@@column_types[database][table][column] = klass
end
|
.register_row_type(table, klass) ⇒ Object
25
26
27
|
# File 'lib/doh/mysql/types.rb', line 25
def self.register_row_type(table, klass)
@@row_types[table] = klass
end
|
.replace_hash(hash, table) ⇒ Object
39
40
41
|
# File 'lib/doh/mysql/connector_instance.rb', line 39
def self.replace_hash(hash, table)
request_handle.replace_hash(hash, table)
end
|
.request_handle ⇒ Object
11
12
13
|
# File 'lib/doh/mysql/connector_instance.rb', line 11
def self.request_handle
connector_instance.request_handle
end
|
.require_dbtypes ⇒ Object
3
4
5
6
|
# File 'lib/doh/mysql/require_dbtypes.rb', line 3
def self.require_dbtypes
lib_dbtypes_file = File.join(DohApp::home, 'lib/dbtypes.rb')
require(lib_dbtypes_file) if File.exist?(lib_dbtypes_file)
end
|
.select(statement, row_builder = nil) ⇒ Object
43
44
45
|
# File 'lib/doh/mysql/connector_instance.rb', line 43
def self.select(statement, row_builder = nil)
request_handle.select(statement, row_builder)
end
|
.select_field(statement, row_builder = nil) ⇒ Object
55
56
57
|
# File 'lib/doh/mysql/connector_instance.rb', line 55
def self.select_field(statement, row_builder = nil)
request_handle.select_field(statement, row_builder)
end
|
.select_list(statement, row_builder = nil) ⇒ Object
71
72
73
|
# File 'lib/doh/mysql/connector_instance.rb', line 71
def self.select_list(statement, row_builder = nil)
request_handle.select_list(statement, row_builder)
end
|
.select_optional_field(statement, row_builder = nil) ⇒ Object
59
60
61
|
# File 'lib/doh/mysql/connector_instance.rb', line 59
def self.select_optional_field(statement, row_builder = nil)
request_handle.select_optional_field(statement, row_builder)
end
|
.select_optional_row(statement, row_builder = nil) ⇒ Object
51
52
53
|
# File 'lib/doh/mysql/connector_instance.rb', line 51
def self.select_optional_row(statement, row_builder = nil)
request_handle.select_optional_row(statement, row_builder)
end
|
.select_row(statement, row_builder = nil) ⇒ Object
47
48
49
|
# File 'lib/doh/mysql/connector_instance.rb', line 47
def self.select_row(statement, row_builder = nil)
request_handle.select_row(statement, row_builder)
end
|
.select_transpose(statement, row_builder = nil) ⇒ Object
63
64
65
|
# File 'lib/doh/mysql/connector_instance.rb', line 63
def self.select_transpose(statement, row_builder = nil)
request_handle.select_transpose(statement, row_builder)
end
|
.select_values(statement, row_builder = nil) ⇒ Object
67
68
69
|
# File 'lib/doh/mysql/connector_instance.rb', line 67
def self.select_values(statement, row_builder = nil)
request_handle.select_values(statement, row_builder)
end
|
.set_connector_instance(conn) ⇒ Object
3
4
5
|
# File 'lib/doh/mysql/connector_instance.rb', line 3
def self.set_connector_instance(conn)
@@connector_instance = conn
end
|
.table_exist?(table, database = nil) ⇒ Boolean
58
59
60
|
# File 'lib/doh/mysql/metadata_util.rb', line 58
def self.table_exist?(table, database = nil)
!find_primary_key(table, database).nil?
end
|
18
19
20
21
|
# File 'lib/doh/mysql/db_date.rb', line 18
def self.today
day = Date.today
DateToday.new(day.year, day.month, day.mday)
end
|
.unquoted(str) ⇒ Object
9
10
11
|
# File 'lib/doh/mysql/unquoted.rb', line 9
def self.unquoted(str)
Unquoted.new(str)
end
|
.update(statement) ⇒ Object
19
20
21
|
# File 'lib/doh/mysql/connector_instance.rb', line 19
def self.update(statement)
request_handle.update(statement)
end
|
.update_hash(hash, table, primary_key_value, primary_key_name) ⇒ Object
27
28
29
|
# File 'lib/doh/mysql/connector_instance.rb', line 27
def self.update_hash(hash, table, primary_key_value, primary_key_name)
request_handle.update_hash(hash, table, primary_key_value, primary_key_name)
end
|
.update_locked_file(database) ⇒ Object
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
# File 'lib/doh/mysql/version.rb', line 50
def self.update_locked_file(database)
locked_file = locked_filename(database)
if File.exist?(locked_file)
new_version = YAML.load_file(locked_file).first + 1
else
new_version = 0
need_to_add = true
end
file_to_check = ''
if need_to_add
file_to_check = File.join(DohApp::home, "database")
else
unlocked_migration_file = migration_filename(database, new_version)
return [true, "nothing to lock"] unless File.exist?(unlocked_migration_file)
svnout = `svn st #{unlocked_migration_file}`
unless svnout.strip.empty?
return [false, "svn status shows local changes to #{unlocked_migration_file} -- this needs to be resolved before updating the migration locked file"]
end
file_to_check = unlocked_migration_file
end
`svn update #{file_to_check}`
svnout = `svn st -v #{file_to_check}`.split("\n")
svnout =~ /(\d+)/
revision = svnout.collect {|elem| elem =~ /(\d+)/; $1.to_i}.max
if !revision
return [false, "unable to extract svn revision from: '#{svnout}'"]
end
outfile = File.new(locked_file, 'w')
outfile.puts([new_version, revision.to_i].inspect)
outfile.close
if need_to_add
svnout = `svn add #{locked_file}`
if svnout[0,1] != 'A'
return [false, "failed to svn add #{locked_file}"]
end
end
msg = "migrate lock for #{database} database, version #{new_version}"
svnout = `svn ci -m \"#{msg}\" #{locked_file}`
unless svnout.index("Committed revision")
return [false, "failed to svn ci #{locked_file}"]
end
[true, "#{locked_file} successfully updated"]
end
|
.update_row(statement) ⇒ Object
23
24
25
|
# File 'lib/doh/mysql/connector_instance.rb', line 23
def self.update_row(statement)
request_handle.update_row(statement)
end
|