dm-constraints 0.9.11 → 0.10.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/{History.txt → History.rdoc} +4 -2
- data/Manifest.txt +3 -5
- data/{README.txt → README.rdoc} +0 -0
- data/Rakefile +2 -3
- data/lib/dm-constraints/delete_constraint.rb +37 -106
- data/lib/dm-constraints/migrations.rb +274 -0
- data/lib/dm-constraints/version.rb +1 -1
- data/lib/dm-constraints.rb +27 -49
- data/spec/integration/constraints_spec.rb +380 -339
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +50 -12
- data/tasks/install.rb +1 -1
- data/tasks/spec.rb +4 -4
- metadata +15 -24
- data/lib/dm-constraints/data_objects_adapter.rb +0 -197
- data/lib/dm-constraints/mysql_adapter.rb +0 -50
- data/lib/dm-constraints/postgres_adapter.rb +0 -32
data/spec/spec.opts
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,25 +1,63 @@
|
|
1
|
-
require 'pathname'
|
2
1
|
require 'rubygems'
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
gem 'dm-core', '0.9.11'
|
3
|
+
# use local dm-core if running from a typical dev checkout.
|
4
|
+
lib = File.join('..', '..', 'dm-core', 'lib')
|
5
|
+
$LOAD_PATH.unshift(lib) if File.directory?(lib)
|
8
6
|
require 'dm-core'
|
9
7
|
|
10
|
-
|
8
|
+
# Support running specs with 'rake spec' and 'spec'
|
9
|
+
$LOAD_PATH.unshift('lib') unless $LOAD_PATH.include?('lib')
|
10
|
+
|
11
|
+
require 'dm-constraints'
|
12
|
+
|
13
|
+
ADAPTERS = {}
|
11
14
|
def load_driver(name, default_uri)
|
15
|
+
connection_string = ENV["#{name.to_s.upcase}_SPEC_URI"] || default_uri
|
12
16
|
begin
|
13
|
-
DataMapper.setup(name,
|
14
|
-
|
15
|
-
|
17
|
+
adapter = DataMapper.setup(name.to_sym, connection_string)
|
18
|
+
|
19
|
+
# test the connection if possible
|
20
|
+
if adapter.respond_to?(:query)
|
21
|
+
adapter.query('SELECT 1')
|
22
|
+
end
|
23
|
+
|
24
|
+
ADAPTERS[name] = connection_string
|
16
25
|
rescue LoadError => e
|
17
26
|
warn "Could not load do_#{name}: #{e}"
|
18
27
|
false
|
19
28
|
end
|
20
29
|
end
|
21
30
|
|
22
|
-
load_driver(:postgres, 'postgres://postgres@localhost/dm_core_test')
|
23
|
-
load_driver(:mysql, 'mysql://localhost/dm_core_test')
|
24
31
|
|
25
|
-
|
32
|
+
HAS_SQLITE3 = load_driver(:sqlite3, 'sqlite3::memory:')
|
33
|
+
HAS_MYSQL = load_driver(:mysql, 'mysql://localhost/dm_core_test')
|
34
|
+
HAS_POSTGRES = load_driver(:postgres, 'postgres://postgres@localhost/dm_core_test')
|
35
|
+
|
36
|
+
|
37
|
+
Spec::Runner.configure do |config|
|
38
|
+
config.after :all do
|
39
|
+
# global model cleanup
|
40
|
+
descendants = DataMapper::Model.descendants.to_a
|
41
|
+
while model = descendants.shift
|
42
|
+
descendants.concat(model.descendants.to_a - [ model ])
|
43
|
+
|
44
|
+
parts = model.name.split('::')
|
45
|
+
constant_name = parts.pop.to_sym
|
46
|
+
base = parts.empty? ? Object : Object.full_const_get(parts.join('::'))
|
47
|
+
|
48
|
+
if base.const_defined?(constant_name)
|
49
|
+
base.send(:remove_const, constant_name)
|
50
|
+
end
|
51
|
+
|
52
|
+
DataMapper::Model.descendants.delete(model)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
config.before do
|
57
|
+
DataMapper.auto_migrate!
|
58
|
+
end
|
59
|
+
|
60
|
+
config.after do
|
61
|
+
DataMapper.send(:auto_migrate_down!, @repository.name)
|
62
|
+
end
|
63
|
+
end
|
data/tasks/install.rb
CHANGED
@@ -4,7 +4,7 @@ end
|
|
4
4
|
|
5
5
|
desc "Install #{GEM_NAME} #{GEM_VERSION}"
|
6
6
|
task :install => [ :package ] do
|
7
|
-
sudo_gem "install
|
7
|
+
sudo_gem "install pkg/#{GEM_NAME}-#{GEM_VERSION} --no-update-sources"
|
8
8
|
end
|
9
9
|
|
10
10
|
desc "Uninstall #{GEM_NAME} #{GEM_VERSION}"
|
data/tasks/spec.rb
CHANGED
@@ -1,6 +1,4 @@
|
|
1
1
|
begin
|
2
|
-
gem 'rspec', '~>1.2'
|
3
|
-
require 'spec'
|
4
2
|
require 'spec/rake/spectask'
|
5
3
|
|
6
4
|
task :default => [ :spec ]
|
@@ -8,16 +6,18 @@ begin
|
|
8
6
|
desc 'Run specifications'
|
9
7
|
Spec::Rake::SpecTask.new(:spec) do |t|
|
10
8
|
t.spec_opts << '--options' << 'spec/spec.opts' if File.exists?('spec/spec.opts')
|
11
|
-
t.
|
9
|
+
t.libs << 'lib' << 'spec' # needed for CI rake spec task, duplicated in spec_helper
|
12
10
|
|
13
11
|
begin
|
14
|
-
|
12
|
+
require 'rcov'
|
15
13
|
t.rcov = JRUBY ? false : (ENV.has_key?('NO_RCOV') ? ENV['NO_RCOV'] != 'true' : true)
|
16
14
|
t.rcov_opts << '--exclude' << 'spec'
|
17
15
|
t.rcov_opts << '--text-summary'
|
18
16
|
t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
|
19
17
|
rescue LoadError
|
20
18
|
# rcov not installed
|
19
|
+
rescue SyntaxError
|
20
|
+
# rcov syntax invalid
|
21
21
|
end
|
22
22
|
end
|
23
23
|
rescue LoadError
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dm-constraints
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dirkjan Bussink
|
@@ -9,19 +9,10 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-09-16 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
16
|
-
name: dm-core
|
17
|
-
type: :runtime
|
18
|
-
version_requirement:
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
20
|
-
requirements:
|
21
|
-
- - "="
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 0.9.11
|
24
|
-
version:
|
14
|
+
dependencies: []
|
15
|
+
|
25
16
|
description: DataMapper plugin constraining relationships
|
26
17
|
email:
|
27
18
|
- d.bussink [a] gmail [d] com
|
@@ -30,22 +21,20 @@ executables: []
|
|
30
21
|
extensions: []
|
31
22
|
|
32
23
|
extra_rdoc_files:
|
33
|
-
- README.
|
24
|
+
- README.rdoc
|
34
25
|
- LICENSE
|
35
26
|
- TODO
|
36
|
-
- History.
|
27
|
+
- History.rdoc
|
37
28
|
files:
|
38
|
-
- History.
|
29
|
+
- History.rdoc
|
39
30
|
- LICENSE
|
40
31
|
- Manifest.txt
|
41
|
-
- README.
|
32
|
+
- README.rdoc
|
42
33
|
- Rakefile
|
43
34
|
- TODO
|
44
35
|
- lib/dm-constraints.rb
|
45
|
-
- lib/dm-constraints/data_objects_adapter.rb
|
46
36
|
- lib/dm-constraints/delete_constraint.rb
|
47
|
-
- lib/dm-constraints/
|
48
|
-
- lib/dm-constraints/postgres_adapter.rb
|
37
|
+
- lib/dm-constraints/migrations.rb
|
49
38
|
- lib/dm-constraints/version.rb
|
50
39
|
- spec/integration/constraints_spec.rb
|
51
40
|
- spec/spec.opts
|
@@ -53,11 +42,13 @@ files:
|
|
53
42
|
- tasks/install.rb
|
54
43
|
- tasks/spec.rb
|
55
44
|
has_rdoc: true
|
56
|
-
homepage: http://github.com/
|
45
|
+
homepage: http://github.com/datamapper/dm-more/tree/master/dm-constraints
|
46
|
+
licenses: []
|
47
|
+
|
57
48
|
post_install_message:
|
58
49
|
rdoc_options:
|
59
50
|
- --main
|
60
|
-
- README.
|
51
|
+
- README.rdoc
|
61
52
|
require_paths:
|
62
53
|
- lib
|
63
54
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -75,9 +66,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
75
66
|
requirements: []
|
76
67
|
|
77
68
|
rubyforge_project: datamapper
|
78
|
-
rubygems_version: 1.3.
|
69
|
+
rubygems_version: 1.3.5
|
79
70
|
signing_key:
|
80
|
-
specification_version:
|
71
|
+
specification_version: 3
|
81
72
|
summary: DataMapper plugin constraining relationships
|
82
73
|
test_files: []
|
83
74
|
|
@@ -1,197 +0,0 @@
|
|
1
|
-
module DataMapper
|
2
|
-
module Constraints
|
3
|
-
module DataObjectsAdapter
|
4
|
-
module SQL
|
5
|
-
|
6
|
-
##
|
7
|
-
# generates all foreign key create constraint statements for valid relationships
|
8
|
-
# given repository and a model
|
9
|
-
#
|
10
|
-
# This wraps calls to create_constraints_statement
|
11
|
-
#
|
12
|
-
# @see #create_constraints_statement
|
13
|
-
#
|
14
|
-
# @param repository_name [Symbol] Name of the repository to constrain
|
15
|
-
#
|
16
|
-
# @param model [DataMapper::Model] Model to constrain
|
17
|
-
#
|
18
|
-
# @return [Array[String]] List of statements to create constraints
|
19
|
-
#
|
20
|
-
#
|
21
|
-
# @api public
|
22
|
-
def create_constraints_statements(repository_name, model)
|
23
|
-
model.many_to_one_relationships.map do |relationship|
|
24
|
-
|
25
|
-
table_name = model.storage_name(repository_name)
|
26
|
-
constraint_name = constraint_name(table_name, relationship.name)
|
27
|
-
next if constraint_exists?(table_name, constraint_name)
|
28
|
-
|
29
|
-
keys = relationship.child_key.map { |key| property_to_column_name(model.repository(repository_name), key, false) }
|
30
|
-
parent = relationship.parent_model
|
31
|
-
foreign_table = parent.storage_name(repository_name)
|
32
|
-
foreign_keys = parent.key.map { |key| property_to_column_name(parent.repository(repository_name), key, false) }
|
33
|
-
|
34
|
-
#Anonymous relationshps for :through => Resource
|
35
|
-
one_to_many_relationship = parent.relationships.values.select { |rel|
|
36
|
-
rel.options[:near_relationship_name] == Extlib::Inflection.tableize(model.name).to_sym
|
37
|
-
}.first
|
38
|
-
|
39
|
-
one_to_many_relationship ||= parent.relationships.values.select { |rel|
|
40
|
-
rel.child_model == model
|
41
|
-
}.first
|
42
|
-
|
43
|
-
delete_constraint_type = case one_to_many_relationship.nil? ? :protect : one_to_many_relationship.delete_constraint
|
44
|
-
when :protect, nil
|
45
|
-
"NO ACTION"
|
46
|
-
when :destroy, :destroy!
|
47
|
-
"CASCADE"
|
48
|
-
when :set_nil
|
49
|
-
"SET NULL"
|
50
|
-
when :skip
|
51
|
-
nil
|
52
|
-
end
|
53
|
-
|
54
|
-
create_constraints_statement(table_name, constraint_name, keys, foreign_table, foreign_keys, delete_constraint_type) if delete_constraint_type
|
55
|
-
end.compact
|
56
|
-
end
|
57
|
-
|
58
|
-
##
|
59
|
-
# generates all foreign key destroy constraint statements for valid relationships
|
60
|
-
# given repository and a model
|
61
|
-
#
|
62
|
-
# This wraps calls to destroy_constraints_statement
|
63
|
-
#
|
64
|
-
# @see #destroy_constraints_statement
|
65
|
-
#
|
66
|
-
# @param repository_name [Symbol] Name of the repository to constrain
|
67
|
-
#
|
68
|
-
# @param model [DataMapper::Model] Model to constrain
|
69
|
-
#
|
70
|
-
# @return [Array[String]] List of statements to destroy constraints
|
71
|
-
#
|
72
|
-
#
|
73
|
-
# @api public
|
74
|
-
def destroy_constraints_statements(repository_name, model)
|
75
|
-
model.many_to_one_relationships.map do |relationship|
|
76
|
-
table_name = model.storage_name(repository_name)
|
77
|
-
constraint_name = constraint_name(table_name, relationship.name)
|
78
|
-
next unless constraint_exists?(table_name, constraint_name)
|
79
|
-
|
80
|
-
destroy_constraints_statement(table_name, constraint_name)
|
81
|
-
|
82
|
-
end.compact
|
83
|
-
end
|
84
|
-
|
85
|
-
private
|
86
|
-
|
87
|
-
##
|
88
|
-
# Generates the SQL statement to create a constraint
|
89
|
-
#
|
90
|
-
# @param table_name [String] name of table to constrain
|
91
|
-
#
|
92
|
-
# @param constraint_name [String] name of foreign key constraint
|
93
|
-
#
|
94
|
-
# @param keys [Array[String]] keys that refer to another table
|
95
|
-
#
|
96
|
-
# @param foreign_table [String] table fk refers to
|
97
|
-
#
|
98
|
-
# @param foreign_keys [Array[String]] keys on foreign table that constraint refers to
|
99
|
-
#
|
100
|
-
# @param delete_constraint_type [String] the constraint to add to the table
|
101
|
-
#
|
102
|
-
# @return [String] SQL DDL Statement to create a constraint
|
103
|
-
#
|
104
|
-
# @api private
|
105
|
-
def create_constraints_statement(table_name, constraint_name, keys, foreign_table, foreign_keys, delete_constraint_type)
|
106
|
-
<<-EOS.compress_lines
|
107
|
-
ALTER TABLE #{quote_table_name(table_name)}
|
108
|
-
ADD CONSTRAINT #{quote_constraint_name(constraint_name)}
|
109
|
-
FOREIGN KEY (#{keys * ', '})
|
110
|
-
REFERENCES #{quote_table_name(foreign_table)} (#{foreign_keys * ', '})
|
111
|
-
ON DELETE #{delete_constraint_type}
|
112
|
-
ON UPDATE #{delete_constraint_type}
|
113
|
-
EOS
|
114
|
-
end
|
115
|
-
|
116
|
-
##
|
117
|
-
# Generates the SQL statement to destroy a constraint
|
118
|
-
#
|
119
|
-
# @param table_name [String] name of table to constrain
|
120
|
-
#
|
121
|
-
# @param constraint_name [String] name of foreign key constraint
|
122
|
-
#
|
123
|
-
# @return [String] SQL DDL Statement to destroy a constraint
|
124
|
-
#
|
125
|
-
# @api private
|
126
|
-
def destroy_constraints_statement(table_name, constraint_name)
|
127
|
-
<<-EOS.compress_lines
|
128
|
-
ALTER TABLE #{quote_table_name(table_name)}
|
129
|
-
DROP CONSTRAINT #{quote_constraint_name(constraint_name)}
|
130
|
-
EOS
|
131
|
-
end
|
132
|
-
|
133
|
-
##
|
134
|
-
# generates a unique constraint name given a table and a relationships
|
135
|
-
#
|
136
|
-
# @param table_name [String] name of table to constrain
|
137
|
-
#
|
138
|
-
# @param relationships_name [String] name of the relationship to constrain
|
139
|
-
#
|
140
|
-
# @return [String] name of the constraint
|
141
|
-
#
|
142
|
-
# @api private
|
143
|
-
def constraint_name(table_name, relationship_name)
|
144
|
-
"#{table_name}_#{relationship_name}_fk"
|
145
|
-
end
|
146
|
-
|
147
|
-
##
|
148
|
-
# SQL quotes a foreign key constraint name
|
149
|
-
#
|
150
|
-
# @see #quote_table_name
|
151
|
-
#
|
152
|
-
# @param foreign_key [String] SQL quotes a foreign key name
|
153
|
-
#
|
154
|
-
# @return [String] quoted constraint name
|
155
|
-
#
|
156
|
-
# @api private
|
157
|
-
def quote_constraint_name(foreign_key)
|
158
|
-
quote_table_name(foreign_key)
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
module Migration
|
163
|
-
def self.included(migrator)
|
164
|
-
migrator.extend(ClassMethods)
|
165
|
-
migrator.before_class_method :auto_migrate_down, :auto_migrate_constraints_down
|
166
|
-
migrator.after_class_method :auto_migrate_up, :auto_migrate_constraints_up
|
167
|
-
end
|
168
|
-
|
169
|
-
module ClassMethods
|
170
|
-
def auto_migrate_constraints_down(repository_name, *descendants)
|
171
|
-
descendants = DataMapper::Resource.descendants.to_a if descendants.empty?
|
172
|
-
descendants.each do |model|
|
173
|
-
repository_name ||= model.repository(repository_name).name
|
174
|
-
if model.storage_exists?(repository_name)
|
175
|
-
adapter = model.repository(repository_name).adapter
|
176
|
-
next unless adapter.respond_to?(:destroy_constraints_statements)
|
177
|
-
statements = adapter.destroy_constraints_statements(repository_name, model)
|
178
|
-
statements.each {|stmt| adapter.execute(stmt) }
|
179
|
-
end
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
def auto_migrate_constraints_up(retval, repository_name, *descendants)
|
184
|
-
descendants = DataMapper::Resource.descendants.to_a if descendants.empty?
|
185
|
-
descendants.each do |model|
|
186
|
-
repository_name ||= model.repository(repository_name).name
|
187
|
-
adapter = model.repository(repository_name).adapter
|
188
|
-
next unless adapter.respond_to?(:create_constraints_statements)
|
189
|
-
statements = adapter.create_constraints_statements(repository_name, model)
|
190
|
-
statements.each {|stmt| adapter.execute(stmt) }
|
191
|
-
end
|
192
|
-
end
|
193
|
-
end
|
194
|
-
end
|
195
|
-
end
|
196
|
-
end
|
197
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
module DataMapper
|
2
|
-
module Constraints
|
3
|
-
module MysqlAdapter
|
4
|
-
module SQL
|
5
|
-
include DataMapper::Constraints::DataObjectsAdapter::SQL
|
6
|
-
|
7
|
-
private
|
8
|
-
|
9
|
-
##
|
10
|
-
# MySQL specific query to determine to drop a foreign key
|
11
|
-
#
|
12
|
-
# @param table_name [Symbol] name of table to check constraint on
|
13
|
-
#
|
14
|
-
# @param constraint_name [~String] name of constraint to check for
|
15
|
-
#
|
16
|
-
# @return [String] SQL DDL to destroy a constraint
|
17
|
-
#
|
18
|
-
# @api private
|
19
|
-
def destroy_constraints_statement(table_name, constraint_name)
|
20
|
-
<<-EOS.compress_lines
|
21
|
-
ALTER TABLE #{quote_table_name(table_name)}
|
22
|
-
DROP FOREIGN KEY #{quote_constraint_name(constraint_name)}
|
23
|
-
EOS
|
24
|
-
end
|
25
|
-
|
26
|
-
##
|
27
|
-
# MySQL specific query to determine if a constraint exists
|
28
|
-
#
|
29
|
-
# @param table_name [Symbol] name of table to check constraint on
|
30
|
-
#
|
31
|
-
# @param constraint_name [~String] name of constraint to check for
|
32
|
-
#
|
33
|
-
# @return [Boolean]
|
34
|
-
#
|
35
|
-
# @api private
|
36
|
-
def constraint_exists?(table_name, constraint_name)
|
37
|
-
statement = <<-EOS.compress_lines
|
38
|
-
SELECT COUNT(*)
|
39
|
-
FROM `information_schema`.`table_constraints`
|
40
|
-
WHERE `constraint_type` = 'FOREIGN KEY'
|
41
|
-
AND `table_schema` = ?
|
42
|
-
AND `table_name` = ?
|
43
|
-
AND `constraint_name` = ?
|
44
|
-
EOS
|
45
|
-
query(statement, db_name, table_name, constraint_name).first > 0
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
module DataMapper
|
2
|
-
module Constraints
|
3
|
-
module PostgresAdapter
|
4
|
-
module SQL
|
5
|
-
include DataMapper::Constraints::DataObjectsAdapter::SQL
|
6
|
-
|
7
|
-
private
|
8
|
-
|
9
|
-
##
|
10
|
-
# Postgres specific query to determine if a constraint exists
|
11
|
-
#
|
12
|
-
# @param table_name [Symbol] name of table to check constraint on
|
13
|
-
#
|
14
|
-
# @param constraint_name [~String] name of constraint to check for
|
15
|
-
#
|
16
|
-
# @return [Boolean]
|
17
|
-
#
|
18
|
-
# @api private
|
19
|
-
def constraint_exists?(table_name, constraint_name)
|
20
|
-
statement = <<-EOS.compress_lines
|
21
|
-
SELECT COUNT(*)
|
22
|
-
FROM "information_schema"."table_constraints"
|
23
|
-
WHERE "table_schema" = current_schema()
|
24
|
-
AND "table_name" = ?
|
25
|
-
AND "constraint_name" = ?
|
26
|
-
EOS
|
27
|
-
query(statement, table_name, constraint_name).first > 0
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|