activerecord-jdbcteradata-adapter 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- activerecord-jdbcteradata-adapter (0.2.0)
4
+ activerecord-jdbcteradata-adapter (0.3.1)
5
5
  activerecord
6
6
  activerecord-jdbc-adapter
7
7
  jdbc-teradata
@@ -23,11 +23,11 @@ GEM
23
23
  multi_json (~> 1.0)
24
24
  arel (3.0.2)
25
25
  builder (3.0.4)
26
- diff-lcs (1.2.1)
26
+ diff-lcs (1.2.2)
27
27
  i18n (0.6.1)
28
28
  jdbc-teradata (0.2.0)
29
29
  multi_json (1.7.2)
30
- rake (10.0.3)
30
+ rake (10.0.4)
31
31
  rspec (2.13.0)
32
32
  rspec-core (~> 2.13.0)
33
33
  rspec-expectations (~> 2.13.0)
@@ -40,6 +40,7 @@ GEM
40
40
 
41
41
  PLATFORMS
42
42
  java
43
+ ruby
43
44
 
44
45
  DEPENDENCIES
45
46
  activerecord-jdbcteradata-adapter!
data/README.md CHANGED
@@ -5,4 +5,7 @@
5
5
  ## DESCRIPTION:
6
6
 
7
7
  This is an ActiveRecord driver for Teradata using JDBC running under JRuby.
8
+
8
9
  It is still under heavy development.
10
+
11
+ Right now I am testing this code with the ActiveRecord test suite.
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "activerecord-jdbcteradata-adapter"
3
- s.version = "0.3.0"
3
+ s.version = "0.3.1"
4
4
  s.authors = ["Chris Parker"]
5
5
  s.email = [ "mrcsparker@gmail.com"]
6
6
  s.homepage = "https://github.com/mrcsparker/activerecord-jdbcteradata-adapter"
@@ -25,7 +25,6 @@ module Arel
25
25
  else
26
26
  sql = super
27
27
  end
28
-
29
28
  sql
30
29
  end
31
30
 
@@ -53,9 +52,9 @@ module Arel
53
52
  primary_key = @connection.columns(table_name).detect { |column| column.primary }
54
53
  return primary_key.name if primary_key
55
54
  # Look for an id column. Return it, without changing case, to cover dbs with a case-sensitive collation.
56
- columns(table_name).each { |column| return column.name if column.name =~ /^id$/i }
55
+ @connection.columns(table_name).each { |column| return column.name if column.name =~ /^id$/i }
57
56
  # Give up and provide something which is going to crash almost certainly
58
- columns(table_name)[0].name
57
+ @connection.columns(table_name)[0].name
59
58
  end
60
59
 
61
60
  def add_limit_offset!(sql, options)
@@ -7,6 +7,8 @@ module ::ArJdbc
7
7
  [ /teradata/i, lambda { |cfg, column| column.extend(::ArJdbc::Teradata::Column) } ]
8
8
  end
9
9
 
10
+ ## ActiveRecord::ConnectionAdapters::JdbcAdapter
11
+
10
12
  #- jdbc_connection_class
11
13
 
12
14
  #- jdbc_column_class
@@ -16,6 +18,19 @@ module ::ArJdbc
16
18
  #- adapter_spec
17
19
 
18
20
  #+ modify_types
21
+ def modify_types(types)
22
+ super(types)
23
+ types[:primary_key] = 'INTEGER PRIMARY KEY NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1 MINVALUE -2147483647 MAXVALUE 1000000000 NO CYCLE)',
24
+ types[:string][:limit] = 255
25
+ types[:integer][:limit] = nil
26
+ types
27
+ end
28
+
29
+ # Make sure that integer gets specified as INTEGER and not INTEGER(11)
30
+ def type_to_sql(type, limit = nil, precision = nil, scale = nil)
31
+ limit = nil if type.to_sym == :integer
32
+ super(type, limit, precision, scale)
33
+ end
19
34
 
20
35
  #+ adapter_name
21
36
  def adapter_name
@@ -41,7 +56,6 @@ module ::ArJdbc
41
56
 
42
57
  #+ native_database_types
43
58
  def native_database_types
44
-
45
59
  super.merge({
46
60
  :primary_key => 'INTEGER PRIMARY KEY NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1 MINVALUE -2147483647 MAXVALUE 1000000000 NO CYCLE)',
47
61
  :string => { :name => 'VARCHAR', :limit => 255 },
@@ -50,15 +64,18 @@ module ::ArJdbc
50
64
  :decimal => { :name => "DECIMAL" },
51
65
  :datetime => { :name => "TIMESTAMP" },
52
66
  :timestamp => { :name => "TIMESTAMP" },
53
- :time => { :name => "TIME" },
67
+ :time => { :name => "TIMESTAMP" },
54
68
  :date => { :name => "DATE" },
55
69
  :binary => { :name => "BLOB" },
56
- :boolean => { :name => "BYTEINT", :limit => 1 },
70
+ :boolean => { :name => "BYTEINT" },
57
71
  :raw => { :name => "BYTE" }
58
72
  })
