@@ -3,44 +3,52 @@ defmodule Ecto.Migration.Auto do
3
3
alias Ecto.Migration.Index
4
4
alias Ecto.Migration.SystemTable
5
5
6
- def migrate ( repo , module ) do
7
- table_name = module . __schema__ ( :source )
6
+ def migrate ( repo , module , opts \\ [ ] ) do
7
+ { tag_field , tablename } = case opts do
8
+ [ ] ->
9
+ { :nothing , module . __schema__ ( :source ) }
10
+ [ for: mod ] ->
11
+ [ { field , _ , tablename } ] = get_associations ( mod )
12
+ { field , tablename }
13
+ end
8
14
# already stored fields of the model in the system table
9
- all_system_fields = get_existings_fields ( repo , table_name )
15
+ all_system_fields = get_existings_fields ( repo , tablename )
10
16
# already stored indexes of the model in the system table
11
- all_system_indexes = get_existings_indexes ( repo , table_name )
12
- if execute ( module , all_system_fields , all_system_indexes , repo ) do
13
- Ecto.Migrator . up ( repo , random , extend_module_name ( module , ".Migration" ) )
14
- end
17
+ all_system_indexes = get_existings_indexes ( repo , tablename )
18
+ # execute migration
19
+ if execute ( tablename |> to_string , module , all_system_fields , all_system_indexes , tag_field , repo , opts ) do
20
+ Ecto.Migrator . up ( repo , random , migration_module_name ( module , opts ) )
21
+ end
15
22
end
16
23
17
- defp execute ( module , all_system_fields , all_system_indexes , repo ) do
18
- metainfo = all_system_fields [ :metainfo ] |> transform_existing_keys ( )
24
+ defp execute ( tablename , module , all_system_fields , all_system_indexes , tag_field , repo , opts ) do
19
25
assocs = get_associations ( module )
26
+ metainfo = all_system_fields [ :metainfo ] |> transform_existing_keys ( )
20
27
all_fields = module . __schema__ ( :fields )
21
- add_fields = add_fields ( module , all_fields , metainfo , assocs )
28
+ add_fields = [ assoc_field ( tag_field , tablename , all_system_fields , opts ) | add_fields ( module , all_fields , metainfo , assocs ) ] |> :lists . flatten
22
29
remove_fields = remove_fields ( all_fields , metainfo )
23
30
all_indexes = Index . get_all ( module )
24
31
update_index = Index . updated? ( all_indexes , all_system_indexes )
25
32
all_changes = remove_fields ++ add_fields
26
- update_metainfo ( module , all_fields , assocs , repo )
27
- do_execute ( module , all_changes , metainfo , update_index , all_indexes , all_system_indexes , repo )
33
+ update_metainfo ( module , tablename , all_fields , assocs , repo )
34
+ update_index_info ( tablename , module , repo )
35
+ index_info = { update_index , all_indexes , all_system_indexes }
36
+ do_execute ( repo , tablename , module , all_changes , metainfo , index_info , opts )
28
37
end
29
38
30
- defp do_execute ( _module , [ ] , _fields_in_db , false , _ , _ , _repo ) , do: nil
31
-
32
- defp do_execute ( module , all_changes , fields_in_db , update_index , all_indexes , all_system_indexes , repo ) do
33
- table_name = table_name ( module )
34
- module_name = extend_module_name ( module , ".Migration" )
35
- updsl = gen_up_dsl ( repo , module , table_name , all_changes , fields_in_db , all_indexes , all_system_indexes , update_index )
39
+ defp do_execute ( _repo , _ , _module , [ ] , _fields_in_db , { false , _ , _ } , _ ) , do: nil
40
+ defp do_execute ( repo , tablename , module , all_changes , fields_in_db , index_info , opts ) do
41
+ { update_index , all_indexes , all_system_indexes } = index_info
42
+ updsl = gen_up_dsl ( repo , module , tablename |> String . to_atom , all_changes , fields_in_db , all_indexes , all_system_indexes , update_index )
43
+ migration_module_name = migration_module_name ( module , opts )
36
44
res = quote do
37
- defmodule unquote ( module_name ) do
45
+ defmodule unquote ( migration_module_name ) do
38
46
use Ecto.Migration
39
47
def up do
40
48
unquote ( updsl )
41
49
end
42
50
def down do
43
- drop table ( unquote table_name )
51
+ drop table ( unquote tablename )
44
52
end
45
53
end
46
54
end
@@ -49,22 +57,22 @@ defmodule Ecto.Migration.Auto do
49
57
end
50
58
51
59
# create new table
52
- defp gen_up_dsl ( _repo , module , table_name , all_changes , [ ] , all_indexes , _ , update_index ) do
60
+ defp gen_up_dsl ( _repo , module , tablename , all_changes , [ ] , all_indexes , _ , update_index ) do
53
61
key? = module . __schema__ ( :primary_key ) == [ :id ]
54
- index_creation = Index . create ( module , all_indexes , update_index )
62
+ index_creation = Index . create ( tablename , all_indexes , update_index )
55
63
quote do
56
- create table ( unquote ( table_name ) , primary_key: unquote ( key? ) ) do
64
+ create table ( unquote ( tablename ) , primary_key: unquote ( key? ) ) do
57
65
unquote ( all_changes )
58
66
end
59
67
unquote ( index_creation )
60
68
end
61
69
end
62
70
63
71
# updated or table or index or both
64
- defp gen_up_dsl ( repo , module , table_name , all_changes , _ , all_indexes , all_system_indexes , update_index ) do
65
- index_deletion = Index . delete ( update_index , table_name |> Atom . to_string , module , repo , all_system_indexes )
66
- index_creation = Index . create ( module , all_indexes , update_index )
67
- alter = alter_table ( all_changes , table_name )
72
+ defp gen_up_dsl ( repo , module , tablename , all_changes , _ , all_indexes , all_system_indexes , update_index ) do
73
+ index_deletion = Index . delete ( update_index , tablename |> Atom . to_string , module , repo , all_system_indexes )
74
+ index_creation = Index . create ( tablename , all_indexes , update_index )
75
+ alter = alter_table ( all_changes , tablename )
68
76
quote do
69
77
unquote ( alter )
70
78
unquote ( index_deletion )
@@ -81,25 +89,26 @@ defmodule Ecto.Migration.Auto do
81
89
end
82
90
end
83
91
84
- defp update_metainfo ( module , all_fields , assocs , repo ) do
85
- table_name = module . __schema__ ( :source )
92
+ defp update_metainfo ( module , tablename , all_fields , assocs , repo ) do
86
93
metainfo = system_table_meta ( module , all_fields , assocs )
87
- case repo . get ( SystemTable , table_name ) do
94
+ case repo . get ( SystemTable , tablename ) do
88
95
nil ->
89
- repo . insert ( % SystemTable { tablename: table_name , metainfo: metainfo } )
90
- table ->
96
+ repo . insert ( % SystemTable { tablename: tablename , metainfo: metainfo } )
97
+ table ->
91
98
repo . update ( % SystemTable { table | metainfo: metainfo } )
92
99
end
100
+ end
93
101
94
- query = from s in SystemTable.Index , where: s . tablename == ^ table_name , select: s
95
- # insert index info if need
102
+ defp update_index_info ( tablename , module , repo ) do
103
+ query = from s in SystemTable.Index , where: s . tablename == ^ tablename , select: s
104
+ # insert index info into system table, if need
96
105
case repo . all ( query ) do
97
106
[ ] ->
98
- # we have no anything with 'table_name ' record in the SystemTable.Index
107
+ # we have no anything with 'tablename ' record in the SystemTable.Index
99
108
# table, let's insert records about it
100
109
all_indexes = Index . get_all ( module )
101
110
for { fields , opts } <- all_indexes do
102
- repo . insert ( Map . merge ( % SystemTable.Index { tablename: table_name , index: Enum . join ( fields , "," ) } , :maps . from_list ( opts ) ) )
111
+ repo . insert ( Map . merge ( % SystemTable.Index { tablename: tablename , index: Enum . join ( fields , "," ) } , :maps . from_list ( opts ) ) )
103
112
end
104
113
_ ->
105
114
# we can't update index information here, because table is not empty and
@@ -108,19 +117,19 @@ defmodule Ecto.Migration.Auto do
108
117
end
109
118
end
110
119
111
- def get_existings_indexes ( repo , table_name ) do
120
+ def get_existings_indexes ( repo , tablename ) do
112
121
try do
113
- repo . all ( from s in SystemTable.Index , where: ^ table_name == s . tablename )
122
+ repo . all ( from s in SystemTable.Index , where: ^ tablename == s . tablename )
114
123
catch
115
124
_x , _y ->
116
125
Ecto.Migrator . up ( repo , random , SystemTable.Index.Migration ) # we have no system table - 'ecto_migration_auto_index', let's create it
117
126
nil
118
127
end
119
128
end
120
129
121
- def get_existings_fields ( repo , table_name ) do
130
+ def get_existings_fields ( repo , tablename ) do
122
131
try do
123
- repo . get ( SystemTable , table_name )
132
+ repo . get ( SystemTable , tablename )
124
133
catch
125
134
_x , _y ->
126
135
Ecto.Migrator . up ( repo , random , SystemTable.Migration ) # we have no system table - 'ecto_migration_auto', let's create it
@@ -132,7 +141,9 @@ defmodule Ecto.Migration.Auto do
132
141
module . __schema__ ( :associations ) |> Enum . flat_map ( fn ( association ) ->
133
142
case module . __schema__ ( :association , association ) do
134
143
% Ecto.Association.BelongsTo { owner_key: field , assoc: assoc_module } ->
135
- [ { field , table_name ( assoc_module ) , assoc_module } ]
144
+ [ { field , assoc_module . __schema__ ( :source ) |> String . to_atom , assoc_module } ]
145
+ % Ecto.Association.Has { field: field , assoc: assoc , queryable: { tablename , _ } } ->
146
+ [ { field , assoc , tablename } ]
136
147
_ ->
137
148
[ ]
138
149
end
@@ -203,11 +214,11 @@ defmodule Ecto.Migration.Auto do
203
214
204
215
defp random , do: :crypto . rand_uniform ( 0 , 1099511627775 )
205
216
206
- defp extend_module_name ( module , str ) do
207
- ( ( module |> to_string ) <> str ) |> String . to_atom
208
- end
217
+ defp assoc_field ( _ , _ , system_fields , _ )
218
+ when system_fields != nil , do: [ ]
219
+ defp assoc_field ( _ , _ , _ , [ ] ) , do: [ ]
220
+ defp assoc_field ( tag_field , tablename , _ , _opts ) , do: quote do: ( add unquote ( tag_field ) , references ( unquote ( tablename ) |> String . to_atom ) )
209
221
210
- defp table_name ( module ) do
211
- module . __schema__ ( :source ) |> String . to_atom
212
- end
222
+ defp migration_module_name ( module , [ ] ) , do: ( ( module |> Atom . to_string ) <> ".Migration" ) |> String . to_atom
223
+ defp migration_module_name ( module , [ for: mod ] ) , do: ( ( module |> Atom . to_string ) <> "." <> ( mod |> Atom . to_string ) <> ".Migration" ) |> String . to_atom
213
224
end
0 commit comments