miguel 0.1.0.pre4 → 0.1.0.pre5
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.
- checksums.yaml +4 -4
- data/.travis.yml +3 -0
- data/README.md +7 -5
- data/lib/miguel/importer.rb +44 -38
- data/lib/miguel/migrator.rb +2 -2
- data/lib/miguel/schema.rb +29 -6
- data/miguel.gemspec +4 -1
- data/test/data/db.yml +17 -0
- data/test/data/schema.rb +3 -2
- data/test/data/schema.txt +24 -23
- data/test/data/schema_bare.txt +128 -0
- data/test/data/schema_change.txt +132 -0
- data/test/data/schema_down.txt +32 -0
- data/test/data/schema_full.txt +166 -0
- data/test/data/seq_0.rb +18 -0
- data/test/data/seq_0.txt +17 -0
- data/test/data/seq_1.rb +33 -0
- data/test/data/seq_1.txt +60 -0
- data/test/data/seq_2.rb +38 -0
- data/test/data/seq_2.txt +51 -0
- data/test/data/simple.txt +5 -5
- data/test/helper.rb +24 -0
- data/test/test_importer.rb +66 -0
- data/test/test_migrator.rb +53 -0
- data/test/test_schema.rb +473 -8
- metadata +57 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a0ecd54548a6934b77b3f075d8b1fc74db7c555b
|
4
|
+
data.tar.gz: 87c76a4d8e883f01be334d3d07fd3be0598d5097
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1d8c0640ab68fe0d19b45a4f6ab05b34acba429d21dd3de9d30341eb64aab8127e2535ce416eb29ecdfb741d8d1f07fe624ba249ba45fce35a1d1689faaf0ad5
|
7
|
+
data.tar.gz: e3598249193c4e2edd85800f9b48c584526ab56045516c3910969a82ccf8ae11e79ca7dc27675e734727907303bcdf09bf43b4fe95368cbb3c43db1f4c208dc9
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -102,7 +102,7 @@ end
|
|
102
102
|
```
|
103
103
|
|
104
104
|
One enhancement is that it allows you to define `NULL` columns simply by adding `?` to the type name.
|
105
|
-
Anything else is implicitly `NOT NULL`, which is a really wise default.
|
105
|
+
Anything else is implicitly `NOT NULL`, which is a really wise default for many reasons.
|
106
106
|
|
107
107
|
Another enhancement is that it allows you to set defaults and
|
108
108
|
define custom shortcuts for types which you use frequently.
|
@@ -118,24 +118,26 @@ set_defaults :False, :TrueClass, default: false
|
|
118
118
|
set_defaults :Signed, :integer, unsigned: false
|
119
119
|
set_defaults :Unsigned, :integer, unsigned: true
|
120
120
|
set_defaults :Text, :String, text: true
|
121
|
-
set_defaults :Time, :timestamp, default: '
|
121
|
+
set_defaults :Time, :timestamp, default: '2000-01-01 00:00:00'
|
122
122
|
set_defaults :Time?, :timestamp, default: nil
|
123
123
|
|
124
124
|
set_defaults :unique, :index, unique: true
|
125
125
|
|
126
|
+
set_defaults :Key, :integer, unsigned: false
|
126
127
|
set_defaults :primary_key, type: :integer, unsigned: false
|
127
128
|
set_defaults :foreign_key, key: :id, type: :integer, unsigned: false
|
128
129
|
```
|
129
130
|
|
130
131
|
If you prefer unsigned keys instead and your database engine supports it,
|
131
|
-
you can pass the `unsigned_keys: true` option to `define` to make it happen.
|
132
|
+
you can pass the `unsigned_keys: true` option to `Schema.define` to make it happen.
|
132
133
|
If you don't want any of these defaults set up for you,
|
133
|
-
pass the `use_defaults: false` option to define instead.
|
134
|
+
pass the `use_defaults: false` option to `define` instead.
|
134
135
|
|
135
136
|
Finally, the `timestamps` helper can be used to create the
|
136
137
|
`create_time` and `update_time` timestamps for you.
|
137
138
|
If you pass the `mysql_timestamps: true` option to `define`,
|
138
|
-
the `update_time` timestamp will have the MySQL auto-update feature enabled
|
139
|
+
the `update_time` timestamp will have the MySQL auto-update feature enabled,
|
140
|
+
and timestamps will use the `'0000-00-00 00:00:00'` default by default.
|
139
141
|
|
140
142
|
## Using the command
|
141
143
|
|
data/lib/miguel/importer.rb
CHANGED
@@ -105,27 +105,24 @@ module Miguel
|
|
105
105
|
|
106
106
|
# Convert given database default of given type to default used by our schema definitions.
|
107
107
|
def revert_default( type, default, ruby_default )
|
108
|
-
default = ruby_default unless ruby_default.nil?
|
109
|
-
return if default.nil?
|
110
|
-
|
111
|
-
case default
|
112
|
-
when String, Numeric, TrueClass, FalseClass
|
113
|
-
when DateTime
|
114
|
-
default = default.strftime( '%F %T' )
|
115
|
-
else
|
116
|
-
default = default.to_s
|
117
|
-
end
|
118
|
-
|
119
108
|
if type.to_s =~ /date|time/
|
120
109
|
case default
|
121
|
-
when /\A'([-: \d]+)'\z/
|
122
|
-
default = $1
|
123
110
|
when 'CURRENT_TIMESTAMP'
|
124
111
|
# This matches our use of MySQL timestamps in schema definitions.
|
125
|
-
|
112
|
+
return Sequel.lit('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP')
|
126
113
|
end
|
127
114
|
end
|
128
|
-
|
115
|
+
|
116
|
+
default = ruby_default unless ruby_default.nil?
|
117
|
+
|
118
|
+
case default
|
119
|
+
when nil, String, Numeric, TrueClass, FalseClass
|
120
|
+
return default
|
121
|
+
when DateTime
|
122
|
+
return default.strftime( '%F %T' )
|
123
|
+
else
|
124
|
+
return default.to_s
|
125
|
+
end
|
129
126
|
end
|
130
127
|
|
131
128
|
# Import indexes of given table.
|
@@ -156,46 +153,55 @@ module Miguel
|
|
156
153
|
# These are usually just schema hints which the user normally doesn't specify.
|
157
154
|
IGNORED_OPTS = [ :max_length ]
|
158
155
|
|
159
|
-
# Import
|
160
|
-
def
|
161
|
-
|
156
|
+
# Import column type and options.
|
157
|
+
def import_column_type_and_options( opts )
|
158
|
+
opts = opts.dup
|
162
159
|
|
163
|
-
#
|
160
|
+
# Discard anything we don't need.
|
164
161
|
|
165
|
-
|
162
|
+
opts.delete_if{ |key, value| IGNORED_OPTS.include? key }
|
166
163
|
|
167
|
-
|
164
|
+
# Import type.
|
168
165
|
|
169
|
-
|
166
|
+
type = opts.delete( :type )
|
167
|
+
db_type = opts.delete( :db_type )
|
170
168
|
|
171
|
-
|
169
|
+
type, type_opts = revert_type_literal( db_type, type )
|
170
|
+
opts.merge!( type_opts ) if type_opts
|
172
171
|
|
173
|
-
|
172
|
+
# Import NULL option.
|
174
173
|
|
175
|
-
|
174
|
+
opts[ :null ] = opts.delete( :allow_null )
|
176
175
|
|
177
|
-
|
176
|
+
# Import default value.
|
178
177
|
|
179
|
-
|
178
|
+
default = opts.delete( :default )
|
179
|
+
ruby_default = opts.delete( :ruby_default )
|
180
|
+
|
181
|
+
default = revert_default( type, default, ruby_default )
|
182
|
+
|
183
|
+
opts[ :default ] = default unless default.nil?
|
184
|
+
|
185
|
+
[ type, opts ]
|
186
|
+
end
|
180
187
|
|
181
|
-
|
182
|
-
|
188
|
+
# Import columns of given table.
|
189
|
+
def import_columns( table )
|
190
|
+
schema = db.schema( table.name )
|
183
191
|
|
184
|
-
|
185
|
-
opts.merge!( type_opts ) if type_opts
|
192
|
+
# Get info about primary key columns.
|
186
193
|
|
187
|
-
|
194
|
+
primary_key_columns = schema.select{ |name, opts| opts[ :primary_key ] }
|
188
195
|
|
189
|
-
|
196
|
+
multi_primary_key = ( primary_key_columns.count > 1 )
|
190
197
|
|
191
|
-
|
198
|
+
# Import each column in sequence.
|
192
199
|
|
193
|
-
|
194
|
-
ruby_default = opts.delete( :ruby_default )
|
200
|
+
for name, opts in schema
|
195
201
|
|
196
|
-
|
202
|
+
# Import column type and options.
|
197
203
|
|
198
|
-
opts
|
204
|
+
type, opts = import_column_type_and_options( opts )
|
199
205
|
|
200
206
|
# Deal with primary keys, which is a bit obscure because of the auto-increment handling.
|
201
207
|
|
data/lib/miguel/migrator.rb
CHANGED
@@ -111,7 +111,7 @@ module Miguel
|
|
111
111
|
# Generate code for dropping given columns.
|
112
112
|
def dump_drop_columns( out, columns )
|
113
113
|
for column in columns
|
114
|
-
if column.
|
114
|
+
if column.primary_key_constraint?
|
115
115
|
out << "drop_constraint #{column.out_name}, :type => :primary_key#{column.out_opts(' # ')}"
|
116
116
|
else
|
117
117
|
out << "drop_column #{column.out_name} # #{column.out_type}#{column.out_opts}"
|
@@ -125,7 +125,7 @@ module Miguel
|
|
125
125
|
if column.type == :primary_key
|
126
126
|
out << "add_primary_key #{column.out_name}#{column.out_opts}"
|
127
127
|
else
|
128
|
-
out << "add_column #{column.out_name}, #{column.out_type}#{column.
|
128
|
+
out << "add_column #{column.out_name}, #{column.out_type}#{column.out_default_opts}"
|
129
129
|
end
|
130
130
|
end
|
131
131
|
end
|
data/lib/miguel/schema.rb
CHANGED
@@ -9,9 +9,12 @@ module Miguel
|
|
9
9
|
# Class for defining database schema.
|
10
10
|
class Schema
|
11
11
|
|
12
|
-
# String denoting zero time.
|
12
|
+
# String denoting zero time in MySQL.
|
13
13
|
ZERO_TIME = '0000-00-00 00:00:00'.freeze
|
14
14
|
|
15
|
+
# String denoting default time.
|
16
|
+
DEFAULT_TIME = '2000-01-01 00:00:00'.freeze
|
17
|
+
|
15
18
|
# Module for pretty printing of names, types, and especially options.
|
16
19
|
module Output
|
17
20
|
|
@@ -45,6 +48,10 @@ module Miguel
|
|
45
48
|
out_hash( canonic_opts, prefix )
|
46
49
|
end
|
47
50
|
|
51
|
+
def out_default_opts( prefix = ', ' )
|
52
|
+
out_hash( default_opts, prefix )
|
53
|
+
end
|
54
|
+
|
48
55
|
def out_name
|
49
56
|
name.inspect
|
50
57
|
end
|
@@ -81,6 +88,11 @@ module Miguel
|
|
81
88
|
@opts = opts
|
82
89
|
end
|
83
90
|
|
91
|
+
# Test if the column is in fact just a primary key constraint.
|
92
|
+
def primary_key_constraint?
|
93
|
+
type == :primary_key && name.is_a?( Array )
|
94
|
+
end
|
95
|
+
|
84
96
|
# Get the column default.
|
85
97
|
def default
|
86
98
|
d = opts[ :default ]
|
@@ -159,7 +171,7 @@ module Miguel
|
|
159
171
|
|
160
172
|
# Get the column options in a canonic way.
|
161
173
|
def canonic_opts
|
162
|
-
return {} if
|
174
|
+
return {} if primary_key_constraint?
|
163
175
|
o = { :type => canonic_type, :default => default, :null => true }
|
164
176
|
o.merge!( DEFAULT_OPTS[ canonic_type ] || {} )
|
165
177
|
o.merge!( opts )
|
@@ -167,6 +179,11 @@ module Miguel
|
|
167
179
|
o.delete_if{ |key, value| IGNORED_OPTS.include? key }
|
168
180
|
end
|
169
181
|
|
182
|
+
# Get options with default value included.
|
183
|
+
def default_opts
|
184
|
+
{ :default => default }.merge( opts )
|
185
|
+
end
|
186
|
+
|
170
187
|
# Compare one column with another one.
|
171
188
|
def == other
|
172
189
|
other.is_a?( Column ) &&
|
@@ -240,7 +257,7 @@ module Miguel
|
|
240
257
|
|
241
258
|
# Options we ignore when comparing.
|
242
259
|
# These are usually tied to the underlying column, not constraint.
|
243
|
-
IGNORED_OPTS = [ :null, :unsigned, :type ]
|
260
|
+
IGNORED_OPTS = [ :null, :unsigned, :type, :default ]
|
244
261
|
|
245
262
|
# Get the foreign key options, in a canonic way.
|
246
263
|
def canonic_opts
|
@@ -475,6 +492,7 @@ module Miguel
|
|
475
492
|
# Also note that the defaults are applied in the instant the +table+ block is evaluated,
|
476
493
|
# so it is eventually possible (though not necessarily recommended) to change them in between.
|
477
494
|
def set_defaults( name, *args, &block )
|
495
|
+
clear_defaults( name )
|
478
496
|
@aliases[ name ] = args.shift if args.first.is_a? Symbol
|
479
497
|
@defaults[ name ] = args.pop if args.last.is_a? Hash
|
480
498
|
@callbacks[ name ] = block
|
@@ -512,6 +530,7 @@ module Miguel
|
|
512
530
|
#
|
513
531
|
# :unique, :index, :unique => true
|
514
532
|
#
|
533
|
+
# :Key, :integer, :unsigned => false
|
515
534
|
# :primary_key, :type => :integer, :unsigned => false
|
516
535
|
# :foreign_key, :key => :id, :type => :integer, :unsigned => false
|
517
536
|
#
|
@@ -528,14 +547,17 @@ module Miguel
|
|
528
547
|
# Unfortunately, :unsigned currently works only with :integer,
|
529
548
|
# not the default :Integer, and :integer can't be specified for compound keys,
|
530
549
|
# so we have to use the callback to set the type only at correct times.
|
550
|
+
# Furthermore, Postgres's autoincrementing serials only work with Integer,
|
551
|
+
# so we set the type only as long as the unsigned keys are not requested.
|
531
552
|
|
532
553
|
unsigned_keys = !! opts[ :unsigned_keys ]
|
533
554
|
|
555
|
+
set_defaults :Key, :integer, :unsigned => unsigned_keys
|
534
556
|
set_defaults :primary_key, :unsigned => unsigned_keys do |opts,args,table|
|
535
|
-
opts[ :type ] ||= :integer unless args.first.is_a? Array
|
557
|
+
opts[ :type ] ||= :integer unless args.first.is_a? Array or not opts[ :unsigned ]
|
536
558
|
end
|
537
559
|
set_defaults :foreign_key, :key => :id, :unsigned => unsigned_keys do |opts,args,table|
|
538
|
-
opts[ :type ] ||= :integer unless args.first.is_a? Array
|
560
|
+
opts[ :type ] ||= :integer unless args.first.is_a? Array or not opts[ :unsigned ]
|
539
561
|
end
|
540
562
|
|
541
563
|
# Save some typing for unique indexes.
|
@@ -557,7 +579,8 @@ module Miguel
|
|
557
579
|
# we have to be careful to turn off the MySQL autoupdate behavior.
|
558
580
|
# That's why we have to set defaults explicitly.
|
559
581
|
|
560
|
-
|
582
|
+
default_time = opts[ :mysql_timestamps ] ? ZERO_TIME : DEFAULT_TIME
|
583
|
+
set_defaults :Time, :timestamp, :default => default_time
|
561
584
|
set_defaults :Time?, :timestamp, :default => nil
|
562
585
|
|
563
586
|
self
|
data/miguel.gemspec
CHANGED
@@ -4,7 +4,7 @@ require File.expand_path( '../lib/miguel/version', __FILE__ )
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = 'miguel'
|
7
|
-
s.version = Miguel::VERSION + '.
|
7
|
+
s.version = Miguel::VERSION + '.pre5'
|
8
8
|
s.summary = 'Database migrator and migration generator for Sequel.'
|
9
9
|
s.description = <<EOT
|
10
10
|
This gem makes it easy to create and maintain an up-to-date database schema
|
@@ -22,6 +22,9 @@ EOT
|
|
22
22
|
s.required_ruby_version = '>= 1.9.3'
|
23
23
|
s.add_runtime_dependency 'sequel', '~> 4.0'
|
24
24
|
s.add_development_dependency 'bacon', '~> 1.2'
|
25
|
+
s.add_development_dependency 'sqlite3'
|
26
|
+
s.add_development_dependency 'mysql2'
|
27
|
+
s.add_development_dependency 'pg'
|
25
28
|
end
|
26
29
|
|
27
30
|
# EOF #
|
data/test/data/db.yml
ADDED
data/test/data/schema.rb
CHANGED
@@ -29,6 +29,7 @@ Miguel::Schema.define( use_defaults: false ) do
|
|
29
29
|
set_defaults :Custom, :String, fixed: true, size: 3
|
30
30
|
|
31
31
|
table :miguel_types do
|
32
|
+
Key :key
|
32
33
|
String :string
|
33
34
|
Text :text
|
34
35
|
File :blob
|
@@ -74,8 +75,8 @@ Miguel::Schema.define( use_defaults: false ) do
|
|
74
75
|
end
|
75
76
|
|
76
77
|
table :compound do
|
77
|
-
|
78
|
-
|
78
|
+
Integer :a
|
79
|
+
Integer :b
|
79
80
|
primary_key [:a, :b]
|
80
81
|
foreign_key [:b, :a], :compound, key: [:a, :b]
|
81
82
|
String :c
|
data/test/data/schema.txt
CHANGED
@@ -19,6 +19,7 @@ table :sequel_types do
|
|
19
19
|
FalseClass :l
|
20
20
|
end
|
21
21
|
table :miguel_types do
|
22
|
+
integer :key, :null => false, :unsigned => false
|
22
23
|
String :string, :null => false
|
23
24
|
String :text, :null => false, :text => true
|
24
25
|
File :blob, :null => false
|
@@ -29,7 +30,7 @@ table :miguel_types do
|
|
29
30
|
TrueClass :bool, :null => false
|
30
31
|
TrueClass :true, :null => false, :default => true
|
31
32
|
TrueClass :false, :null => false, :default => false
|
32
|
-
timestamp :time, :null => false, :default => "
|
33
|
+
timestamp :time, :null => false, :default => "2000-01-01 00:00:00"
|
33
34
|
String :custom, :null => false, :fixed => true, :size => 3
|
34
35
|
end
|
35
36
|
table :native_types do
|
@@ -39,29 +40,29 @@ table :native_types do
|
|
39
40
|
timestamp :timestamp, :null => false, :default => "1970-01-02 00:00:00"
|
40
41
|
end
|
41
42
|
table :timestamps do
|
42
|
-
timestamp :t1, :null => false, :default => "
|
43
|
+
timestamp :t1, :null => false, :default => "2000-01-01 00:00:00"
|
43
44
|
timestamp :t2, :null => true, :default => nil
|
44
|
-
timestamp :create_time, :null => false, :default => "
|
45
|
-
timestamp :update_time, :null => false, :default => "
|
45
|
+
timestamp :create_time, :null => false, :default => "2000-01-01 00:00:00"
|
46
|
+
timestamp :update_time, :null => false, :default => "2000-01-01 00:00:00"
|
46
47
|
end
|
47
48
|
table :users do
|
48
|
-
primary_key :id, :null => false, :unsigned => false
|
49
|
+
primary_key :id, :null => false, :unsigned => false
|
49
50
|
String :name, :null => false
|
50
51
|
index [:name], :null => false, :unique => true
|
51
52
|
end
|
52
53
|
table :simple do
|
53
|
-
primary_key :id, :null => false, :unsigned => false
|
54
|
-
integer :user_id, :null => false, :key => [:id], :unsigned => false
|
54
|
+
primary_key :id, :null => false, :unsigned => false
|
55
|
+
integer :user_id, :null => false, :key => [:id], :unsigned => false
|
55
56
|
index [:user_id], :null => false
|
56
|
-
foreign_key [:user_id], :users, :null => false, :key => [:id], :unsigned => false
|
57
|
+
foreign_key [:user_id], :users, :null => false, :key => [:id], :unsigned => false
|
57
58
|
end
|
58
59
|
table :reuse do
|
59
|
-
primary_key :user_id, :null => false, :unsigned => false
|
60
|
+
primary_key :user_id, :null => false, :unsigned => false
|
60
61
|
foreign_key [:user_id], :users, :null => false, :key => [:id], :unsigned => false
|
61
62
|
end
|
62
63
|
table :compound do
|
63
|
-
|
64
|
-
|
64
|
+
Integer :a, :null => false
|
65
|
+
Integer :b, :null => false
|
65
66
|
primary_key [:a, :b], :null => false, :unsigned => false
|
66
67
|
String :c, :null => false
|
67
68
|
integer :d, :null => false, :unsigned => false
|
@@ -82,8 +83,8 @@ table :null do
|
|
82
83
|
TrueClass :true, :null => true, :default => true
|
83
84
|
TrueClass :false, :null => true, :default => false
|
84
85
|
timestamp :t, :null => true, :default => nil
|
85
|
-
integer :user_id, :null => true, :key => [:id], :unsigned => false
|
86
|
-
foreign_key [:user_id], :users, :null => true, :key => [:id], :unsigned => false
|
86
|
+
integer :user_id, :null => true, :key => [:id], :unsigned => false
|
87
|
+
foreign_key [:user_id], :users, :null => true, :key => [:id], :unsigned => false
|
87
88
|
end
|
88
89
|
table :defaults do
|
89
90
|
String :string, :null => false, :default => "abc"
|
@@ -95,21 +96,21 @@ table :defaults do
|
|
95
96
|
timestamp :time, :null => false, :default => "2037-12-31 23:59:59"
|
96
97
|
end
|
97
98
|
table :simple_users do
|
98
|
-
integer :user_id, :null => false, :key => [:id], :unsigned => false
|
99
|
-
integer :simple_id, :null => false, :key => [:id], :unsigned => false
|
99
|
+
integer :user_id, :null => false, :key => [:id], :unsigned => false
|
100
|
+
integer :simple_id, :null => false, :key => [:id], :unsigned => false
|
100
101
|
primary_key [:user_id, :simple_id], :null => false, :unsigned => false
|
101
102
|
index [:simple_id, :user_id], :null => false, :unique => true
|
102
|
-
foreign_key [:user_id], :users, :null => false, :key => [:id], :unsigned => false
|
103
|
-
foreign_key [:simple_id], :simple, :null => false, :key => [:id], :unsigned => false
|
103
|
+
foreign_key [:user_id], :users, :null => false, :key => [:id], :unsigned => false
|
104
|
+
foreign_key [:simple_id], :simple, :null => false, :key => [:id], :unsigned => false
|
104
105
|
end
|
105
106
|
table :self_join do
|
106
|
-
integer :left_id, :null => false, :key => [:id], :unsigned => false
|
107
|
-
integer :right_id, :null => false, :key => [:id], :unsigned => false
|
107
|
+
integer :left_id, :null => false, :key => [:id], :unsigned => false
|
108
|
+
integer :right_id, :null => false, :key => [:id], :unsigned => false
|
108
109
|
primary_key [:left_id, :right_id], :null => false, :unsigned => false
|
109
|
-
timestamp :create_time, :null => false, :default => "
|
110
|
-
timestamp :update_time, :null => false, :default => "
|
110
|
+
timestamp :create_time, :null => false, :default => "2000-01-01 00:00:00"
|
111
|
+
timestamp :update_time, :null => false, :default => "2000-01-01 00:00:00"
|
111
112
|
index [:right_id, :left_id], :null => false, :unique => true
|
112
113
|
index [:create_time], :null => false
|
113
|
-
foreign_key [:left_id], :users, :null => false, :key => [:id], :unsigned => false
|
114
|
-
foreign_key [:right_id], :users, :null => false, :key => [:id], :unsigned => false
|
114
|
+
foreign_key [:left_id], :users, :null => false, :key => [:id], :unsigned => false
|
115
|
+
foreign_key [:right_id], :users, :null => false, :key => [:id], :unsigned => false
|
115
116
|
end
|