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