activerecord-sqlserver-adapter-schemas 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
+