activerecord-oracle_enhanced-adapter-with-schema 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.rspec +2 -0
  2. data/Gemfile +52 -0
  3. data/History.md +301 -0
  4. data/License.txt +20 -0
  5. data/README.md +123 -0
  6. data/RUNNING_TESTS.md +45 -0
  7. data/Rakefile +59 -0
  8. data/VERSION +1 -0
  9. data/activerecord-oracle_enhanced-adapter-with-schema.gemspec +130 -0
  10. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +5 -0
  11. data/lib/active_record/connection_adapters/oracle_enhanced.rake +105 -0
  12. data/lib/active_record/connection_adapters/oracle_enhanced_activerecord_patches.rb +41 -0
  13. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +1399 -0
  14. data/lib/active_record/connection_adapters/oracle_enhanced_base_ext.rb +121 -0
  15. data/lib/active_record/connection_adapters/oracle_enhanced_column.rb +146 -0
  16. data/lib/active_record/connection_adapters/oracle_enhanced_connection.rb +119 -0
  17. data/lib/active_record/connection_adapters/oracle_enhanced_context_index.rb +359 -0
  18. data/lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb +25 -0
  19. data/lib/active_record/connection_adapters/oracle_enhanced_cpk.rb +21 -0
  20. data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +46 -0
  21. data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +565 -0
  22. data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +494 -0
  23. data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +260 -0
  24. data/lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb +227 -0
  25. data/lib/active_record/connection_adapters/oracle_enhanced_schema_dumper.rb +260 -0
  26. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements.rb +428 -0
  27. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb +258 -0
  28. data/lib/active_record/connection_adapters/oracle_enhanced_structure_dump.rb +294 -0
  29. data/lib/active_record/connection_adapters/oracle_enhanced_tasks.rb +17 -0
  30. data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +1 -0
  31. data/lib/activerecord-oracle_enhanced-adapter-with-schema.rb +25 -0
  32. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +778 -0
  33. data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +332 -0
  34. data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +427 -0
  35. data/spec/active_record/connection_adapters/oracle_enhanced_core_ext_spec.rb +19 -0
  36. data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +113 -0
  37. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +1388 -0
  38. data/spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb +69 -0
  39. data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +141 -0
  40. data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +25 -0
  41. data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +378 -0
  42. data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +440 -0
  43. data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +1385 -0
  44. data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +339 -0
  45. data/spec/spec_helper.rb +189 -0
  46. metadata +260 -0
