schema_auto_foreign_keys 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c7bb4e877d1795bda1f593666141fcc43c154410
4
+ data.tar.gz: 171e3b7fafbb1b6cbce610b9a7a83c425b93b7ab
5
+ SHA512:
6
+ metadata.gz: 207ed1d89fab44de59c78e882b0bc072707626a184045fcbc933e632f79f53871473762eaae3f8d71bc640e1f8735a38cbd18f064ccac496a68fc0de297ee5bf
7
+ data.tar.gz: c09043f5a1d8151b72c5432fde2e9106c6fb9cdb908736565710ac0fb467d0fca6716457a6740b7b515b6d7c66aeb7dfbf90143bc602157286595da3b142448e
@@ -0,0 +1,9 @@
1
+ /coverage
2
+ /tmp
3
+ /pkg
4
+ /Gemfile.local
5
+
6
+ *.lock
7
+ *.log
8
+ *.sqlite3
9
+ !gemfiles/**/*.sqlite3
@@ -0,0 +1,21 @@
1
+ # This file was auto-generated by the schema_dev tool, based on the data in
2
+ # ./schema_dev.yml
3
+ # Please do not edit this file; any changes will be overwritten next time
4
+ # schema_dev gets run.
5
+ ---
6
+ sudo: false
7
+ rvm:
8
+ - 2.1.5
9
+ gemfile:
10
+ - gemfiles/activerecord-4.2.0/Gemfile.mysql2
11
+ - gemfiles/activerecord-4.2.0/Gemfile.postgresql
12
+ - gemfiles/activerecord-4.2.0/Gemfile.sqlite3
13
+ - gemfiles/activerecord-4.2.1/Gemfile.mysql2
14
+ - gemfiles/activerecord-4.2.1/Gemfile.postgresql
15
+ - gemfiles/activerecord-4.2.1/Gemfile.sqlite3
16
+ env: POSTGRESQL_DB_USER=postgres MYSQL_DB_USER=travis
17
+ addons:
18
+ postgresql: '9.4'
19
+ before_script: bundle exec rake create_databases
20
+ after_script: bundle exec rake drop_databases
21
+ script: bundle exec rake travis
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ File.exist?(gemfile_local = File.expand_path('../Gemfile.local', __FILE__)) and eval File.read(gemfile_local), binding, gemfile_local
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 ronen barzel
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,144 @@
1
+ [![Gem Version](https://badge.fury.io/rb/schema_auto_foreign_keys.svg)](http://badge.fury.io/rb/schema_auto_foreign_keys)
2
+ [![Build Status](https://secure.travis-ci.org/SchemaPlus/schema_auto_foreign_keys.svg)](http://travis-ci.org/SchemaPlus/schema_auto_foreign_keys)
3
+ [![Coverage Status](https://img.shields.io/coveralls/SchemaPlus/schema_auto_foreign_keys.svg)](https://coveralls.io/r/SchemaPlus/schema_auto_foreign_keys)
4
+ [![Dependency Status](https://gemnasium.com/lomba/schema_auto_foreign_keys.svg)](https://gemnasium.com/SchemaPlus/schema_auto_foreign_keys)
5
+
6
+ # SchemaAutoForeignKeys
7
+
8
+
9
+ SchemaAutoForeignKeys is part of the [SchemaPlus](https://github.com/SchemaPlus/) family of Ruby on Rails ActiveRecord extension gems.
10
+
11
+ ## Usage
12
+
13
+ Many of us think that it should goes without saying that if you define a foreign key *relation* in your database you should also define a foreign key *constraint*.
14
+
15
+ Similarly, it should go without saying that if you have a foreign key *constraint* on a column, you should also have an *index* on that column.
16
+
17
+ And if you include the `schema_auto_foreign_keys` gem, these will also go without typing! schema_auto_foreign_keys simply turns on some default behavior in your migrations:
18
+
19
+ ```ruby
20
+ t.integer :user_id # any column named xxxx_id defaults to...
21
+ t.integer :user_id, foreign_key: true, index: true
22
+
23
+ t.references :user # references defaults to...
24
+ t.references :user, foreign_key: true, index: true
25
+
26
+ t.belongs_to :user # belongs_to default to...
27
+ t.belongs_to :user, foreign_key: true, index: true
28
+ ```
29
+
30
+ Note that schema_auto_foreign_keys depends on the [schema_plus_foreign_keys](https://github.com/SchemaPlus/schema_plus_foreign_keys) and [schema_plus_indexes](https://github.com/SchemaPlus/schema_plus_indexes) gems, and so makes available their migration shortcuts.
31
+
32
+ There is actually one difference between an auto-created index and specifying `index: true`: if you don't specify anything, schema_auto_foreign_keys will maintain "ownership" of the auto-created index: It will remove the index if the foreign key gets removed; and it will rename the index if the table gets renamed.
33
+
34
+ ### Overriding
35
+
36
+ If you need specific paramaters other than the default, you can of course specify them:
37
+
38
+ ```ruby
39
+ t.integer :user_id, index: :unique # "has one" relationship between users and this
40
+ model
41
+ t.integer :user_id, on_delete: :cascade
42
+ ```
43
+
44
+ If you don't want a foreign key constraint (e.g. because "product_id" is a domain-level string rather than a foreign key), or an index just specify falsey:
45
+
46
+ ```rugy
47
+ t.integer :product_id, foreign_key: false # also implies index: false
48
+ t.integer :product_id, references: nil
49
+ t.integer :user_id, index: false
50
+ ```
51
+
52
+ ## Configuration
53
+
54
+ SchemaAutoForeignKeys adds two new entries to SchemaPlus::ForeignKeys' config:
55
+
56
+ ```ruby
57
+ SchemaPlus::ForeignKeys.setup do |config|
58
+ config.auto_create = true # default for schema_auto_foreign_keys
59
+ config.auto_index = true # default for schema_auto_foreign_keys
60
+ end
61
+ ```
62
+
63
+ You can also configure the behavior per-table in a migration:
64
+
65
+ ```ruby
66
+ create_table :posts, foreign_keys: { auto_create: true, auto_index: true } do |t|
67
+ t.integer :author_id
68
+ endf
69
+ ```
70
+
71
+
72
+ ## Installation
73
+
74
+ <!-- SCHEMA_DEV: TEMPLATE INSTALLATION - begin -->
75
+ <!-- These lines are auto-inserted from a schema_dev template -->
76
+ As usual:
77
+
78
+ ```ruby
79
+ gem "schema_auto_foreign_keys" # in a Gemfile
80
+ gem.add_dependency "schema_auto_foreign_keys" # in a .gemspec
81
+ ```
82
+
83
+ <!-- SCHEMA_DEV: TEMPLATE INSTALLATION - end -->
84
+
85
+ ## Compatibility
86
+
87
+ SchemaAutoForeignKeys is tested on:
88
+
89
+ <!-- SCHEMA_DEV: MATRIX - begin -->
90
+ <!-- These lines are auto-generated by schema_dev based on schema_dev.yml -->
91
+ * ruby **2.1.5** with activerecord **4.2.0**, using **mysql2**, **sqlite3** or **postgresql**
92
+ * ruby **2.1.5** with activerecord **4.2.1**, using **mysql2**, **sqlite3** or **postgresql**
93
+
94
+ <!-- SCHEMA_DEV: MATRIX - end -->
95
+
96
+ ### Platform-specific Notes:
97
+
98
+ MySQL automatically creates indexes for foreign key constraints, so when used with MySQL, schema_auto_foreign_keys doesn't include the auto-index capability.
99
+
100
+ SQlite3 doesn't support renaming the auto-index whtn the table name changes.
101
+
102
+
103
+
104
+ ## History
105
+
106
+ * 0.1.0 - Initial release, extracted from schema_plus 2.0.0.pre*
107
+
108
+ ## Development & Testing
109
+
110
+ Are you interested in contributing to SchemaAutoForeignKeys? Thanks! Please follow
111
+ the standard protocol: fork, feature branch, develop, push, and issue pull
112
+ request.
113
+
114
+ Some things to know about to help you develop and test:
115
+
116
+ <!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_DEV - begin -->
117
+ <!-- These lines are auto-inserted from a schema_dev template -->
118
+ * **schema_dev**: SchemaAutoForeignKeys uses [schema_dev](https://github.com/SchemaPlus/schema_dev) to
119
+ facilitate running rspec tests on the matrix of ruby, activerecord, and database
120
+ versions that the gem supports, both locally and on
121
+ [travis-ci](http://travis-ci.org/SchemaPlus/schema_auto_foreign_keys)
122
+
123
+ To to run rspec locally on the full matrix, do:
124
+
125
+ $ schema_dev bundle install
126
+ $ schema_dev rspec
127
+
128
+ You can also run on just one configuration at a time; For info, see `schema_dev --help` or the [schema_dev](https://github.com/SchemaPlus/schema_dev) README.
129
+
130
+ The matrix of configurations is specified in `schema_dev.yml` in
131
+ the project root.
132
+
133
+
134
+ <!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_DEV - end -->
135
+
136
+
137
+ <!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_MONKEY - begin -->
138
+ <!-- These lines are auto-inserted from a schema_dev template -->
139
+ * **schema_monkey**: SchemaAutoForeignKeys is implemented as a
140
+ [schema_monkey](https://github.com/SchemaPlus/schema_monkey) client,
141
+ using [schema_monkey](https://github.com/SchemaPlus/schema_monkey)'s
142
+ convention-based protocols for extending ActiveRecord and using middleware stacks.
143
+
144
+ <!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_MONKEY - end -->
@@ -0,0 +1,9 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'schema_dev/tasks'
5
+
6
+ task :default => :spec
7
+
8
+ require 'rspec/core/rake_task'
9
+ RSpec::Core::RakeTask.new(:spec)
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+ gemspec :path => File.expand_path('..', __FILE__)
3
+
4
+ File.exist?(gemfile_local = File.expand_path('../Gemfile.local', __FILE__)) and eval File.read(gemfile_local), binding, gemfile_local
@@ -0,0 +1,3 @@
1
+ eval File.read File.expand_path('../../Gemfile.base', __FILE__)
2
+
3
+ gem "activerecord", "4.2.0"
@@ -0,0 +1,10 @@
1
+ require "pathname"
2
+ eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
+
4
+ platform :ruby do
5
+ gem "mysql2"
6
+ end
7
+
8
+ platform :jruby do
9
+ gem 'activerecord-jdbcmysql-adapter'
10
+ end
@@ -0,0 +1,10 @@
1
+ require "pathname"
2
+ eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
+
4
+ platform :ruby do
5
+ gem "pg"
6
+ end
7
+
8
+ platform :jruby do
9
+ gem 'activerecord-jdbcpostgresql-adapter'
10
+ end
@@ -0,0 +1,10 @@
1
+ require "pathname"
2
+ eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
+
4
+ platform :ruby do
5
+ gem "sqlite3"
6
+ end
7
+
8
+ platform :jruby do
9
+ gem 'activerecord-jdbcsqlite3-adapter', '>=1.3.0.beta2'
10
+ end
@@ -0,0 +1,3 @@
1
+ eval File.read File.expand_path('../../Gemfile.base', __FILE__)
2
+
3
+ gem "activerecord", "4.2.1"
@@ -0,0 +1,10 @@
1
+ require "pathname"
2
+ eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
+
4
+ platform :ruby do
5
+ gem "mysql2"
6
+ end
7
+
8
+ platform :jruby do
9
+ gem 'activerecord-jdbcmysql-adapter'
10
+ end
@@ -0,0 +1,10 @@
1
+ require "pathname"
2
+ eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
+
4
+ platform :ruby do
5
+ gem "pg"
6
+ end
7
+
8
+ platform :jruby do
9
+ gem 'activerecord-jdbcpostgresql-adapter'
10
+ end
@@ -0,0 +1,10 @@
1
+ require "pathname"
2
+ eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
+
4
+ platform :ruby do
5
+ gem "sqlite3"
6
+ end
7
+
8
+ platform :jruby do
9
+ gem 'activerecord-jdbcsqlite3-adapter', '>=1.3.0.beta2'
10
+ end
@@ -0,0 +1,31 @@
1
+ require 'schema_plus/foreign_keys'
2
+ require 'schema_plus/indexes'
3
+
4
+ require_relative 'schema_auto_foreign_keys/middleware/migration'
5
+ require_relative 'schema_auto_foreign_keys/middleware/schema'
6
+
7
+ module SchemaAutoForeignKeys
8
+ module ActiveRecord
9
+ module ConnectionAdapters
10
+ autoload :Sqlite3Adapter, 'schema_auto_foreign_keys/active_record/connection_adapters/sqlite3_adapter'
11
+ end
12
+ end
13
+ end
14
+
15
+ class SchemaPlus::ForeignKeys::Config
16
+ ##
17
+ # :attr_accessor: auto_create
18
+ #
19
+ # Whether to automatically create foreign key constraints for columns
20
+ # suffixed with +_id+. Boolean, default is +true+.
21
+ has_value :auto_create, :klass => :boolean, :default => true
22
+
23
+ ##
24
+ # :attr_accessor: auto_index
25
+ #
26
+ # Whether to automatically create indexes when creating foreign key constraints for columns.
27
+ # Boolean, default is +true+.
28
+ has_value :auto_index, :klass => :boolean, :default => true
29
+ end
30
+
31
+ SchemaMonkey.register SchemaAutoForeignKeys
@@ -0,0 +1,22 @@
1
+ module SchemaAutoForeignKeys
2
+ module ActiveRecord
3
+ module ConnectionAdapters
4
+
5
+ # SchemaPlus::ForeignKeys includes an Sqlite3 implementation of the AbstractAdapter
6
+ # extensions.
7
+ module Sqlite3Adapter
8
+
9
+ def copy_table(*args, &block)
10
+ fk_override = { :auto_create => false, :auto_index => false }
11
+ save = Hash[fk_override.keys.collect{|key| [key, SchemaPlus::ForeignKeys.config.send(key)]}]
12
+ begin
13
+ SchemaPlus::ForeignKeys.config.update_attributes(fk_override)
14
+ super
15
+ ensure
16
+ SchemaPlus::ForeignKeys.config.update_attributes(save)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,90 @@
1
+ require 'openssl'
2
+
3
+ module SchemaAutoForeignKeys
4
+ module AutoCreate
5
+ # defined below
6
+ end
7
+
8
+ module Middleware
9
+ module Migration
10
+ module Column
11
+ module PostgreSQL ; include AutoCreate ; end
12
+ module SQLite3 ; include AutoCreate ; end
13
+ module MySQL
14
+ include AutoCreate
15
+ def auto_index?(env, config) ; false end
16
+ def remove_auto_index?(env) ; false end
17
+ end
18
+ end
19
+
20
+ module RenameTable
21
+ def after(env)
22
+ newname = env.new_name
23
+ oldname = env.table_name
24
+ indexes = env.connection.indexes(newname)
25
+ env.connection.foreign_keys(newname).each do |fk|
26
+ index = indexes.find(&its.name == AutoCreate.auto_index_name(oldname, fk.column))
27
+ env.connection.rename_index(newname, index.name, AutoCreate.auto_index_name(newname, index.columns)) if index
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ module AutoCreate
35
+ def before(env)
36
+ config ||= env.caller.try(:schema_plus_foreign_keys_config) || SchemaPlus::ForeignKeys.config
37
+ set_foreign_key(env) if auto_fk?(env, config)
38
+ set_auto_index(env) if auto_index?(env, config)
39
+ end
40
+
41
+ def after(env)
42
+ remove_auto_index(env) if env.operation == :change and remove_auto_index?(env)
43
+ end
44
+
45
+ def auto_fk?(env, config)
46
+ return false if env.options.include? :foreign_key
47
+ return false unless config.auto_create?
48
+ return true if env.type == :reference
49
+ return false if env.implements_reference
50
+ return true if env.column_name.to_s =~ /_id$/ # later on add a config option for this
51
+ end
52
+
53
+ def auto_index?(env, config)
54
+ return false if env.options.include? :index
55
+ return false unless env.options[:foreign_key]
56
+ return true if config.auto_index?
57
+ end
58
+
59
+ def remove_auto_index?(env)
60
+ env.options.include? :foreign_key and not env.options[:foreign_key]
61
+ end
62
+
63
+ def set_foreign_key(env)
64
+ env.options[:foreign_key] = true
65
+ end
66
+
67
+ def set_auto_index(env)
68
+ env.options[:index] = { name: auto_index_name(env) }
69
+ end
70
+
71
+ def remove_auto_index(env)
72
+ env.caller.remove_index(env.table_name, :name => auto_index_name(env), :column => env.column_name, :if_exists => true)
73
+ end
74
+
75
+ def auto_index_name(env)
76
+ AutoCreate.auto_index_name(env.table_name, env.column_name)
77
+ end
78
+
79
+ def self.auto_index_name(from_table, column_name)
80
+ name = "fk__#{fixup_schema_name(from_table)}_#{Array.wrap(column_name).join('_and_')}"
81
+ name = name.slice(0, 27) + "_" + OpenSSL::Digest::MD5.new.hexdigest(name) if name.length > 60
82
+ name
83
+ end
84
+
85
+ def self.fixup_schema_name(table_name)
86
+ # replace . with _
87
+ table_name.to_s.gsub(/[.]/, '_')
88
+ end
89
+ end
90
+ end