activerecord-sqlserver-adapter-schemas 1.0.0

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.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,48 @@
1
+
2
+ == Schema support for Rails SQL Server 2000, 2005 and 2008 Adapter
3
+
4
+ Adds support for schemas to the activerecord-sqlserver-adapter gem
5
+
6
+ == Installation
7
+
8
+ $ gem install activerecord-sqlserver-adapter
9
+ $ gem install activerecord-sqlserver-adapter-schemas
10
+
11
+ Optionally configure your gem dependencies in your rails environment.rb file.
12
+
13
+ config.gem 'activerecord-sqlserver-adapter', :version => 'x.x.xx'
14
+ config.gem 'activerecord-sqlserver-adapter-schemas', :version => 'x.x.xx'
15
+
16
+ == Using Schemas with ActiveRecord
17
+
18
+ The simplest way to use schemas is to simply specify it as part of the table name
19
+
20
+ class FooBar < ActiveRecord::Base
21
+ set_table_name 'foo.bars'
22
+ end
23
+
24
+ To use any the following methods, you must first enable schema names:
25
+
26
+ ActiveRecord::Base.use_schema_names = true
27
+
28
+ With use_schema_names enabled, models in a module will use the module name as the schema name automatically. For example:
29
+
30
+ # the table name for this model would be assumed to be foo.bars
31
+ class Foo::Bar < ActiveRecord::Base
32
+ end
33
+
34
+ The schema name can also be set explicitly when use_schema_names is enabled:
35
+
36
+ class Bar < ActiveRecord::Base
37
+ set_schema_name 'foo'
38
+ end
39
+
40
+ == Migrations
41
+
42
+ It is possible to have separate schema_migrations tables in different schemas existing in the database at the same time. This is useful if you have multiple rails applications using the same database but different schemas.
43
+
44
+ To use this feature, use different users for each application with different default schemas set in the database. So if you have 2 rails applications, if they log in as different users with different default schemas, they each get their own schema_migrations table in that schema.
45
+
46
+ == License
47
+
48
+ Copyright 2010. It is free software, and may be redistributed under the terms specified in the MIT-LICENSE file.
@@ -0,0 +1,57 @@
1
+ # This module is used to make it easier to deal with legacy char fields by trimming them automatically after a find.
2
+ module ActiveRecord
3
+ module Schemas
4
+ module Base
5
+ # returns true if schema names should be used. Default is false
6
+ def use_schema_names?
7
+ read_inheritable_attribute(:use_schema_names)
8
+ end
9
+
10
+ # sets if schema names should be used.
11
+ def use_schema_names=(value)
12
+ write_inheritable_attribute(:use_schema_names, value)
13
+ end
14
+ alias_method :set_use_schema_names, :use_schema_names=
15
+
16
+ # returns the schema name, either based on the module (via reset_schema_name) of an explicitly set value defined by the class
17
+ def schema_name
18
+ reset_schema_name
19
+ end
20
+
21
+ # calculates the schema name based on the class's module
22
+ def reset_schema_name
23
+ ar_descendant = class_of_active_record_descendant(self)
24
+ if ar_descendant == self
25
+ name = self.name.split('::').first.downcase
26
+ set_schema_name name
27
+ name
28
+ else
29
+ ar_descendant.schema_name
30
+ end
31
+ end
32
+
33
+ # overrides the default schema based on the module
34
+ def schema_name=(value = nil, &block)
35
+ define_attr_method :schema_name, value, &block
36
+ end
37
+ alias_method :set_schema_name, :schema_name=
38
+
39
+ # sets the table name with the schema
40
+ def reset_table_name_with_schema
41
+ ar_descendant = class_of_active_record_descendant(self)
42
+ if self == ar_descendant
43
+ name = reset_table_name
44
+ if use_schema_names? && schema_name
45
+ name = "#{"#{schema_name}." if schema_name}#{name}"
46
+ set_table_name name
47
+ end
48
+ name
49
+ else
50
+ name = ar_descendant.table_name
51
+ set_table_name name
52
+ name
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,56 @@
1
+ module ActiveRecord
2
+ module Schemas
3
+ module ConnectionAdapters
4
+
5
+ module SqlserverAdapter
6
+
7
+ # When this module is included, the following methods are chained in order
8
+ # to strip off the schema names if the schema is the default schema
9
+ def self.included(base)
10
+ base.alias_method_chain :columns, :default_schema_check
11
+ base.alias_method_chain :table_exists?, :default_schema_check
12
+ base.alias_method_chain :table_name_or_views_table_name, :default_schema_check
13
+ end
14
+
15
+ def default_schema
16
+ unless sqlserver_2000?
17
+ @default_schema ||= select_values("SELECT default_schema_name FROM sys.database_principals WHERE type = 'S' and name = '#{self.quote_string(@connection_options[:username])}'").first
18
+ end
19
+ @default_schema ||= 'dbo'
20
+ end
21
+ attr_writer :default_schema
22
+
23
+ def table_name_or_views_table_name_with_default_schema_check(table_name)
24
+ table_name = unqualify_table_name_if_default_schema(table_name)
25
+ table_name_or_views_table_name_without_default_schema_check(table_name)
26
+ end
27
+
28
+ def table_exists_with_default_schema_check?(table_name)
29
+ table_name = unqualify_table_name_if_default_schema(table_name)
30
+ table_exists_without_default_schema_check?(table_name)
31
+ end
32
+
33
+ def columns_with_default_schema_check(table_name, column_name = nil)
34
+ table_name = unqualify_table_name_if_default_schema(table_name) if table_name
35
+ columns_without_default_schema_check(table_name, column_name)
36
+ end
37
+
38
+ def unqualify_schema_name(table_name)
39
+ parts = table_name.to_s.split('.')
40
+ parts.length == 1 ? default_schema : parts[parts.length - 2].gsub(/[\[\]]/,'')
41
+ end
42
+
43
+ def unqualify_table_name_if_default_schema(table_name)
44
+ schema = unqualify_schema_name(table_name)
45
+ schema == default_schema ? unqualify_table_name(table_name) : table_name
46
+ end
47
+
48
+ # override index name so that if there is a schema, rename it schema_table instead of schema.table
49
+ def index_name(table_name, options) #:nodoc:
50
+ super table_name.tr('.', '_'), options
51
+ end
52
+ end
53
+
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,151 @@
1
+ require File.join(File.dirname(__FILE__), 'active_record', 'schemas', 'base')
2
+ require File.join(File.dirname(__FILE__), 'active_record', 'schemas', 'connection_adapters', 'sqlserver_adapter')
3
+
4
+ class ActiveRecord::Base
5
+ extend ActiveRecord::Schemas::Base
6
+
7
+ def self.table_name
8
+ reset_table_name_with_schema
9
+ end
10
+ end
11
+
12
+ class ActiveRecord::ConnectionAdapters::SQLServerAdapter
13
+ include ActiveRecord::Schemas::ConnectionAdapters::SqlserverAdapter
14
+
15
+ # This method is overridden to support linked servers
16
+ def unqualify_db_name(table_name)
17
+ table_names = table_name.to_s.split('.')
18
+ table_names.length >= 3 ? table_names[0...table_names.length - 2].join('.').tr('[]','') : nil
19
+ end
20
+
21
+ # This method is overridden to support schema names
22
+ def tables(name = nil)
23
+ # return schema.table unless the schema is the default schema, in which case just return table
24
+ info_schema_query do
25
+ select_values("SELECT TABLE_SCHEMA + '.' + TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME <> 'dtproperties'").collect do |table|
26
+ default_schema && table.index("#{default_schema}.") == 0 ? table[default_schema.length + 1..table.length] : table
27
+ end
28
+ end
29
+ end
30
+
31
+ # This method is overridden to support schema names
32
+ def views(name = nil)
33
+ # return schema.view unless the schema is the default schema, in which case just return view
34
+ @sqlserver_views_cache ||=
35
+ info_schema_query do
36
+ select_values("SELECT TABLE_SCHEMA + '.' + TABLE_NAME FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME NOT IN ('sysconstraints','syssegments')").collect do |view|
37
+ default_schema && view.index("#{default_schema}.") == 0 ? view[default_schema.length + 1..view.length] : view
38
+ end
39
+ end
40
+ end
41
+
42
+ # This method is overridden to support references such as database..table
43
+ def quote_column_name(column_name)
44
+ column_name.to_s.split('..').collect do |part|
45
+ part.split('.').map{ |name| name =~ /^\[.*\]$/ ? name : "[#{name}]" }.join('.')
46
+ end.join('..')
47
+ end
48
+
49
+ # overridden to support schemas. sp_helpindex does not support linked servers
50
+ def indexes(table_name, name = nil)
51
+ db_name = unqualify_db_name(table_name)
52
+ db_name << '.' if db_name
53
+ schema_name = unqualify_schema_name(table_name) << '.'
54
+ table_name = unqualify_table_name(table_name)
55
+
56
+ select("EXEC sp_helpindex '#{quote_table_name("#{db_name}#{schema_name}#{table_name}")}'",name).inject([]) do |indexes,index|
57
+ if index['index_description'] =~ /primary key/
58
+ indexes
59
+ else
60
+ name = index['index_name']
61
+ unique = index['index_description'] =~ /unique/
62
+ columns = index['index_keys'].split(',').map do |column|
63
+ column.strip!
64
+ column.gsub! '(-)', '' if column.ends_with?('(-)')
65
+ column
66
+ end
67
+ indexes << ::ActiveRecord::ConnectionAdapters::IndexDefinition.new(table_name, name, unique, columns)
68
+ end
69
+ end
70
+ end
71
+
72
+ def view_information(table_name)
73
+ db_name = unqualify_db_name(table_name)
74
+ schema_name = unqualify_schema_name(table_name)
75
+ table_name = unqualify_table_name(table_name)
76
+
77
+ @@sqlserver_view_information_cache ||= {}
78
+ @@sqlserver_view_information_cache[table_name.downcase] ||= begin
79
+ sql = "SELECT * FROM #{"#{db_name}." if db_name}INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME = '#{table_name}'"
80
+ sql << " and TABLE_SCHEMA = '#{schema_name}'" if schema_name
81
+ view_info = info_schema_query { select_one(sql) }
82
+ if view_info
83
+ if view_info['VIEW_DEFINITION'].blank? || view_info['VIEW_DEFINITION'].length == 4000
84
+ view_info['VIEW_DEFINITION'] = info_schema_query { select_values("EXEC sp_helptext #{table_name}").join }
85
+ end
86
+ end
87
+ view_info
88
+ end
89
+ end
90
+
91
+ def column_definitions(table_name)
92
+ db_name = unqualify_db_name(table_name)
93
+ db_name << '.' if db_name
94
+ schema_name = unqualify_schema_name(table_name)
95
+ table_name = unqualify_table_name(table_name)
96
+ sql = %{
97
+ SELECT
98
+ columns.TABLE_NAME as table_name,
99
+ columns.COLUMN_NAME as name,
100
+ columns.DATA_TYPE as type,
101
+ columns.COLUMN_DEFAULT as default_value,
102
+ columns.NUMERIC_SCALE as numeric_scale,
103
+ columns.NUMERIC_PRECISION as numeric_precision,
104
+ CASE
105
+ WHEN columns.DATA_TYPE IN ('nchar','nvarchar') THEN columns.CHARACTER_MAXIMUM_LENGTH
106
+ ELSE COL_LENGTH(columns.TABLE_SCHEMA+'.'+columns.TABLE_NAME, columns.COLUMN_NAME)
107
+ END as length,
108
+ CASE
109
+ WHEN columns.IS_NULLABLE = 'YES' THEN 1
110
+ ELSE NULL
111
+ end as is_nullable,
112
+ CASE
113
+ WHEN COLUMNPROPERTY(OBJECT_ID(columns.TABLE_SCHEMA+'.'+columns.TABLE_NAME), columns.COLUMN_NAME, 'IsIdentity') = 0 THEN NULL
114
+ ELSE 1
115
+ END as is_identity
116
+ FROM #{db_name}INFORMATION_SCHEMA.COLUMNS columns
117
+ WHERE columns.TABLE_NAME = '#{table_name}'
118
+ #{"AND columns.TABLE_SCHEMA = '#{schema_name}'" if schema_name}
119
+ ORDER BY columns.ordinal_position
120
+ }.gsub(/[ \t\r\n]+/,' ')
121
+ results = info_schema_query { select(sql,nil,true) }
122
+ results.collect do |ci|
123
+ ci.symbolize_keys!
124
+ ci[:type] = case ci[:type]
125
+ when /^bit|image|text|ntext|datetime$/
126
+ ci[:type]
127
+ when /^numeric|decimal$/i
128
+ "#{ci[:type]}(#{ci[:numeric_precision]},#{ci[:numeric_scale]})"
129
+ when /^char|nchar|varchar|nvarchar|varbinary|bigint|int|smallint$/
130
+ ci[:length].to_i == -1 ? "#{ci[:type]}(max)" : "#{ci[:type]}(#{ci[:length]})"
131
+ else
132
+ ci[:type]
133
+ end
134
+ if ci[:default_value].nil? && views.include?(table_name)
135
+ real_table_name = table_name_or_views_table_name(table_name)
136
+ real_column_name = views_real_column_name(table_name,ci[:name])
137
+ col_default_sql = "SELECT c.COLUMN_DEFAULT FROM #{db_name}INFORMATION_SCHEMA.COLUMNS c WHERE c.TABLE_NAME = '#{real_table_name}' AND c.COLUMN_NAME = '#{real_column_name}'"
138
+ ci[:default_value] = info_schema_query { select_value(col_default_sql) }
139
+ end
140
+ ci[:default_value] = case ci[:default_value]
141
+ when nil, '(null)', '(NULL)'
142
+ nil
143
+ else
144
+ match_data = ci[:default_value].match(/\A\(+N?'?(.*?)'?\)+\Z/m)
145
+ match_data ? match_data[1] : nil
146
+ end
147
+ ci[:null] = ci[:is_nullable].to_i == 1 ; ci.delete(:is_nullable)
148
+ ci
149
+ end
150
+ end
151
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: activerecord-sqlserver-adapter-schemas
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Airlite Plastics
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-06-25 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activerecord-sqlserver-adapter
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description: Adds schema support to activerecord-sqlserver-adapter.
26
+ email: dtjablonski@airliteplastics.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README.rdoc
33
+ files:
34
+ - MIT-LICENSE
35
+ - README.rdoc
36
+ - lib/activerecord-sqlserver-adapter-schemas.rb
37
+ - lib/active_record/schemas/base.rb
38
+ - lib/active_record/schemas/connection_adapters/sqlserver_adapter.rb
39
+ has_rdoc: true
40
+ homepage:
41
+ licenses: []
42
+
43
+ post_install_message:
44
+ rdoc_options:
45
+ - --line-numbers
46
+ - --inline-source
47
+ - --main
48
+ - README.rdoc
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: 1.8.6
56
+ version:
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
63
+ requirements: []
64
+
65
+ rubyforge_project:
66
+ rubygems_version: 1.3.5
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: Adds schema support to activerecord-sqlserver-adapter.
70
+ test_files: []
71
+