@@ -0,0 +1,260 @@
1
+ # define accessors before requiring ruby-plsql as these accessors are used in clob writing callback and should be
2
+ # available also if ruby-plsql could not be loaded
3
+ ActiveRecord::Base.class_eval do
4
+ if respond_to? :class_attribute
5
+ class_attribute :custom_create_method, :custom_update_method, :custom_delete_method
6
+ elsif respond_to? :class_inheritable_accessor
7
+ class_inheritable_accessor :custom_create_method, :custom_update_method, :custom_delete_method
8
+ end
9
+ end
10
+
11
+ require 'active_support'
12
+
13
+ module ActiveRecord #:nodoc:
14
+ module ConnectionAdapters #:nodoc:
15
+ module OracleEnhancedProcedures #:nodoc:
16
+
17
+ module ClassMethods
18
+ # Specify custom create method which should be used instead of Rails generated INSERT statement.
19
+ # Provided block should return ID of new record.
20
+ # Example:
21
+ # set_create_method do
22
+ # plsql.employees_pkg.create_employee(
23
+ # :p_first_name => first_name,
24
+ # :p_last_name => last_name,
25
+ # :p_employee_id => nil
26
+ # )[:p_employee_id]
27
+ # end
28
+ def set_create_method(&block)
29
+ include_with_custom_methods
30
+ self.custom_create_method = block
31
+ end
32
+
33
+ # Specify custom update method which should be used instead of Rails generated UPDATE statement.
34
+ # Example:
35
+ # set_update_method do
36
+ # plsql.employees_pkg.update_employee(
37
+ # :p_employee_id => id,
38
+ # :p_first_name => first_name,
39
+ # :p_last_name => last_name
40
+ # )
41
+ # end
42
+ def set_update_method(&block)
43
+ include_with_custom_methods
44
+ self.custom_update_method = block
45
+ end
46
+
47
+ # Specify custom delete method which should be used instead of Rails generated DELETE statement.
48
+ # Example:
49
+ # set_delete_method do
50
+ # plsql.employees_pkg.delete_employee(
51
+ # :p_employee_id => id
52
+ # )
53
+ # end
54
+ def set_delete_method(&block)
55
+ include_with_custom_methods
56
+ self.custom_delete_method = block
57
+ end
58
+
59
+ if ActiveRecord::VERSION::MAJOR < 3
60
+ def create_method_name_before_custom_methods #:nodoc:
61
+ if private_method_defined?(:create_without_timestamps) && defined?(ActiveRecord::VERSION) && ActiveRecord::VERSION::STRING.to_f >= 2.3
62
+ :create_without_timestamps
63
+ elsif private_method_defined?(:create_without_callbacks)
64
+ :create_without_callbacks
65
+ else
66
+ :create
67
+ end
68
+ end
69
+
70
+ def update_method_name_before_custom_methods #:nodoc:
71
+ if private_method_defined?(:update_without_dirty)
72
+ :update_without_dirty
73
+ elsif private_method_defined?(:update_without_timestamps) && defined?(ActiveRecord::VERSION) && ActiveRecord::VERSION::STRING.to_f >= 2.3
74
+ :update_without_timestamps
75
+ elsif private_method_defined?(:update_without_callbacks)
76
+ :update_without_callbacks
77
+ else
78
+ :update
79
+ end
80
+ end
81
+
82
+ def destroy_method_name_before_custom_methods #:nodoc:
83
+ if public_method_defined?(:destroy_without_callbacks)
84
+ :destroy_without_callbacks
85
+ else
86
+ :destroy
87
+ end
88
+ end
89
+ end
90
+
91
+ private
92
+
93
+ def include_with_custom_methods
94
+ unless included_modules.include? InstanceMethods
95
+ include InstanceMethods
96
+ end
97
+ end
98
+ end
99
+
100
+ module InstanceMethods #:nodoc:
101
+ def self.included(base)
102
+ # alias methods just for ActiveRecord 2.x
103
+ # for ActiveRecord 3.0 will just redefine create, update, delete methods which call super
104
+ if ActiveRecord::VERSION::MAJOR < 3
105
+ base.instance_eval do
106
+ alias_method :create_without_custom_method, create_method_name_before_custom_methods
107
+ alias_method create_method_name_before_custom_methods, :create_with_custom_method
108
+ alias_method :update_without_custom_method, update_method_name_before_custom_methods
109
+ alias_method update_method_name_before_custom_methods, :update_with_custom_method
110
+ alias_method :destroy_without_custom_method, destroy_method_name_before_custom_methods
111
+ alias_method destroy_method_name_before_custom_methods, :destroy_with_custom_method
112
+ private :create, :update
113
+ public :destroy
114
+ end
115
+ end
116
+ end
117
+
118
+ if ActiveRecord::VERSION::MAJOR >= 3
119
+ def destroy #:nodoc:
120
+ # check if class has custom delete method
121
+ if self.class.custom_delete_method
122
+ # wrap destroy in transaction
123
+ with_transaction_returning_status do
124
+ # run before/after callbacks defined in model
125
+ _run_destroy_callbacks { destroy_using_custom_method }
126
+ end
127
+ else
128
+ super
129
+ end
130
+ end
131
+ end
132
+
133
+ private
134
+
135
+ # Creates a record with custom create method
136
+ # and returns its id.
137
+ if ActiveRecord::VERSION::MAJOR < 3
138
+ def create_with_custom_method
139
+ # check if class has custom create method
140
+ self.class.custom_create_method ? create_using_custom_method : create_without_custom_method
141
+ end
142
+ else # ActiveRecord 3.x
143
+ def create
144
+ # check if class has custom create method
145
+ if self.class.custom_create_method
146
+ set_timestamps_before_custom_create_method
147
+ # run before/after callbacks defined in model
148
+ _run_create_callbacks { create_using_custom_method }
149
+ else
150
+ super
151
+ end
152
+ end
153
+ end
154
+
155
+ def create_using_custom_method
156
+ self.class.connection.log_custom_method("custom create method", "#{self.class.name} Create") do
157
+ self.id = instance_eval(&self.class.custom_create_method)
158
+ end
159
+ @new_record = false
160
+ # Starting from ActiveRecord 3.0.3 @persisted is used instead of @new_record
161
+ @persisted = true
162
+ id
163
+ end
164
+
165
+ # Updates the associated record with custom update method
166
+ # Returns the number of affected rows.
167
+ if ActiveRecord::VERSION::MAJOR < 3
168
+ def update_with_custom_method(attribute_names = @attributes.keys)
169
+ # check if class has custom create method
170
+ self.class.custom_update_method ? update_using_custom_method(attribute_names) : update_without_custom_method(attribute_names)
171
+ end
172
+ else # ActiveRecord 3.x
173
+ def update(attribute_names = @attributes.keys)
174
+ # check if class has custom update method
175
+ if self.class.custom_update_method
176
+ set_timestamps_before_custom_update_method
177
+ # run before/after callbacks defined in model
178
+ _run_update_callbacks do
179
+ # update just dirty attributes
180
+ if partial_updates?
181
+ # Serialized attributes should always be written in case they've been
182
+ # changed in place.
183
+ update_using_custom_method(changed | (attributes.keys & self.class.serialized_attributes.keys))
184
+ else
185
+ update_using_custom_method(attribute_names)
186
+ end
187
+ end
188
+ else
189
+ super
190
+ end
191
+ end
192
+ end
193
+
194
+ def update_using_custom_method(attribute_names)
195
+ return 0 if attribute_names.empty?
196
+ self.class.connection.log_custom_method("custom update method with #{self.class.primary_key}=#{self.id}", "#{self.class.name} Update") do
197
+ instance_eval(&self.class.custom_update_method)
198
+ end
199
+ 1
200
+ end
201
+
202
+ # Deletes the record in the database with custom delete method
203
+ # and freezes this instance to reflect that no changes should
204
+ # be made (since they can't be persisted).
205
+ if ActiveRecord::VERSION::MAJOR < 3
206
+ def destroy_with_custom_method
207
+ # check if class has custom delete method
208
+ self.class.custom_delete_method ? destroy_using_custom_method : destroy_without_custom_method
209
+ end
210
+ end
211
+
212
+ def destroy_using_custom_method
213
+ unless new_record? || @destroyed
214
+ self.class.connection.log_custom_method("custom delete method with #{self.class.primary_key}=#{self.id}", "#{self.class.name} Destroy") do
215
+ instance_eval(&self.class.custom_delete_method)
216
+ end
217
+ end
218
+
219
+ @destroyed = true
220
+ freeze
221
+ end
222
+
223
+ if ActiveRecord::VERSION::MAJOR >= 3
224
+ def set_timestamps_before_custom_create_method
225
+ if record_timestamps
226
+ current_time = current_time_from_proper_timezone
227
+
228
+ write_attribute('created_at', current_time) if respond_to?(:created_at) && created_at.nil?
229
+ write_attribute('created_on', current_time) if respond_to?(:created_on) && created_on.nil?
230
+
231
+ write_attribute('updated_at', current_time) if respond_to?(:updated_at) && updated_at.nil?
232
+ write_attribute('updated_on', current_time) if respond_to?(:updated_on) && updated_on.nil?
233
+ end
234
+ end
235
+
236
+ def set_timestamps_before_custom_update_method
237
+ if record_timestamps && (!partial_updates? || changed?)
238
+ current_time = current_time_from_proper_timezone
239
+
240
+ write_attribute('updated_at', current_time) if respond_to?(:updated_at)
241
+ write_attribute('updated_on', current_time) if respond_to?(:updated_on)
242
+ end
243
+ end
244
+ end
245
+
246
+ end
247
+
248
+ end
249
+ end
250
+ end
251
+
252
+ ActiveRecord::Base.class_eval do
253
+ extend ActiveRecord::ConnectionAdapters::OracleEnhancedProcedures::ClassMethods
254
+ end
255
+
256
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.class_eval do
257
+ # public alias to log method which could be used from other objects
258
+ alias_method :log_custom_method, :log
259
+ public :log_custom_method
260
+ end
@@ -0,0 +1,227 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ class OracleEnhancedForeignKeyDefinition < Struct.new(:from_table, :to_table, :options) #:nodoc:
4
+ end
5
+
6
+ class OracleEnhancedSynonymDefinition < Struct.new(:name, :table_owner, :table_name, :db_link) #:nodoc:
7
+ end
8
+
9
+ class OracleEnhancedIndexDefinition < Struct.new(:table, :name, :unique, :type, :parameters, :statement_parameters,
10
+ :tablespace, :columns) #:nodoc:
11
+ end
12
+
13
+ module OracleEnhancedColumnDefinition
14
+ def self.included(base) #:nodoc:
15
+ base.class_eval do
16
+ alias_method_chain :to_sql, :virtual_columns
17
+ alias to_s :to_sql
18
+ end
19
+ end
20
+
21
+ def to_sql_with_virtual_columns
22
+ if type == :virtual
23
+ sql_type = base.type_to_sql(default[:type], limit, precision, scale) if default[:type]
24
+ "#{base.quote_column_name(name)} #{sql_type} AS (#{default[:as]})"
25
+ else
26
+ to_sql_without_virtual_columns
27
+ end
28
+ end
29
+
30
+ def lob?
31
+ ['CLOB', 'BLOB'].include?(sql_type)
32
+ end
33
+ end
34
+
35
+ module OracleEnhancedSchemaDefinitions #:nodoc:
36
+ def self.included(base)
37
+ base::TableDefinition.class_eval do
38
+ include OracleEnhancedTableDefinition
39
+ end
40
+
41
+ base::ColumnDefinition.class_eval do
42
+ include OracleEnhancedColumnDefinition
43
+ end
44
+
45
+ # Available starting from ActiveRecord 2.1
46
+ base::Table.class_eval do
47
+ include OracleEnhancedTable
48
+ end if defined?(base::Table)
49
+ end
50
+ end
51
+
52
+ module OracleEnhancedTableDefinition
53
+ class ForeignKey < Struct.new(:base, :to_table, :options) #:nodoc:
54
+ def to_sql
55
+ base.foreign_key_definition(to_table, options)
56
+ end
57
+ alias to_s :to_sql
58
+ end
59
+
60
+ def self.included(base) #:nodoc:
61
+ base.class_eval do
62
+ alias_method_chain :references, :foreign_keys
63
+ alias_method_chain :to_sql, :foreign_keys
64
+
65
+ alias_method_chain :column, :virtual_columns
66
+ end
67
+ end
68
+
69
+ def raw(name, options={})
70
+ column(name, :raw, options)
71
+ end
72
+
73
+ def virtual(* args)
74
+ options = args.extract_options!
75
+ column_names = args
76
+ column_names.each { |name| column(name, :virtual, options) }
77
+ end
78
+
79
+ def column_with_virtual_columns(name, type, options = {})
80
+ if type == :virtual
81
+ default = {:type => options[:type]}
82
+ if options[:as]
83
+ default[:as] = options[:as]
84
+ elsif options[:default]
85
+ warn "[DEPRECATION] virtual column `:default` option is deprecated. Please use `:as` instead."
86
+ default[:as] = options[:default]
87
+ else
88
+ raise "No virtual column definition found."
89
+ end
90
+ options[:default] = default
91
+ end
92
+ column_without_virtual_columns(name, type, options)
93
+ end
94
+
95
+ # Adds a :foreign_key option to TableDefinition.references.
96
+ # If :foreign_key is true, a foreign key constraint is added to the table.
97
+ # You can also specify a hash, which is passed as foreign key options.
98
+ #
99
+ # ===== Examples
100
+ # ====== Add goat_id column and a foreign key to the goats table.
101
+ # t.references(:goat, :foreign_key => true)
102
+ # ====== Add goat_id column and a cascading foreign key to the goats table.
103
+ # t.references(:goat, :foreign_key => {:dependent => :delete})
104
+ #
105
+ # Note: No foreign key is created if :polymorphic => true is used.
106
+ # Note: If no name is specified, the database driver creates one for you!
107
+ def references_with_foreign_keys(*args)
108
+ options = args.extract_options!
109
+ fk_options = options.delete(:foreign_key)
110
+
111
+ if fk_options && !options[:polymorphic]
112
+ fk_options = {} if fk_options == true
113
+ args.each { |to_table| foreign_key(to_table, fk_options) }
114
+ end
115
+
116
+ references_without_foreign_keys(*(args << options))
117
+ end
118
+
119
+ # Defines a foreign key for the table. +to_table+ can be a single Symbol, or
120
+ # an Array of Symbols. See SchemaStatements#add_foreign_key
121
+ #
122
+ # ===== Examples
123
+ # ====== Creating a simple foreign key
124
+ # t.foreign_key(:people)
125
+ # ====== Defining the column
126
+ # t.foreign_key(:people, :column => :sender_id)
127
+ # ====== Creating a named foreign key
128
+ # t.foreign_key(:people, :column => :sender_id, :name => 'sender_foreign_key')
129
+ # ====== Defining the column of the +to_table+.
130
+ # t.foreign_key(:people, :column => :sender_id, :primary_key => :person_id)
131
+ def foreign_key(to_table, options = {})
132
+ if @base.respond_to?(:supports_foreign_keys?) && @base.supports_foreign_keys?
133
+ to_table = to_table.to_s.pluralize if ActiveRecord::Base.pluralize_table_names
134
+ foreign_keys << ForeignKey.new(@base, to_table, options)
135
+ else
136
+ raise ArgumentError, "this ActiveRecord adapter is not supporting foreign_key definition"
137
+ end
138
+ end
139
+
140
+ def to_sql_with_foreign_keys #:nodoc:
141
+ sql = to_sql_without_foreign_keys
142
+ sql << ', ' << (foreign_keys * ', ') unless foreign_keys.blank?
143
+ sql
144
+ end
145
+
146
+ def lob_columns
147
+ columns.select(&:lob?)
148
+ end
149
+
150
+ private
151
+ def foreign_keys
152
+ @foreign_keys ||= []
153
+ end
154
+ end
155
+
156
+ module OracleEnhancedTable
157
+ def self.included(base) #:nodoc:
158
+ base.class_eval do
159
+ alias_method_chain :references, :foreign_keys
160
+ end
161
+ end
162
+
163
+ # Adds a new foreign key to the table. +to_table+ can be a single Symbol, or
164
+ # an Array of Symbols. See SchemaStatements#add_foreign_key
165
+ #
166
+ # ===== Examples
167
+ # ====== Creating a simple foreign key
168
+ # t.foreign_key(:people)
169
+ # ====== Defining the column
170
+ # t.foreign_key(:people, :column => :sender_id)
171
+ # ====== Creating a named foreign key
172
+ # t.foreign_key(:people, :column => :sender_id, :name => 'sender_foreign_key')
173
+ # ====== Defining the column of the +to_table+.
174
+ # t.foreign_key(:people, :column => :sender_id, :primary_key => :person_id)
175
+ def foreign_key(to_table, options = {})
176
+ if @base.respond_to?(:supports_foreign_keys?) && @base.supports_foreign_keys?
177
+ to_table = to_table.to_s.pluralize if ActiveRecord::Base.pluralize_table_names
178
+ @base.add_foreign_key(@table_name, to_table, options)
179
+ else
180
+ raise ArgumentError, "this ActiveRecord adapter is not supporting foreign_key definition"
181
+ end
182
+ end
183
+
184
+ # Remove the given foreign key from the table.
185
+ #
186
+ # ===== Examples
187
+ # ====== Remove the suppliers_company_id_fk in the suppliers table.
188
+ # t.remove_foreign_key :companies
189
+ # ====== Remove the foreign key named accounts_branch_id_fk in the accounts table.
190
+ # remove_foreign_key :column => :branch_id
191
+ # ====== Remove the foreign key named party_foreign_key in the accounts table.
192
+ # remove_index :name => :party_foreign_key
193
+ def remove_foreign_key(options = {})
194
+ @base.remove_foreign_key(@table_name, options)
195
+ end
196
+
197
+ # Adds a :foreign_key option to TableDefinition.references.
198
+ # If :foreign_key is true, a foreign key constraint is added to the table.
199
+ # You can also specify a hash, which is passed as foreign key options.
200
+ #
201
+ # ===== Examples
202
+ # ====== Add goat_id column and a foreign key to the goats table.
203
+ # t.references(:goat, :foreign_key => true)
204
+ # ====== Add goat_id column and a cascading foreign key to the goats table.
205
+ # t.references(:goat, :foreign_key => {:dependent => :delete})
206
+ #
207
+ # Note: No foreign key is created if :polymorphic => true is used.
208
+ def references_with_foreign_keys(*args)
209
+ options = args.extract_options!
210
+ polymorphic = options[:polymorphic]
211
+ fk_options = options.delete(:foreign_key)
212
+
213
+ references_without_foreign_keys(*(args << options))
214
+ # references_without_foreign_keys adds {:type => :integer}
215
+ args.extract_options!
216
+ if fk_options && !polymorphic
217
+ fk_options = {} if fk_options == true
218
+ args.each { |to_table| foreign_key(to_table, fk_options) }
219
+ end
220
+ end
221
+ end
222
+ end
223
+ end
224
+
225
+ ActiveRecord::ConnectionAdapters.class_eval do
226
+ include ActiveRecord::ConnectionAdapters::OracleEnhancedSchemaDefinitions
227
+ end