59
73
  end
60
74
 
61
75
  #- database_name
76
+ def database_name
77
+ @connection.config[:database]
78
+ end
62
79
 
63
80
  #- native_sql_to_type
64
81
 
@@ -96,12 +113,12 @@ module ::ArJdbc
96
113
  output = nil
97
114
  pk = primary_key(table)
98
115
  if pk
99
- output = execute("SELECT TOP 1 #{pk} FROM #{table} ORDER BY #{pk} DESC").first[pk]
116
+ output = execute("SELECT TOP 1 #{quote_column_name(pk)} FROM #{quote_table_name(table)} ORDER BY #{quote_column_name(pk)} DESC").first[pk]
100
117
  end
101
118
  output
102
119
  end
103
120
 
104
- #- select
121
+ #- select
105
122
 
106
123
  #- select_rows
107
124
 
@@ -110,6 +127,11 @@ module ::ArJdbc
110
127
  #- tables
111
128
 
112
129
  #- table_exists?
130
+ def table_exists?(table_name)
131
+ return false unless table_name
132
+ output = execute("SELECT count(*) as table_count FROM dbc.tables WHERE TableName = '#{table_name}' AND DatabaseName = '#{database_name}'")
133
+ output.first['table_count'] > 0
134
+ end
113
135
 
114
136
  #+ indexes
115
137
  # TODO: Multiple indexes per column
@@ -118,7 +140,7 @@ module ::ArJdbc
118
140
  result = select_rows("SELECT" <<
119
141
  " DatabaseName, TableName, ColumnName, IndexType, IndexName, UniqueFlag" <<
120
142
  " FROM DBC.Indices" <<
121
- " WHERE TableName = '#{table_name}'")
143
+ " WHERE TableName = '#{table_name}' AND DatabaseName = '#{database_name}'")
122
144
 
123
145
  result.map do |row|
124
146
  idx_database_name = row[0].to_s.strip
@@ -155,24 +177,142 @@ module ::ArJdbc
155
177
 
156
178
  #- to_sql
157
179
 
180
+ ## ConnectionAdapters::Abstract::SchemaStatements
181
+
182
+ #- table_exists?
183
+
184
+ #- index_exists?
185
+
186
+ #- columns
187
+
188
+ #- column_exists?
189
+
190
+ #- create_table
191
+
192
+ #- change_table
193
+
194
+ #+ rename_table
195
+
196
+ #- drop_table
197
+
198
+ #- add_column
199
+
200
+ #- remove_column
201
+ def remove_column(table_name, *column_names) #:nodoc:
202
+ for column_name in column_names.flatten
203
+ execute "ALTER TABLE #{quote_table_name(table_name)} DROP COLUMN #{quote_column_name(column_name)}"
204
+ end
205
+ end
206
+
207
+ #+ change_column
208
+ # This only works in a VERY limited fashion. For example, VARCHAR columns
209
+ # cannot be shortened, one column type cannot be converted to another.
210
+ def change_column(table_name, column_name, type, options = {}) #:nodoc:
211
+ change_column_sql = "ALTER TABLE #{quote_table_name(table_name)} " <<
212
+ "ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit])}"
213
+ add_column_options!(change_column_sql, options)
214
+ execute(change_column_sql)
215
+ end
216
+
217
+ #+ change_column_default
218
+ def change_column_default(table_name, column_name, default) #:nodoc:
219
+ execute "ALTER TABLE #{quote_table_name(table_name)} " +
220
+ "ADD #{quote_column_name(column_name)} DEFAULT #{quote(default)}"
221
+ end
222
+
223
+ #+ rename_column
224
+ def rename_column(table_name, column_name, new_column_name) #:nodoc:
225
+ execute "ALTER TABLE #{quote_table_name(table_name)} " <<
226
+ "RENAME COLUMN #{quote_column_name(column_name)} to #{quote_column_name(new_column_name)}"
227
+ end
228
+
229
+ #- add_index
230
+
231
+ #- remove_index
232
+
233
+ #- rename_index
234
+
235
+ #- index_name
236
+
237
+ #- index_name_exists?
238
+
239
+ #+ structure_dump
240
+
241
+ #- dump_schema_information
242
+
243
+ #- initialize_schema_migrations_table
244
+
245
+ #- assume_migrated_upto_version
246
+
247
+ #- type_to_sql
248
+
249
+ #- add_column_options!
250
+
251
+ #- distinct
252
+
253
+ #- add_timestamps
254
+
255
+ #- remove_timestamps
256
+
158
257
  module Column
