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
@@ -1,187 +0,0 @@
1
- # encoding: utf-8
2
- module Skiima
3
- module DbAdapters
4
- class Base
5
- attr_accessor :version
6
-
7
- def initialize(connection, logger = nil) #:nodoc:
8
- super()
9
-
10
- @active = nil
11
- @connection = connection
12
- @in_use = false
13
- @last_use = false
14
- @logger = logger
15
- @visitor = nil
16
- end
17
-
18
- def adapter_name
19
- 'Base'
20
- end
21
-
22
- def supports_ddl_transactions?
23
- false
24
- end
25
-
26
- def supported_objects
27
- [] # this should be overridden by concrete adapters
28
- end
29
-
30
- def drop(type, name, opts = {})
31
- send("drop_#{type}", name, opts) if supported_objects.include? type.to_sym
32
- end
33
-
34
- def object_exists?(type, name, opts = {})
35
- send("#{type}_exists?", name, opts) if supported_objects.include? type.to_sym
36
- end
37
-
38
- # Does this adapter support savepoints? PostgreSQL and MySQL do,
39
- # SQLite < 3.6.8 does not.
40
- def supports_savepoints?
41
- false
42
- end
43
-
44
- def active?
45
- @active != false
46
- end
47
-
48
- # Disconnects from the database if already connected, and establishes a
49
- # new connection with the database.
50
- def reconnect!
51
- @active = true
52
- end
53
-
54
- # Disconnects from the database if already connected. Otherwise, this
55
- # method does nothing.
56
- def disconnect!
57
- @active = false
58
- end
59
-
60
- # Reset the state of this connection, directing the DBMS to clear
61
- # transactions and other connection-related server-side state. Usually a
62
- # database-dependent operation.
63
- #
64
- # The default implementation does nothing; the implementation should be
65
- # overridden by concrete adapters.
66
- def reset!
67
- # this should be overridden by concrete adapters
68
- end
69
-
70
- ###
71
- # Clear any caching the database adapter may be doing, for example
72
- # clearing the prepared statement cache. This is database specific.
73
- def clear_cache!
74
- # this should be overridden by concrete adapters
75
- end
76
-
77
- # Returns true if its required to reload the connection between requests for development mode.
78
- # This is not the case for Ruby/MySQL and it's not necessary for any adapters except SQLite.
79
- def requires_reloading?
80
- false
81
- end
82
-
83
- # Checks whether the connection to the database is still active (i.e. not stale).
84
- # This is done under the hood by calling <tt>active?</tt>. If the connection
85
- # is no longer active, then this method will reconnect to the database.
86
- def verify!(*ignored)
87
- reconnect! unless active?
88
- end
89
-
90
- # Provides access to the underlying database driver for this adapter. For
91
- # example, this method returns a Mysql object in case of MysqlAdapter,
92
- # and a PGconn object in case of PostgreSQLAdapter.
93
- #
94
- # This is useful for when you need to call a proprietary method such as
95
- # PostgreSQL's lo_* methods.
96
- def raw_connection
97
- @connection
98
- end
99
-
100
- attr_reader :open_transactions
101
-
102
- def increment_open_transactions
103
- @open_transactions += 1
104
- end
105
-
106
- def decrement_open_transactions
107
- @open_transactions -= 1
108
- end
109
-
110
- def transaction_joinable=(joinable)
111
- @transaction_joinable = joinable
112
- end
113
-
114
- def create_savepoint
115
- end
116
-
117
- def rollback_to_savepoint
118
- end
119
-
120
- def release_savepoint
121
- end
122
-
123
- def current_savepoint_name
124
- "active_record_#{open_transactions}"
125
- end
126
-
127
- # Check the connection back in to the connection pool
128
- def close
129
- disconnect!
130
- end
131
-
132
- # Disconnects from the database if already connected. Otherwise, this
133
- # method does nothing.
134
- def disconnect!
135
- clear_cache!
136
- @connection.close rescue nil
137
- end
138
-
139
- protected
140
-
141
- def log(sql, name = "SQL", binds = [])
142
- @logger.debug("Executing SQL Statement: #{name}")
143
- @logger.debug(sql)
144
- result = yield
145
- @logger.debug("SUCCESS!")
146
- result
147
- rescue Exception => e
148
- message = "#{e.class.name}: #{e.message}: #{sql}"
149
- @logger.debug message if @logger
150
- exception = translate_exception(e, message)
151
- exception.set_backtrace e.backtrace
152
- raise exception
153
- end
154
-
155
- def translate_exception(e, message)
156
- # override in derived class
157
- raise "override in derived class"
158
- end
159
-
160
- end
161
-
162
- class Resolver
163
- attr_accessor :db, :adapter_method
164
-
165
- def initialize(db_config)
166
- @db = Skiima.symbolize_keys(db_config)
167
- adapter_specified?
168
- load_adapter
169
- @adapter_method = "#{db[:adapter]}_connection"
170
- end
171
-
172
- private
173
-
174
- def adapter_specified?
175
- raise(AdapterNotSpecified, "database configuration does not specify adapter") unless db.key?(:adapter)
176
- end
177
-
178
- def load_adapter
179
- begin
180
- require "skiima/db_adapters/#{db[:adapter]}_adapter"
181
- rescue => e
182
- raise LoadError, "Adapter does not exist: #{db[:adapter]} - (#{e.message})", e.backtrace
183
- end
184
- end
185
- end
186
- end
187
- end
@@ -1,308 +0,0 @@
1
- # encoding: utf-8
2
- module Skiima
3
- module DbAdapters
4
- class BaseMysqlAdapter < Base
5
- attr_accessor :version
6
-
7
- LOST_CONNECTION_ERROR_MESSAGES = [
8
- "Server shutdown in progress",
9
- "Broken pipe",
10
- "Lost connection to MySQL server during query",
11
- "MySQL server has gone away" ]
12
-
13
- # FIXME: Make the first parameter more similar for the two adapters
14
- def initialize(connection, logger, connection_options, config)
15
- super(connection, logger)
16
- @connection_options, @config = connection_options, config
17
- @quoted_column_names, @quoted_table_names = {}, {}
18
- end
19
-
20
- def version
21
- @version ||= @connection.info[:version].scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i }
22
- end
23
-
24
- def adapter_name #:nodoc:
25
- self.class::ADAPTER_NAME
26
- end
27
-
28
- # Returns true, since this connection adapter supports migrations.
29
- def supports_migrations?
30
- true
31
- end
32
-
33
- def supports_primary_key?
34
- true
35
- end
36
-
37
- # Returns true, since this connection adapter supports savepoints.
38
- def supports_savepoints?
39
- true
40
- end
41
-
42
- # Must return the Mysql error number from the exception, if the exception has an
43
- # error number.
44
- def error_number(exception) # :nodoc:
45
- raise NotImplementedError
46
- end
47
-
48
- def disable_referential_integrity(&block) #:nodoc:
49
- old = select_value("SELECT @@FOREIGN_KEY_CHECKS")
50
-
51
- begin
52
- update("SET FOREIGN_KEY_CHECKS = 0")
53
- yield
54
- ensure
55
- update("SET FOREIGN_KEY_CHECKS = #{old}")
56
- end
57
- end
58
-
59
- # MysqlAdapter has to free a result after using it, so we use this method to write
60
- # stuff in a abstract way without concerning ourselves about whether it needs to be
61
- # explicitly freed or not.
62
- def execute_and_free(sql, name = nil) #:nodoc:
63
- yield execute(sql, name)
64
- end
65
-
66
- # Executes the SQL statement in the context of this connection.
67
- def execute(sql, name = nil)
68
- if name == :skip_logging
69
- @connection.query(sql)
70
- else
71
- log(sql, name) { @connection.query(sql) }
72
- end
73
- rescue StatementInvalid => exception
74
- if exception.message.split(":").first =~ /Packets out of order/
75
- raise StatementInvalid, "'Packets out of order' error was received from the database. Please update your mysql bindings (gem install mysql) and read http://dev.mysql.com/doc/mysql/en/password-hashing.html for more information. If you're on Windows, use the Instant Rails installer to get the updated mysql bindings."
76
- else
77
- raise
78
- end
79
- end
80
-
81
- def begin_db_transaction
82
- execute "BEGIN"
83
- rescue Exception
84
- # Transactions aren't supported
85
- end
86
-
87
- def commit_db_transaction #:nodoc:
88
- execute "COMMIT"
89
- rescue Exception
90
- # Transactions aren't supported
91
- end
92
-
93
- def rollback_db_transaction #:nodoc:
94
- execute "ROLLBACK"
95
- rescue Exception
96
- # Transactions aren't supported
97
- end
98
-
99
- def create_savepoint
100
- execute("SAVEPOINT #{current_savepoint_name}")
101
- end
102
-
103
- def rollback_to_savepoint
104
- execute("ROLLBACK TO SAVEPOINT #{current_savepoint_name}")
105
- end
106
-
107
- def release_savepoint
108
- execute("RELEASE SAVEPOINT #{current_savepoint_name}")
109
- end
110
-
111
- def supported_objects
112
- [:database, :table, :view, :index]
113
- end
114
-
115
- def tables(name = nil, database = nil, like = nil)
116
- sql = "SHOW FULL TABLES "
117
- sql << "IN #{database} " if database
118
- sql << "WHERE table_type = 'BASE TABLE' "
119
- sql << "LIKE '#{like}' " if like
120
-
121
- execute_and_free(sql, 'SCHEMA') do |result|
122
- result.collect { |field| field.first }
123
- end
124
- end
125
-
126
- def views(name = nil, database = nil, like = nil)
127
- sql = "SHOW FULL TABLES "
128
- sql << "IN #{database} " if database
129
- sql << "WHERE table_type = 'VIEW' "
130
- sql << "LIKE '#{like}' " if like
131
-
132
- execute_and_free(sql, 'SCHEMA') do |result|
133
- result.collect { |field| field.first }
134
- end
135
- end
136
-
137
- def indexes(name = nil, database = nil, table = nil)
138
- sql = "SHOW INDEX "
139
- sql << "IN #{table} "
140
- sql << "IN #{database} " if database
141
- sql << "WHERE key_name = '#{name}'" if name
142
-
143
- execute_and_free(sql, 'SCHEMA') do |result|
144
- result.collect { |field| field[2] }
145
- end
146
- end
147
-
148
- "select routine_schema, routine_name, routine_type from routines;"
149
-
150
- def procs(name = nil, database = nil, like = nil)
151
- sql = "SELECT r.routine_name "
152
- sql << "FROM information_schema.routines r "
153
- sql << "WHERE r.routine_type = 'PROCEDURE' "
154
- sql << "AND r.routine_name LIKE '#{like}' " if like
155
- sql << "AND r.routine_schema = #{database} " if database
156
-
157
- execute_and_free(sql, 'SCHEMA') do |result|
158
- result.collect { |field| field.first }
159
- end
160
- end
161
-
162
- def database_exists?(name)
163
- #stub
164
- end
165
-
166
- def table_exists?(name)
167
- return false unless name
168
- return true if tables(nil, nil, name).any?
169
-
170
- name = name.to_s
171
- schema, table = name.split('.', 2)
172
-
173
- unless table # A table was provided without a schema
174
- table = schema
175
- schema = nil
176
- end
177
-
178
- tables(nil, schema, table).any?
179
- end
180
-
181
- def view_exists?(name)
182
- return false unless name
183
- return true if views(nil, nil, name).any?
184
-
185
- name = name.to_s
186
- schema, view = name.split('.', 2)
187
-
188
- unless view # A table was provided without a schema
189
- view = schema
190
- schema = nil
191
- end
192
-
193
- views(nil, schema, view).any?
194
- end
195
-
196
- def index_exists?(name, opts = {})
197
- target = opts[:attr] ? opts[:attr][0] : nil
198
- raise "requires target object" unless target
199
-
200
- return false unless table_exists?(target) #mysql blows up when table doesn't exist
201
- return false unless name
202
- return true if indexes(name, nil, target).any?
203
-
204
- name = name.to_s
205
- schema, target = name.split('.', 2)
206
-
207
- unless target # A table was provided without a schema
208
- target = schema
209
- schema = nil
210
- end
211
-
212
- indexes(name, schema, target).any?
213
- end
214
-
215
- def proc_exists?(name, opts = {})
216
- return false unless name
217
- return true if procs(nil, nil, name).any?
218
-
219
- name = name.to_s
220
- schema, proc = name.split('.', 2)
221
-
222
- unless proc # A table was provided without a schema
223
- proc = schema
224
- schema = nil
225
- end
226
-
227
- procs(name, schema, proc).any?
228
- end
229
-
230
- def drop_database(name, opts = {})
231
- "DROP DATABASE IF EXISTS #{name}"
232
- end
233
-
234
- def drop_table(name, opts = {})
235
- "DROP TABLE IF EXISTS #{name}"
236
- end
237
-
238
- def drop_view(name, opts = {})
239
- "DROP VIEW IF EXISTS #{name}"
240
- end
241
-
242
- def drop_index(name, opts = {})
243
- target = opts[:attr].first if opts[:attr]
244
- raise "requires target object" unless target
245
-
246
- "DROP INDEX #{name} ON #{target}"
247
- end
248
-
249
- def column_definitions(table_name)
250
- # "SHOW FULL FIELDS FROM #{quote_table_name(table_name)}"
251
- end
252
-
253
- def column_names(table_name)
254
- sql = "SHOW FULL FIELDS FROM #{quote_table_name(table_name)}"
255
- execute_and_free(sql, 'SCHEMA') do |result|
256
- result.collect { |field| field.first }
257
- end
258
- end
259
-
260
- def quote_column_name(name) #:nodoc:
261
- @quoted_column_names[name] ||= "`#{name.to_s.gsub('`', '``')}`"
262
- end
263
-
264
- def quote_table_name(name) #:nodoc:
265
- @quoted_table_names[name] ||= quote_column_name(name).gsub('.', '`.`')
266
- end
267
-
268
- def current_database
269
- select_value 'SELECT DATABASE() as db'
270
- end
271
-
272
- # Returns the database character set.
273
- def charset
274
- show_variable 'character_set_database'
275
- end
276
-
277
- # Returns the database collation strategy.
278
- def collation
279
- show_variable 'collation_database'
280
- end
281
-
282
- def show_variable(name)
283
- # variables = select_all("SHOW VARIABLES LIKE '#{name}'")
284
- # variables.first['Value'] unless variables.empty?
285
- end
286
-
287
- protected
288
-
289
- def translate_exception(exception, message)
290
- exception
291
- # case error_number(exception)
292
- # when 1062
293
- # RecordNotUnique.new(message, exception)
294
- # when 1452
295
- # InvalidForeignKey.new(message, exception)
296
- # else
297
- # super
298
- # end
299
- end
300
-
301
- private
302
-
303
- def supports_views?
304
- version[0] >= 5
305
- end
306
- end
307
- end
308
- end