Skip to content

Commit af81405

Browse files
committed
Changes for gem best practices.
1 parent 78c80f7 commit af81405

File tree

10 files changed

+264
-246
lines changed

10 files changed

+264
-246
lines changed

2000-2005-adapter.gemspec

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,9 @@ Gem::Specification.new do |s|
1818
"autotest/discover.rb",
1919
"autotest/railssqlserver.rb",
2020
"autotest/sqlserver.rb",
21-
"lib/rails-sqlserver-2000-2005-adapter.rb",
2221
"lib/active_record/connection_adapters/sqlserver_adapter.rb",
23-
"lib/core_ext/active_record.rb",
24-
"lib/core_ext/dbi.rb" ]
22+
"lib/active_record/connection_adapters/sqlserver_adapter/core_ext/active_record.rb",
23+
"lib/active_record/connection_adapters/sqlserver_adapter/core_ext/dbi.rb" ]
2524
s.test_files = [
2625
"test/cases/aaaa_create_tables_test_sqlserver.rb",
2726
"test/cases/adapter_test_sqlserver.rb",

CHANGELOG

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@ MASTER
44
*
55

66

7+
* 2.2.21 * (September 10th, 2009)
8+
9+
* Changes for gem best practices per http://weblog.rubyonrails.org/2009/9/1/gem-packaging-best-practices
10+
Details of such are as follows: [Ken Collins]
11+
- Removed rails-sqlserver-2000-2005-adapter.rb load file for old github usage.
12+
- Move the core_ext directory to active_record/connection_adapters/sqlserver_adapter/core_ext
13+
- Renamespace SQLServerDBI to ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::DBI
14+
- Renamespace ActiveRecord::ConnectionAdapters::SQLServerActiveRecordExtensions to ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::ActiveRecord
15+
16+
717
* 2.2.20 * (September 10th, 2009)
818

919
* Implement a new remove_default_constraint method that uses sp_helpconstraint [Ken Collins]

Manifest

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
CHANGELOG
2-
lib/active_record/connection_adapters/sqlserver_adapter.rb
32
lib/activerecord-sqlserver-adapter.rb
4-
lib/core_ext/active_record.rb
5-
lib/core_ext/dbi.rb
3+
lib/active_record/connection_adapters/sqlserver_adapter.rb
4+
lib/active_record/connection_adapters/sqlserver_adapter/core_ext/active_record.rb
5+
lib/active_record/connection_adapters/sqlserver_adapter/core_ext/dbi.rb
66
Manifest
77
MIT-LICENSE
88
Rakefile

Rakefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Echoe.new('activerecord-sqlserver-adapter','2.2.20') do |p|
1111
p.url = "http://github.com/rails-sqlserver"
1212
p.runtime_dependencies = ["dbi =0.4.1","dbd-odbc =0.2.4"]
1313
p.include_gemspec = false
14-
p.ignore_pattern = ["autotest/*","*.gemspec","lib/rails-sqlserver-2000-2005-adapter.rb"]
14+
p.ignore_pattern = ["autotest/*","*.gemspec"]
1515
p.project = 'arsqlserver'
1616
end
1717

lib/active_record/connection_adapters/sqlserver_adapter.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
require 'active_record/connection_adapters/abstract_adapter'
22
require_library_or_gem 'dbi' unless defined?(DBI)
3-
require 'core_ext/dbi'
4-
require 'core_ext/active_record'
3+
require 'active_record/connection_adapters/sqlserver_adapter/core_ext/dbi'
4+
require 'active_record/connection_adapters/sqlserver_adapter/core_ext/active_record'
55
require 'base64'
66

77
module ActiveRecord
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
require 'active_record/version'
2+
3+
module ActiveRecord
4+
module ConnectionAdapters
5+
module SQLServerCoreExtensions
6+
7+
8+
module ActiveRecord
9+
10+
def self.included(klass)
11+
klass.extend ClassMethods
12+
class << klass
13+
alias_method_chain :reset_column_information, :sqlserver_cache_support
14+
alias_method_chain :add_order!, :sqlserver_unique_checking
15+
alias_method_chain :add_limit!, :sqlserver_order_checking
16+
end
17+
end
18+
19+
module ClassMethods
20+
21+
def execute_procedure(proc_name, *variables)
22+
if connection.respond_to?(:execute_procedure)
23+
connection.execute_procedure(proc_name,*variables)
24+
else
25+
[]
26+
end
27+
end
28+
29+
def coerce_sqlserver_date(*attributes)
30+
write_inheritable_attribute :coerced_sqlserver_date_columns, Set.new(attributes.map(&:to_s))
31+
end
32+
33+
def coerce_sqlserver_time(*attributes)
34+
write_inheritable_attribute :coerced_sqlserver_time_columns, Set.new(attributes.map(&:to_s))
35+
end
36+
37+
def coerced_sqlserver_date_columns
38+
read_inheritable_attribute(:coerced_sqlserver_date_columns) || []
39+
end
40+
41+
def coerced_sqlserver_time_columns
42+
read_inheritable_attribute(:coerced_sqlserver_time_columns) || []
43+
end
44+
45+
def reset_column_information_with_sqlserver_cache_support
46+
connection.send(:initialize_sqlserver_caches) if connection.respond_to?(:sqlserver?)
47+
reset_column_information_without_sqlserver_cache_support
48+
end
49+
50+
private
51+
52+
def add_limit_with_sqlserver_order_checking!(sql, options, scope = :auto)
53+
if connection.respond_to?(:sqlserver?)
54+
scope = scope(:find) if :auto == scope
55+
if scope
56+
options = options.dup
57+
scoped_order = scope[:order]
58+
order = options[:order]
59+
if order && scoped_order
60+
options[:order] = add_order_with_sqlserver_unique_checking!('', order, scope).gsub(/^ ORDER BY /,'')
61+
elsif scoped_order
62+
options[:order] = scoped_order
63+
end
64+
end
65+
end
66+
add_limit_without_sqlserver_order_checking!(sql, options, scope)
67+
end
68+
69+
def add_order_with_sqlserver_unique_checking!(sql, order, scope = :auto)
70+
if connection.respond_to?(:sqlserver?)
71+
order_sql = ''
72+
add_order_without_sqlserver_unique_checking!(order_sql, order, scope)
73+
unless order_sql.blank?
74+
unique_order_hash = {}
75+
select_table_name = connection.send(:get_table_name,sql)
76+
select_table_name.tr!('[]','') if select_table_name
77+
orders_and_dirs_set = connection.send(:orders_and_dirs_set,order_sql)
78+
unique_order_sql = orders_and_dirs_set.inject([]) do |array,order_dir|
79+
ord, dir = order_dir
80+
ord_tn_and_cn = ord.to_s.split('.').map{|o|o.tr('[]','')}
81+
ord_table_name, ord_column_name = if ord_tn_and_cn.size > 1
82+
ord_tn_and_cn
83+
else
84+
[nil, ord_tn_and_cn.first]
85+
end
86+
if (ord_table_name && ord_table_name == select_table_name && unique_order_hash[ord_column_name]) || unique_order_hash[ord_column_name]
87+
array
88+
else
89+
unique_order_hash[ord_column_name] = true
90+
array << "#{ord} #{dir}".strip
91+
end
92+
end.join(', ')
93+
sql << " ORDER BY #{unique_order_sql}"
94+
end
95+
else
96+
add_order_without_sqlserver_unique_checking!(sql, order, scope)
97+
end
98+
end
99+
100+
end
101+
102+
module JoinAssociationChanges
103+
104+
def self.included(klass)
105+
klass.class_eval do
106+
include InstanceMethods
107+
alias_method_chain :aliased_table_name_for, :sqlserver_support
108+
end
109+
end
110+
111+
module InstanceMethods
112+
113+
protected
114+
115+
# An exact copy, except this method has a Regexp escape on the quoted table name.
116+
def aliased_table_name_for_with_sqlserver_support(name,suffix=nil)
117+
if !parent.table_joins.blank? && parent.table_joins.to_s.downcase =~ %r{join(\s+\w+)?\s+#{Regexp.escape(active_record.connection.quote_table_name(name.downcase))}\son}i
118+
@join_dependency.table_aliases[name] += 1
119+
end
120+
unless @join_dependency.table_aliases[name].zero?
121+
# if the table name has been used, then use an alias
122+
name = active_record.connection.table_alias_for "#{pluralize(reflection.name)}_#{parent_table_name}#{suffix}"
123+
table_index = @join_dependency.table_aliases[name]
124+
@join_dependency.table_aliases[name] += 1
125+
name = name[0..active_record.connection.table_alias_length-3] + "_#{table_index+1}" if table_index > 0
126+
else
127+
@join_dependency.table_aliases[name] += 1
128+
end
129+
name
130+
end
131+
132+
end
133+
134+
end
135+
136+
end
137+
138+
139+
end
140+
end
141+
end
142+
143+
144+
ActiveRecord::Base.send :include, ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::ActiveRecord
145+
146+
if ActiveRecord::VERSION::MAJOR == 2 && ActiveRecord::VERSION::MINOR >= 3
147+
require 'active_record/associations'
148+
ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation.send :include, ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::ActiveRecord::JoinAssociationChanges
149+
end
150+
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
2+
module ActiveRecord
3+
module ConnectionAdapters
4+
module SQLServerCoreExtensions
5+
6+
7+
module DBI
8+
9+
module Timestamp
10+
# Deprecated DBI. See documentation for Type::SqlserverTimestamp which
11+
# this method tries to mimic as ODBC is still going to convert SQL Server
12+
# milliconds to whole number representation of nanoseconds.
13+
def to_sqlserver_string
14+
datetime, nanoseconds = to_s.split('.')
15+
"#{datetime}.#{sprintf("%03d",nanoseconds.to_i/1000000)}"
16+
end
17+
end
18+
19+
module Type
20+
21+
# Make sure we get DBI::Type::Timestamp returning a string NOT a time object
22+
# that represents what is in the DB before type casting while letting core
23+
# ActiveRecord do the reset. It is assumed that DBI is using ODBC connections
24+
# and that ODBC::Timestamp is taking the native milliseconds that SQL Server
25+
# stores and returning them incorrect using ODBC::Timestamp#fraction which is
26+
# nanoseconds. Below shows the incorrect ODBC::Timestamp represented by DBI
27+
# and the conversion we expect to have in the DB before type casting.
28+
#
29+
# "1985-04-15 00:00:00 0" # => "1985-04-15 00:00:00.000"
30+
# "2008-11-08 10:24:36 30000000" # => "2008-11-08 10:24:36.003"
31+
# "2008-11-08 10:24:36 123000000" # => "2008-11-08 10:24:36.123"
32+
class SqlserverTimestamp
33+
def self.parse(obj)
34+
return nil if ::DBI::Type::Null.parse(obj).nil?
35+
date, time, nanoseconds = obj.split(' ')
36+
"#{date} #{time}.#{sprintf("%03d",nanoseconds.to_i/1000000)}"
37+
end
38+
end
39+
40+
# The adapter and rails will parse our floats, decimals, and money field correctly
41+
# from a string. Do not let the DBI::Type classes create Float/BigDecimal objects
42+
# for us. Trust rails .type_cast to do what it is built to do.
43+
class SqlserverForcedString
44+
def self.parse(obj)
45+
return nil if ::DBI::Type::Null.parse(obj).nil?
46+
obj.to_s
47+
end
48+
end
49+
50+
end
51+
52+
module TypeUtil
53+
54+
def self.included(klass)
55+
klass.extend ClassMethods
56+
class << klass
57+
alias_method_chain :type_name_to_module, :sqlserver_types
58+
end
59+
end
60+
61+
module ClassMethods
62+
63+
# Capture all types classes that we need to handle directly for SQL Server
64+
# and allow normal processing for those that we do not.
65+
def type_name_to_module_with_sqlserver_types(type_name)
66+
case type_name
67+
when /^timestamp$/i
68+
DBI::Type::SqlserverTimestamp
69+
when /^float|decimal|money$/i
70+
DBI::Type::SqlserverForcedString
71+
else
72+
type_name_to_module_without_sqlserver_types(type_name)
73+
end
74+
end
75+
76+
end
77+
78+
end
79+
80+
end
81+
82+
83+
end
84+
end
85+
end
86+
87+
88+
89+
90+
if defined?(DBI::TypeUtil)
91+
DBI::Type.send :include, ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::DBI::Type
92+
DBI::TypeUtil.send :include, ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::DBI::TypeUtil
93+
elsif defined?(DBI::Timestamp) # DEPRECATED in DBI 0.4.0 and above. Remove when 0.2.2 and lower is no longer supported.
94+
DBI::Timestamp.send :include, ActiveRecord::ConnectionAdapters::SQLServerCoreExtensions::DBI::Timestamp
95+
end
96+

0 commit comments

Comments
 (0)