159
258
  # Maps Teradata types of logical Rails types
160
259
  def simplified_type(field_type)
161
260
  case field_type
162
261
  when /^timestamp with(?:out)? time zone$/ then :datetime
262
+ when /byteint/i then :boolean
163
263
  else
164
264
  super
165
265
  end
166
266
  end
167
267
  end # column
168
268
 
269
+ def type_cast
270
+ return super unless value == true || value == false
271
+
272
+ value ? 1 : 0
273
+ end
274
+
275
+ def quote(value, column = nil)
276
+ return value.quoted_id if value.respond_to?(:quoted_id)
277
+ case value
278
+ when String
279
+ %Q{'#{quote_string(value)}'}
280
+ when TrueClass
281
+ '1'
282
+ when FalseClass
283
+ '0'
284
+ else super
285
+ end
286
+ end
287
+
169
288
  def quote_column_name(name)
170
289
  %Q("#{name}")
171
290
  end
172
291
 
173
292
  def quote_table_name(name)
174
- name.to_s
293
+ %Q("#{name.to_s}")
294
+ end
295
+
296
+ def quote_true
297
+ '1'
175
298
  end
176
299
 
300
+ def quoted_false
301
+ '0'
302
+ end
303
+
304
+ def add_index(table_name, column_name, options = {})
305
+ index_name, index_type, index_columns = add_index_options(table_name, column_name, options)
306
+ execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} (#{index_columns}) ON #{quote_table_name(table_name)}"
307
+ end
308
+
309
+ IDENTIFIER_LENGTH = 30 # :nodoc:
310
+
311
+ # maximum length of Teradata identifiers is 30
312
+ def table_alias_length; IDENTIFIER_LENGTH; end # :nodoc:
313
+ def table_name_length; IDENTIFIER_LENGTH; end # :nodoc:
314
+ def index_name_length; IDENTIFIER_LENGTH; end # :nodoc:
315
+ def column_name_length; IDENTIFIER_LENGTH; end # :nodoc:
316
+
177
317
  end
178
318
  end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ require 'models/active_record_schema'
4
+
5
+ require 'models/active_record_models'
6
+
7
+ describe 'ActiveRecordSchemaSpec' do
8
+
9
+ it 'should load in the activerecord sample schema.rb file' do
10
+ expect {
11
+ CreateActiveRecordSchema.up
12
+ }.to_not raise_error
13
+ end
14
+
15
+ context 'from loaded activerecord data' do
16
+ before(:all) do
17
+ CreateActiveRecordSchema.up
18
+ Topic.delete_all
19
+
20
+ 1.upto(4) do |i|
21
+ @topic = Topic.new
22
+ @topic.title = "foo#{i}"
23
+ @topic.author_name = "author#{i}"
24
+ @topic.author_email_address = "email#{i}@localhost"
25
+ @topic.approved = true
26
+ @topic.save
27
+ end
28
+ end
29
+
30
+ it 'should be able to group data' do
31
+ topic = Topic.last
32
+ topic.approved = false
33
+ topic.save
34
+ approved_topics_count = Topic.group(:approved).count(:author_name)[true]
35
+ approved_topics_count.should == 3
36
+ end
37
+ end
38
+ end
data/spec/adapter_spec.rb CHANGED
@@ -19,6 +19,10 @@ describe 'Adapter' do
19
19
  it '#native_database_types' do
20
20
  @adapter.native_database_types.count.should > 0
21
21
  end
22
+
23
+ it '#database_name' do
24
+ @adapter.database_name.should == 'weblog_development'
25
+ end
22
26
 
23
27
  it '#active?' do
24
28
  @adapter.active?.should be_true
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ require 'models/purchase_orders'
4
+
5
+ describe 'AssociationsSpec' do
6
+ before(:all) do
7
+ CreateVendors.up
8
+ CreateProducts.up
9
+ CreatePurchaseOrders.up
10
+ end
11
+
12
+ it 'should create all of the tables' do
13
+ vendor = Vendor.new(:name => 'Test vendor', :catch_phrase => 'Hello, world')
14
+ vendor.products.build(:name => 'Test product', :price => 100.00)
15
+ vendor.save
16
+
17
+ vendor.products.count.should == 1
18
+
19
+ purchase_order = PurchaseOrder.new
20
+ purchase_order.product = vendor.products.first
21
+
22
+ purchase_order.code = "ORDER1"
23
+ purchase_order.quantity = 2
24
+ purchase_order.save
25
+
26
+ vendor.purchase_orders.count.should == 1
27
+ end
28
+
29
+ after(:all) do
30
+ CreateVendors.down
31
+ CreateProducts.down
32
+ CreatePurchaseOrders.down
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ class Topic < ActiveRecord::Base
2
+ self.table_name = 'ar_topics'
3
+ end