skiima 0.1.000 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +9 -0
  3. data/.travis.yml +11 -3
  4. data/Gemfile +12 -6
  5. data/Guardfile +13 -11
  6. data/LICENSE +20 -0
  7. data/Procfile.example +2 -0
  8. data/README.md +170 -23
  9. data/Rakefile +26 -22
  10. data/lib/skiima.rb +61 -240
  11. data/lib/skiima/config.rb +60 -0
  12. data/lib/skiima/config/struct.rb +87 -0
  13. data/lib/skiima/db/connector.rb +195 -0
  14. data/lib/skiima/db/connector/active_record.rb +11 -0
  15. data/lib/skiima/db/connector/active_record/base_connector.rb +34 -0
  16. data/lib/skiima/db/connector/active_record/mysql2_connector.rb +147 -0
  17. data/lib/skiima/db/connector/active_record/mysql_connector.rb +177 -0
  18. data/lib/skiima/db/connector/active_record/postgresql_connector.rb +39 -0
  19. data/lib/skiima/db/helpers/mysql.rb +230 -0
  20. data/lib/skiima/db/helpers/postgresql.rb +221 -0
  21. data/lib/skiima/db/resolver.rb +62 -0
  22. data/lib/skiima/dependency/reader.rb +55 -0
  23. data/lib/skiima/dependency/script.rb +63 -0
  24. data/lib/skiima/i18n.rb +24 -0
  25. data/lib/skiima/loader.rb +108 -0
  26. data/lib/skiima/locales/en.yml +2 -2
  27. data/lib/skiima/logger.rb +54 -0
  28. data/lib/skiima/railtie.rb +10 -0
  29. data/lib/skiima/railties/skiima.rake +31 -0
  30. data/lib/skiima/version.rb +2 -2
  31. data/skiima.gemspec +5 -5
  32. data/spec/config/{database.yml → database.yml.example} +16 -0
  33. data/spec/config/database.yml.travis +69 -0
  34. data/spec/db/skiima/{depends.yml → dependencies.yml} +7 -2
  35. data/spec/db/skiima/{empty_depends.yml → empty_dependencies.yml} +0 -0
  36. data/spec/db/skiima/init_test_db/database.skiima_test.mysql.current.sql +7 -0
  37. data/spec/db/skiima/init_test_db/database.skiima_test.postgresql.current.sql +7 -0
  38. data/spec/mysql2_spec.rb +61 -12
  39. data/spec/mysql_spec.rb +66 -27
  40. data/spec/postgresql_spec.rb +55 -34
  41. data/spec/shared_examples/config_shared_example.rb +40 -0
  42. data/spec/skiima/config/struct_spec.rb +78 -0
  43. data/spec/skiima/config_spec.rb +6 -0
  44. data/spec/skiima/db/connector/active_record/base_connector_spec.rb +0 -0
  45. data/spec/skiima/db/connector/active_record/mysql2_connector_spec.rb +3 -0
  46. data/spec/skiima/db/connector/active_record/mysql_connector_spec.rb +3 -0
  47. data/spec/skiima/db/connector/active_record/postgresql_connector_spec.rb +7 -0
  48. data/spec/skiima/db/connector_spec.rb +6 -0
  49. data/spec/skiima/db/resolver_spec.rb +54 -0
  50. data/spec/skiima/dependency/reader_spec.rb +52 -0
  51. data/spec/skiima/{dependency_spec.rb → dependency/script_spec.rb} +3 -41
  52. data/spec/skiima/i18n_spec.rb +29 -0
  53. data/spec/skiima/loader_spec.rb +102 -0
  54. data/spec/skiima/logger_spec.rb +0 -0
  55. data/spec/skiima_spec.rb +43 -64
  56. data/spec/spec_helper.rb +38 -4
  57. metadata +144 -100
  58. data/lib/skiima/db_adapters.rb +0 -187
  59. data/lib/skiima/db_adapters/base_mysql_adapter.rb +0 -308
  60. data/lib/skiima/db_adapters/mysql2_adapter.rb +0 -114
  61. data/lib/skiima/db_adapters/mysql_adapter.rb +0 -287
  62. data/lib/skiima/db_adapters/postgresql_adapter.rb +0 -509
  63. data/lib/skiima/dependency.rb +0 -84
  64. data/lib/skiima_helpers.rb +0 -49
  65. data/spec/skiima/db_adapters/mysql_adapter_spec.rb +0 -38
  66. data/spec/skiima/db_adapters/postgresql_adapter_spec.rb +0 -20
  67. data/spec/skiima/db_adapters_spec.rb +0 -31
