Revision 0d33a925
Von Moritz Bunkus vor mehr als 10 Jahren hinzugefügt
scripts/rose_auto_create_model.pl | ||
---|---|---|
47 | 47 |
|
48 | 48 |
my %config; |
49 | 49 |
|
50 |
# Maps column names in tables to foreign key relationship names. For |
|
51 |
# example: |
|
52 |
# |
|
53 |
# »follow_up_access« contains a column named »who«. Rose normally |
|
54 |
# names the resulting relationship after the class the target table |
|
55 |
# uses. In this case the target table is »employee« and the |
|
56 |
# corresponding class SL::DB::Employee. The resulting relationship |
|
57 |
# would be named »employee«. |
|
58 |
# |
|
59 |
# In order to rename this relationship we have to map »who« to |
|
60 |
# e.g. »granted_by«: |
|
61 |
# follow_up_access => { who => 'granted_by' }, |
|
62 |
|
|
50 | 63 |
our %foreign_key_name_map = ( |
51 | 64 |
KIVITENDO => { |
52 |
oe => { payment => 'payment_terms', }, |
|
53 |
ar => { payment => 'payment_terms', }, |
|
54 |
ap => { payment => 'payment_terms', }, |
|
65 |
oe => { payment_id => 'payment_terms', },
|
|
66 |
ar => { payment_id => 'payment_terms', },
|
|
67 |
ap => { payment_id => 'payment_terms', },
|
|
55 | 68 |
|
56 |
orderitems => { parts => 'part', trans => 'order', },
|
|
57 |
delivery_order_items => { parts => 'part' }, |
|
58 |
invoice => { parts => 'part' }, |
|
59 |
follow_ups => { 'employee_obj' => 'created_for' },
|
|
69 |
orderitems => { parts_id => 'part', trans_id => 'order', },
|
|
70 |
delivery_order_items => { parts_id => 'part' },
|
|
71 |
invoice => { parts_id => 'part' },
|
|
72 |
follow_ups => { created_for_user => 'created_for', created_by => 'employee', },
|
|
60 | 73 |
|
61 |
periodic_invoices_configs => { oe => 'order' }, |
|
74 |
periodic_invoices_configs => { oe_id => 'order' },
|
|
62 | 75 |
}, |
63 | 76 |
); |
64 | 77 |
|
... | ... | |
89 | 102 |
} |
90 | 103 |
} |
91 | 104 |
|
105 |
sub fix_relationship_names { |
|
106 |
my ($domain, $table, $fkey_text) = @_; |
|
107 |
|
|
108 |
if ($fkey_text !~ m/key_columns \s+ => \s+ \{ \s+ ['"]? ( [^'"\s]+ ) /x) { |
|
109 |
die "fix_relationship_names: could not extract the key column for domain/table $domain/$table; foreign key definition text:\n${fkey_text}\n"; |
|
110 |
} |
|
111 |
|
|
112 |
my $column_name = $1; |
|
113 |
my %changes = map { %{$_} } grep { $_ } ($foreign_key_name_map{$domain}->{ALL}, $foreign_key_name_map{$domain}->{$table}); |
|
114 |
|
|
115 |
if (my $desired_name = $changes{$column_name}) { |
|
116 |
$fkey_text =~ s/^ \s\s [^\s]+ \b/ ${desired_name}/msx; |
|
117 |
} |
|
118 |
|
|
119 |
return $fkey_text; |
|
120 |
} |
|
121 |
|
|
92 | 122 |
sub process_table { |
93 | 123 |
my ($domain, $table, $package) = @_; |
94 | 124 |
my $schema = ''; |
... | ... | |
139 | 169 |
$foreign_key_definition =~ s/::AUTO::/::/g; |
140 | 170 |
|
141 | 171 |
if ($foreign_key_definition && ($definition =~ /\Q$foreign_key_definition\E/)) { |
172 |
# These positions refer to the whole setup call, not just the |
|
173 |
# parameters/actual relationship definitions. |
|
142 | 174 |
my ($start, $end) = ($-[0], $+[0]); |
143 | 175 |
|
144 |
my %changes = map { %{$_} } grep { $_ } ($foreign_key_name_map{$domain}->{ALL}, $foreign_key_name_map{$domain}->{$table}); |
|
145 |
while (my ($auto_generated_name, $desired_name) = each %changes) { |
|
146 |
$foreign_key_definition =~ s/^ \s \s ${auto_generated_name} \b/ ${desired_name}/msx; |
|
147 |
} |
|
176 |
# Match the function parameters = the actual relationship |
|
177 |
# definitions |
|
178 |
next unless $foreign_key_definition =~ m/\(\n(.+)\n\)/s; |
|
148 | 179 |
|
149 |
# Sort foreign key definitions alphabetically |
|
150 |
if ($foreign_key_definition =~ m/\(\n(.+)\n\)/s) { |
|
151 |
my ($list_start, $list_end) = ($-[0], $+[0]); |
|
152 |
my @foreign_keys = split m/\n\n/m, $1; |
|
153 |
my $sorted_foreign_keys = "(\n" . join("\n\n", sort @foreign_keys) . "\n)"; |
|
180 |
my ($list_start, $list_end) = ($-[0], $+[0]); |
|
154 | 181 |
|
155 |
substr $foreign_key_definition, $list_start, $list_end - $list_start, $sorted_foreign_keys;; |
|
156 |
} |
|
182 |
# Split the whole chunk on double new lines. The resulting |
|
183 |
# elements are one relationship each. Then fix the relationship |
|
184 |
# names and sort them by their new names. |
|
185 |
my @new_foreign_keys = sort map { fix_relationship_names($domain, $table, $_) } split m/\n\n/m, $1; |
|
186 |
|
|
187 |
# Replace the function parameters = the actual relationship |
|
188 |
# definitions with the new ones. |
|
189 |
my $sorted_foreign_keys = "(\n" . join("\n\n", @new_foreign_keys) . "\n)"; |
|
190 |
substr $foreign_key_definition, $list_start, $list_end - $list_start, $sorted_foreign_keys; |
|
157 | 191 |
|
158 |
substr($definition, $start, $end - $start) = $foreign_key_definition; |
|
192 |
# Replace the whole setup call in the auto-generated output with |
|
193 |
# our new version. |
|
194 |
substr $definition, $start, $end - $start, $foreign_key_definition; |
|
159 | 195 |
} |
160 | 196 |
|
161 | 197 |
$definition =~ s/(meta->table.*)\n/$1\n$schema_str/m if $schema; |
Auch abrufbar als: Unified diff
rose_auto_create_model.pl: Relationship-Namen anhand der Spaltennamen mappen
Bisher wurde das Umbenennen der generierten Relationships anhand des von
Rose vergebenen Namens der Relationship vorgenommen. Das ist
problematisch, weil diese wiederum von der Reihenfolge abhängen, in der
die Fremdschlüsseldefinitionen von der Datenbank zurückgeliefert werden.
Konkretes Beispiel: Tabelle »follow_up_access« mit den Spalten »who« und
»what«, die beide Fremdschlüssel auf employee sind.
Rose benennt die erzeugten Relationships nach dem Klassennamen
derjenigen Tabelle, auf die die Schlüssel verweisen. Tabelle »employee«
→ Klasse »SL::DB::Employee« → Default-Relationshipname »employee«.
Die erste von der Datenbank gemeldete Fremdschlüsseldefinition bekommt
nun den Namen »employee«. Die zweite sollte diesen ebenfalls bekommen,
aber da der schon vergeben ist, bekommt sie das Suffix »_obj«, ergo
»employee_obj«. Soweit, so gut. Ändert sich nun aber die Reihenfolge, so
werden die Namen genau umgekehrt herum vergeben.
Die Umbenennung anhand des Tripels <Domäne, Tabelle, Spaltennamen>
hingegen ist immer eindeutig.