skiima 0.1.000 → 0.2.2

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.
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