@@ -0,0 +1,195 @@
1
+ # encoding: utf-8
2
+
3
+ module Skiima
4
+ module Db
5
+ module Connector
6
+ class Base
7
+ extend Forwardable
8
+
9
+ class << self
10
+ extend Forwardable
11
+
12
+ def create_connector(config, logger = nil, opts = {})
13
+ pool = config['pool']
14
+ adapter = create_adapter(config, logger, pool)
15
+ new(adapter, logger, config)
16
+ end
17
+ end
18
+
19
+ attr_accessor :config, :orm
20
+ attr_accessor :logger, :adapter
21
+
22
+ alias_method :klass, :class
23
+ delegate helpers_module: :klass
24
+
25
+ def initialize(adapter, logger, config = {})
26
+ @adapter, @logger = adapter, logger
27
+
28
+ set_config(config)
29
+ include_helpers_on_adapter
30
+ end
31
+
32
+ private
33
+
34
+ def set_config(opts = {})
35
+ @config = opts
36
+ end
37
+
38
+ def include_helpers_on_adapter
39
+ adapter.singleton_class.class_eval "include #{helpers_module.to_s}"
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ # encoding: utf-8
47
+ #module Skiima
48
+ # module DbAdapters
49
+ # class Base
50
+ # attr_accessor :version
51
+ #
52
+ # def initialize(connection, logger = nil) #:nodoc:
53
+ # super()
54
+ #
55
+ # @active = nil
56
+ # @connection = connection
57
+ # @in_use = false
58
+ # @last_use = false
59
+ # @logger = logger
60
+ # @visitor = nil
61
+ # end
62
+ #
63
+ # def adapter_name
64
+ # 'Base'
65
+ # end
66
+ #
67
+ # def supports_ddl_transactions?
68
+ # false
69
+ # end
70
+ #
71
+ # # Does this adapter support savepoints? PostgreSQL and MySQL do,
72
+ # # SQLite < 3.6.8 does not.
73
+ # def supports_savepoints?
74
+ # false
75
+ # end
76
+ #
77
+ # def active?
78
+ # @active != false
79
+ # end
80
+ #
81
+ # # Disconnects from the database if already connected, and establishes a
82
+ # # new connection with the database.
83
+ # def reconnect!
84
+ # @active = true
85
+ # end
86
+ #
87
+ # # Disconnects from the database if already connected. Otherwise, this
88
+ # # method does nothing.
89
+ # def disconnect!
90
+ # @active = false
91
+ # end
92
+ #
93
+ # # Reset the state of this connection, directing the DBMS to clear
94
+ # # transactions and other connection-related server-side state. Usually a
95
+ # # database-dependent operation.
96
+ # #
97
+ # # The default implementation does nothing; the implementation should be
98
+ # # overridden by concrete adapters.
99
+ # def reset!
100
+ # # this should be overridden by concrete adapters
101
+ # end
102
+ #
103
+ # ###
104
+ # # Clear any caching the database adapter may be doing, for example
105
+ # # clearing the prepared statement cache. This is database specific.
106
+ # def clear_cache!
107
+ # # this should be overridden by concrete adapters
108
+ # end
109
+ #
110
+ # # Returns true if its required to reload the connection between requests for development mode.
111
+ # # This is not the case for Ruby/MySQL and it's not necessary for any adapters except SQLite.
112
+ # def requires_reloading?
113
+ # false
114
+ # end
115
+ #
116
+ # # Checks whether the connection to the database is still active (i.e. not stale).
117
+ # # This is done under the hood by calling <tt>active?</tt>. If the connection
118
+ # # is no longer active, then this method will reconnect to the database.
119
+ # def verify!(*ignored)
120
+ # reconnect! unless active?
121
+ # end
122
+ #
123
+ # # Provides access to the underlying database driver for this adapter. For
124
+ # # example, this method returns a Mysql object in case of MysqlAdapter,
125
+ # # and a PGconn object in case of PostgreSQLAdapter.
126
+ # #
127
+ # # This is useful for when you need to call a proprietary method such as
128
+ # # PostgreSQL's lo_* methods.
129
+ # def raw_connection
130
+ # @connection
131
+ # end
132
+ #
133
+ # attr_reader :open_transactions
134
+ #
135
+ # def increment_open_transactions
136
+ # @open_transactions += 1
137
+ # end
138
+ #
139
+ # def decrement_open_transactions
140
+ # @open_transactions -= 1
141
+ # end
142
+ #
143
+ # def transaction_joinable=(joinable)
144
+ # @transaction_joinable = joinable
145
+ # end
146
+ #
147
+ # def create_savepoint
148
+ # end
149
+ #
150
+ # def rollback_to_savepoint
151
+ # end
152
+ #
153
+ # def release_savepoint
154
+ # end
155
+ #
156
+ # def current_savepoint_name
157
+ # "active_record_#{open_transactions}"
158
+ # end
159
+ #
160
+ # # Check the connection back in to the connection pool
161
+ # def close
162
+ # disconnect!
163
+ # end
164
+ #
165
+ # # Disconnects from the database if already connected. Otherwise, this
166
+ # # method does nothing.
167
+ # def disconnect!
168
+ # clear_cache!
169
+ # @connection.close rescue nil
170
+ # end
171
+ #
172
+ # protected
173
+ #
174
+ # def log(sql, name = "SQL", binds = [])
175
+ # @logger.debug("Executing SQL Statement: #{name}")
176
+ # @logger.debug(sql)
177
+ # result = yield
178
+ # @logger.debug("SUCCESS!")
179
+ # result
180
+ # rescue Exception => e
181
+ # message = "#{e.class.name}: #{e.message}: #{sql}"
182
+ # @logger.debug message if @logger
183
+ # exception = translate_exception(e, message)
184
+ # exception.set_backtrace e.backtrace
185
+ # raise exception
186
+ # end
187
+ #
188
+ # def translate_exception(e, message)
189
+ # # override in derived class
190
+ # raise "override in derived class"
191
+ # end
192
+ #
193
+ # end
194
+ # end
195
+ #end
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+
3
+ module Skiima
4
+ module Db
5
+ module Connector
6
+ module ActiveRecord
7
+
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,34 @@
1
+ # encoding: utf-8
2
+ require 'active_record' unless defined? ActiveRecord
3
+ require 'active_support' unless defined? ActiveSupport
4
+
5
+ module Skiima
6
+ module Db
7
+ module Connector
8
+ module ActiveRecord
9
+
10
+ class BaseConnector < Skiima::Db::Connector::Base
11
+ delegate [:version, :execute,
12
+ :adapter_name, :supported_objects,
13
+ :supports_ddl_transactions?,
14
+ :drop, :active?, :object_exists?,
15
+ :reconnect!, :disconnect!, :close,
16
+ :reset!, :verify!, :raw_connection,
17
+ :begin_db_transaction, :rollback_db_transaction] => :adapter
18
+
19
+ #alias_method :connection, :raw_connection
20
+
21
+ class << self
22
+ def active_record_resolver_klass
23
+ case ::ActiveRecord::VERSION::MAJOR
24
+ when 4 then ::ActiveRecord::ConnectionHandling
25
+ when 3 then ::ActiveRecord::Base
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,147 @@
1
+ # encoding: utf-8
2
+ require 'skiima/db/helpers/mysql' unless defined? Skiima::Db::Helpers::Mysql
3
+ require 'skiima/db/connector/active_record/base_connector' unless defined? Skiima::Db::Connector::ActiveRecord::BaseConnector
4
+ require 'active_record/connection_adapters/mysql2_adapter' unless defined? ActiveRecord::ConnectionAdapters::Mysql2Adapter
5
+
6
+ module Skiima
7
+ module Db
8
+ module Connector
9
+ module ActiveRecord
10
+ class Mysql2Connector < Skiima::Db::Connector::ActiveRecord::BaseConnector
11
+ delegate [:table_exists?, :index_exists?, :proc_exists?,
12
+ :view_exists?, :schema_exists?] => :adapter
13
+
14
+ class << self
15
+ delegate mysql2_connection: :active_record_resolver_klass
16
+
17
+ def create_adapter(config, logger, pool)
18
+ case ::ActiveRecord::VERSION::MAJOR
19
+ when 3,4 then send('mysql2_connection', config)
20
+ end
21
+ end
22
+
23
+ def helpers_module
24
+ Skiima::Db::Helpers::Mysql
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ ## encoding: utf-8
34
+ #require 'skiima/db_adapters/base_mysql_adapter'
35
+ #
36
+ #gem 'mysql2', '~> 0.3.10'
37
+ #require 'mysql2'
38
+ #
39
+ #module Skiima
40
+ # def self.mysql2_connection(logger, config)
41
+ # config = Skiima.symbolize_keys(config)
42
+ # config[:username] = 'root' if config[:username].nil?
43
+ #
44
+ # if Mysql2::Client.const_defined? :FOUND_ROWS
45
+ # config[:flags] = Mysql2::Client::FOUND_ROWS
46
+ # end
47
+ #
48
+ # client = Mysql2::Client.new(config)
49
+ # options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0]
50
+ # Skiima::DbAdapters::Mysql2Adapter.new(client, logger, options, config)
51
+ # end
52
+ #
53
+ # module DbAdapters
54
+ # class Mysql2Adapter < BaseMysqlAdapter
55
+ # ADAPTER_NAME = 'Mysql2'
56
+ #
57
+ # def initialize(connection, logger, connection_options, config)
58
+ # super
59
+ # configure_connection
60
+ # end
61
+ #
62
+ # def supports_explain?
63
+ # true
64
+ # end
65
+ #
66
+ # def error_number(exception)
67
+ # exception.error_number if exception.respond_to?(:error_number)
68
+ # end
69
+ #
70
+ # def active?
71
+ # return false unless @connection
72
+ # @connection.ping
73
+ # end
74
+ #
75
+ # def reconnect!
76
+ # disconnect!
77
+ # connect
78
+ # end
79
+ #
80
+ # # Disconnects from the database if already connected.
81
+ # # Otherwise, this method does nothing.
82
+ # def disconnect!
83
+ # unless @connection.nil?
84
+ # @connection.close
85
+ # @connection = nil
86
+ # end
87
+ # end
88
+ #
89
+ # def reset!
90
+ # disconnect!
91
+ # connect
92
+ # end
93
+ #
94
+ # def execute(sql, name = nil)
95
+ # # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
96
+ # # made since we established the connection
97
+ # # @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
98
+ #
99
+ # # relying on formatting inside the file is precisely what i wanted to avoid...
100
+ # results = sql.split(/^--={4,}/).map do |spider_monkey|
101
+ # super(spider_monkey)
102
+ # end
103
+ #
104
+ # results.first
105
+ # end
106
+ #
107
+ # def exec_query(sql, name = 'SQL', binds = [])
108
+ # result = execute(sql, name)
109
+ # ActiveRecord::Result.new(result.fields, result.to_a)
110
+ # end
111
+ #
112
+ # alias exec_without_stmt exec_query
113
+ #
114
+ # private
115
+ #
116
+ # def connect
117
+ # @connection = Mysql2::Client.new(@config)
118
+ # configure_connection
119
+ # end
120
+ #
121
+ # def configure_connection
122
+ # @connection.query_options.merge!(:as => :array)
123
+ #
124
+ # variable_assignments = get_var_assignments
125
+ # execute("SET #{variable_assignments.join(', ')}", :skip_logging)
126
+ #
127
+ # version
128
+ # end
129
+ #
130
+ # def get_var_assignments
131
+ # # By default, MySQL 'where id is null' selects the last inserted id.
132
+ # # Turn this off. http://dev.rubyonrails.org/ticket/6778
133
+ # variable_assignments = ['SQL_AUTO_IS_NULL=0']
134
+ # encoding = @config[:encoding]
135
+ #
136
+ # # make sure we set the encoding
137
+ # variable_assignments << "NAMES '#{encoding}'" if encoding
138
+ #
139
+ # # increase timeout so mysql server doesn't disconnect us
140
+ # wait_timeout = @config[:wait_timeout]
141
+ # wait_timeout = 2592000 unless wait_timeout.is_a?(Fixnum)
142
+ # variable_assignments << "@@wait_timeout = #{wait_timeout}"
143
+ # end
144
+ #
145
+ # end
146
+ # end
147
+ #end
@@ -0,0 +1,177 @@
1
+ # encoding: utf-8
2
+ require 'skiima/db/helpers/mysql' unless defined? Skiima::Db::Helpers::Mysql
3
+ require 'skiima/db/connector/active_record/base_connector' unless defined? Skiima::Db::Connector::ActiveRecord::BaseConnector
4
+ require 'active_record/connection_adapters/mysql_adapter' unless defined? ActiveRecord::ConnectionAdapters::MysqlAdapter
5
+
6
+ module Skiima
7
+ module Db
8
+ module Connector
9
+ module ActiveRecord
10
+
11
+ class MysqlConnector < Skiima::Db::Connector::ActiveRecord::BaseConnector
12
+ delegate [:tables, :indexes, :procs, :views, :schemas,
13
+ :drop, :drop_table, :drop_proc, :drop_view,
14
+ :drop_index, :drop_schema, :column_names,
15
+ :table_exists?, :index_exists?, :proc_exists?,
16
+ :view_exists?, :schema_exists?] => :adapter
17
+
18
+ class << self
19
+ delegate mysql_connection: :active_record_resolver_klass
20
+
21
+ def create_adapter(config, logger, pool)
22
+ case ::ActiveRecord::VERSION::MAJOR
23
+ when 3,4 then send('mysql_connection', config)
24
+ end
25
+ end
26
+
27
+ def helpers_module
28
+ Skiima::Db::Helpers::Mysql
29
+ end
30
+ end
31
+ end
32
+
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ ## encoding: utf-8
39
+ #require 'skiima/db_adapters/base_mysql_adapter'
40
+ #
41
+ #gem 'mysql', '~> 2.9.1'
42
+ #require 'mysql'
43
+ #
44
+ #class Mysql
45
+ # class Time
46
+ # ###
47
+ # # This monkey patch is for test_additional_columns_from_join_table
48
+ # def to_date
49
+ # Date.new(year, month, day)
50
+ # end
51
+ # end
52
+ # class Stmt; include Enumerable end
53
+ # class Result; include Enumerable end
54
+ #end
55
+ #
56
+ #module Skiima
57
+ # # Establishes a connection to the database that's used by all Active Record objects.
58
+ # def self.mysql_connection(logger, config) # :nodoc:
59
+ # config = Skiima.symbolize_keys(config)
60
+ # host = config[:host]
61
+ # port = config[:port]
62
+ # socket = config[:socket]
63
+ # username = config[:username] ? config[:username].to_s : 'root'
64
+ # password = config[:password].to_s
65
+ # database = config[:database]
66
+ #
67
+ # mysql = Mysql.init
68
+ # mysql.ssl_set(config[:sslkey], config[:sslcert], config[:sslca], config[:sslcapath], config[:sslcipher]) if config[:sslca] || config[:sslkey]
69
+ #
70
+ # default_flags = Mysql.const_defined?(:CLIENT_MULTI_RESULTS) ? Mysql::CLIENT_MULTI_RESULTS : 0
71
+ # default_flags |= Mysql::CLIENT_FOUND_ROWS if Mysql.const_defined?(:CLIENT_FOUND_ROWS)
72
+ #
73
+ # options = [host, username, password, database, port, socket, default_flags]
74
+ # Skiima::DbAdapters::MysqlAdapter.new(mysql, logger, options, config)
75
+ # end
76
+ #
77
+ # module DbAdapters
78
+ # class MysqlAdapter < BaseMysqlAdapter
79
+ # attr_accessor :client_encoding
80
+ #
81
+ # ADAPTER_NAME = 'MySQL'
82
+ #
83
+ # # def exec_without_stmt(sql, name = 'SQL') # :nodoc:
84
+ # # # Some queries, like SHOW CREATE TABLE don't work through the prepared
85
+ # # # statement API. For those queries, we need to use this method. :'(
86
+ # # log(sql, name) do
87
+ # # result = @connection.query(sql)
88
+ # # cols = []
89
+ # # rows = []
90
+ #
91
+ # # if result
92
+ # # cols = result.fetch_fields.map { |field| field.name }
93
+ # # rows = result.to_a
94
+ # # result.free
95
+ # # end
96
+ # # ActiveRecord::Result.new(cols, rows)
97
+ # # end
98
+ # # end
99
+ #
100
+ # def execute_and_free(sql, name = nil)
101
+ # result = execute(sql, name)
102
+ # ret = yield result
103
+ # result.free
104
+ # ret
105
+ # end
106
+ #
107
+ # def begin_db_transaction #:nodoc:
108
+ # exec_without_stmt "BEGIN"
109
+ # rescue Mysql::Error
110
+ # # Transactions aren't supported
111
+ # end
112
+ #
113
+ # private
114
+ #
115
+ # def exec_stmt(sql, name)
116
+ # stmt = @connection.prepare(sql)
117
+ #
118
+ # begin
119
+ # stmt.execute
120
+ # rescue Mysql::Error => e
121
+ # # Older versions of MySQL leave the prepared statement in a bad
122
+ # # place when an error occurs. To support older mysql versions, we
123
+ # # need to close the statement and delete the statement from the
124
+ # # cache.
125
+ # stmt.close
126
+ # raise e
127
+ # end
128
+ #
129
+ # cols = nil
130
+ # if metadata = stmt.result_metadata
131
+ # cols = metadata.fetch_fields.map { |field| field.name }
132
+ # end
133
+ #
134
+ # result = yield [cols, stmt]
135
+ #
136
+ # stmt.result_metadata.free if cols
137
+ # stmt.free_result
138
+ # stmt.close
139
+ #
140
+ # result
141
+ # end
142
+ #
143
+ # def connect
144
+ # encoding = @config[:encoding]
145
+ # if encoding
146
+ # @connection.options(Mysql::SET_CHARSET_NAME, encoding) rescue nil
147
+ # end
148
+ #
149
+ # if @config[:sslca] || @config[:sslkey]
150
+ # @connection.ssl_set(@config[:sslkey], @config[:sslcert], @config[:sslca], @config[:sslcapath], @config[:sslcipher])
151
+ # end
152
+ #
153
+ # @connection.options(Mysql::OPT_CONNECT_TIMEOUT, @config[:connect_timeout]) if @config[:connect_timeout]
154
+ # @connection.options(Mysql::OPT_READ_TIMEOUT, @config[:read_timeout]) if @config[:read_timeout]
155
+ # @connection.options(Mysql::OPT_WRITE_TIMEOUT, @config[:write_timeout]) if @config[:write_timeout]
156
+ #
157
+ # @connection.real_connect(*@connection_options)
158
+ #
159
+ # # reconnect must be set after real_connect is called, because real_connect sets it to false internally
160
+ # @connection.reconnect = !!@config[:reconnect] if @connection.respond_to?(:reconnect=)
161
+ #
162
+ # version #gets version
163
+ #
164
+ # configure_connection
165
+ # end
166
+ #
167
+ # def configure_connection
168
+ # encoding = @config[:encoding]
169
+ # execute("SET NAMES '#{encoding}'", :skip_logging) if encoding
170
+ #
171
+ # # By default, MySQL 'where id is null' selects the last inserted id.
172
+ # # Turn this off. http://dev.rubyonrails.org/ticket/6778
173
+ # execute("SET SQL_AUTO_IS_NULL=0", :skip_logging)
174
+ # end
175
+ # end
176
+ # end
177
+ #end