1Rose::DB::Object::ConveUnsteironCMoanntargiebru(t3e)d PeRrolseD:o:cDuBm:e:nOtbajteicotn::ConventionManager(3)
2
3
4
6 Rose::DB::Object::ConventionManager - Provide missing metadata by
7 convention.
8
10 package My::Product;
11
12 use base 'Rose::DB::Object';
13
14 __PACKAGE__->meta->setup(columns => [ ... ]);
15
16 # No table is set above, but look at this: the
17 # convention manager provided one for us.
18 print __PACKAGE__->meta->table; # "products"
19
20 ##
21 ## See the EXAMPLE section below for a more complete demonstration.
22 ##
23
25 Each Rose::DB::Object-derived object has a convention manager that it
26 uses to fill in missing metadata. The convention manager encapsulates
27 a set of rules (conventions) for generating various pieces of metadata
28 in the absence of explicitly specified values: table names, column
29 names, etc.
30
31 Each Rose::DB::Object-derived class's convention manager object is
32 stored in the convention_manager attribute of its
33 Rose::DB::Object::Metadata (meta) object.
34 Rose::DB::Object::ConventionManager is the default convention manager
35 class.
36
37 The object method documentation below describes both the purpose of
38 each convention manager method and the particular rules that
39 Rose::DB::Object::ConventionManager follows to fulfill that purpose.
40 Subclasses must honor the purpose of each method, but are free to use
41 any rules they choose.
42
43 Note well: When reading the descriptions of the rules used by each
44 convention manager method below, remember that only values that are
45 missing will be set by the convention manager. Explicitly providing a
46 value for a piece of metadata obviates the need for the convention
47 manager to generate one.
48
49 If insufficient information is available, or if the convention manager
50 simply declines to fulfill a request, undef may be returned from any
51 metadata-generating method.
52
53 In the documentation, the adjectives "local" and "foreign" are used to
54 distinguish between the things that belong to the convention manager's
55 class and the class on "the other side" of the inter-table
56 relationship, respectively.
57
59 Although the object method documentation below includes all the
60 information required to understand the default conventions, it's also
61 quite spread out. What follows is a summary of the default
62 conventions. Some details have necessarily been omitted or simplified
63 for the sake of brevity, but this summary should give you a good
64 starting point for further exploration.
65
66 Here's a brief summary of the default conventions as implemented in
67 Rose::DB::Object::ConventionManager.
68
69 Table, column, foreign key, and relationship names are lowercase, with
70 underscores separating words.
71 Examples: "products", "street_address", "date_created",
72 "vendor_id".
73
74 Table names are plural.
75 Examples: "products", "vendors", "codes", "customer_details",
76 "employee_addresses".
77
78 (This convention can be overridden via the tables_are_singular
79 method.)
80
81 Class names are singular, title-cased, with nothing separating words.
82 Examples: "Product", "Vendor", "Code", "CustomerDetail",
83 "EmployeeAddress".
84
85 Primary key column names do not contain the table name.
86 For example, the primary key column name in the "products" table
87 might be "id" or "sku", but should not be "product_id" or
88 "product_sku".
89
90 Foreign key column names are made from the singular version of the
91 foreign table's name joined (with an underscore) to the foreign table's
92 key column name.
93 Examples: "product_sku", "vendor_id", "employee_address_id".
94
95 One-to-one and many-to-one relationship names are singular.
96 Examples: "product", "vendor", "code". These relationships may
97 point to zero or one foreign object. The default method names
98 generated from such relationships are based on the relationship
99 names, so singular names make the most sense.
100
101 One-to-many and many-to-many relationship names are plural.
102 Examples: "colors", "prices", "customer_details". These
103 relationships may point to more than one foreign object. The
104 default method names generated from such relationships are based on
105 the relationship names, so plural names make the most sense.
106
107 Mapping tables and their associated classes that participate in many-
108 to-many relationships are named according a formula that combines the
109 names of the two classes/tables that are being linked.
110 See the auto_relationship, looks_like_map_class, and
111 looks_like_map_table documentation for all the details.
112
114 new PARAMS
115 Constructs a new object based on PARAMS, where PARAMS are
116 name/value pairs. Any object attribute is a valid parameter name.
117
119 auto_column_method_name TYPE, COLUMN, NAME, OBJECT_CLASS
120 Given a Rose::DB::Object::Metadata::Column column type, a
121 Rose::DB::Object::Metadata::Column object or column name, a default
122 method name, and a Rose::DB::Object-derived class name, return an
123 appropriate method name. The default implementation simply returns
124 undef, relying on the hard-coded default method-type-to-name
125 mapping implemented in Rose::DB::Object::Metadata's
126 method_name_from_column method.
127
128 auto_foreign_key NAME [, SPEC]
129 Given a foreign key name and an optional reference to a hash SPEC
130 of the type passed to Rose::DB::Object::Metadata's add_foreign_keys
131 method, return an appropriately constructed
132 Rose::DB::Object::Metadata::ForeignKey object.
133
134 The foreign key's class name is generated by calling
135 related_table_to_class, passing NAME and the convention manager's
136 class as arguments. An attempt is made is load the class. If this
137 fails, the foreign key's class name is not set.
138
139 The foreign key's key_columns are only set if both the "local" and
140 "foreign" tables have single-column primary keys. The foreign
141 class's primary key column name is used as the foreign column in
142 the key_columns map. If there is a local column with the same
143 name as the foreign key name, and if that column is aliased (making
144 way for the foreign key method to use that name), then that is used
145 as the local column. If not, then the local column name is
146 generated by joining the foreign key name and the foreign class's
147 primary key column name with an underscore. If no column by that
148 name exists, then the search is abandoned. Example:
149
150 Given these pieces:
151
152 Name Description Value
153 --------- -------------------------------- -------
154 NAME Foreign key name vendor
155 FCLASS Foreign class My::Vendor
156 FPK Foreign primary key column name id
157
158 Consider column maps in this order:
159
160 Value Formula
161 --------------------- ----------------------
162 { vendor => 'id' } { NAME => FPK }
163 { vendor_id => 'id' } { <NAME>_<FPK> => FPK }
164
165 auto_foreign_key_name FOREIGN_CLASS, CURRENT_NAME, KEY_COLUMNS,
166 USED_NAMES
167 Given the name of a foreign class, the current foreign key name (if
168 any), a reference to a hash of key columns, and a reference to a
169 hash whose keys are foreign key names already used in this class,
170 return a name for the foreign key.
171
172 If there is more than one pair of columns in KEY_COLUMNS, then the
173 name is generated by calling plural_to_singular, passing the table
174 name of the foreign class. The CURRENT_NAME is used if the call to
175 plural_to_singular does not return a true value.
176
177 If there is just one pair of columns in KEY_COLUMNS, and if the
178 name of the local column ends with an underscore and the name of
179 the referenced column, then that part of the column name is removed
180 and the remaining string is used as the foreign key name. For
181 example, given the following tables:
182
183 CREATE TABLE categories
184 (
185 id SERIAL PRIMARY KEY,
186 ...
187 );
188
189 CREATE TABLE products
190 (
191 category_id INT REFERENCES categories (id),
192 ...
193 );
194
195 The foreign key name would be "category", which is the name of the
196 referring column ("category_id") with an underscore and the name of
197 the referenced column ("_id") removed from the end of it.
198
199 If the foreign key has only one column, but it does not meet the
200 criteria described above, then the name is generated by calling
201 plural_to_singular, passing the table name of the foreign class.
202 The CURRENT_NAME is used if the call to plural_to_singular does not
203 return a true value.
204
205 If the name selected using the above techniques is in the
206 USED_NAMES hash, or is the same as that of an existing or potential
207 method in the target class, then the suffixes "_obj" and "_object"
208 are tried in that order. If neither of those suffixes resolves the
209 situation, then ascending numeric suffixes starting with "1" are
210 tried until a unique name is found.
211
212 auto_manager_base_name TABLE, CLASS
213 Given a table name and the name of the Rose::DB::Object-derived
214 class that fronts it, return a base name suitable for use as the
215 value of the "base_name" parameter to Rose::DB::Object::Manager's
216 make_manager_methods method.
217
218 If no table is specified then the table name is derived from the
219 current class name by calling class_to_table_plural.
220
221 If tables_are_singular is true, then TABLE is passed to the
222 singular_to_plural method and the result is returned. Otherwise,
223 TABLE is returned as-is.
224
225 auto_manager_base_class
226 Return the class that all manager classes will default to
227 inheriting from. By default this will be
228 Rose::DB::Object::Manager.
229
230 auto_manager_class_name CLASS
231 Given the name of a Rose::DB::Object-derived class, returns a class
232 name for a Rose::DB::Object::Manager-derived class to manage such
233 objects. The default implementation simply appends "::Manager" to
234 the Rose::DB::Object-derived class name.
235
236 auto_manager_method_name TYPE, BASE_NAME, OBJECT_CLASS
237 Given the specified Rose::DB::Object::Manager method type, base
238 name, and object class return an appropriate manager method name.
239 The default implementation simply returns undef, relying on the
240 hard-coded default method-type-to-name mapping implemented in
241 Rose::DB::Object::Manager's make_manager_methods method.
242
243 auto_relationship_name_many_to_many FK, MAPCLASS
244 Return the name of a "many to many" relationship that fetches
245 objects from the table pointed to by the
246 Rose::DB::Object::Metadata::ForeignKey object FK by going through
247 the class MAPCLASS.
248
249 The default implementation passes the name of the table pointed to
250 by FK through the singular_to_plural method in order to build the
251 name.
252
253 If the selected name is the name of an existing or potential method
254 in the target class, then the suffixes "_objs" and "_objects" are
255 tried in that order. If neither of those suffixes resolves the
256 situation, then ascending numeric suffixes starting with "1" are
257 tried until a unique name is found.
258
259 auto_relationship_name_one_to_many TABLE, CLASS
260 Return the name of a "one to many" relationship that fetches
261 objects from the specified TABLE and CLASS.
262
263 If tables_are_singular is true, then TABLE is passed to the
264 singular_to_plural method and the result is used as the name.
265 Otherwise, TABLE is used as-is.
266
267 If the selected name is the name of an existing or potential method
268 in the target class, then the suffixes "_objs" and "_objects" are
269 tried in that order. If neither of those suffixes resolves the
270 situation, then ascending numeric suffixes starting with "1" are
271 tried until a unique name is found.
272
273 auto_relationship_name_one_to_one TABLE, CLASS
274 Return the name of a "one to one" relationship that fetches an
275 object from the specified TABLE and CLASS. The default
276 implementation returns a singular version of the table name.
277
278 If the selected name is the name of an existing or potential method
279 in the target class, then the suffixes "obj_" and "_object" are
280 tried in that order. If neither of those suffixes resolves the
281 situation, then ascending numeric suffixes starting with "1" are
282 tried until a unique name is found.
283
284 auto_primary_key_column_names
285 Returns a reference to an array of primary key column names.
286
287 If a column named "id" exists, it is selected as the sole primary
288 key column name. If not, the column name generated by joining the
289 return value of class_to_table_singular with "_id" is considered.
290 If no column with that name exists, then the first column (sorted
291 alphabetically) whose type is "serial" is selected. If all of the
292 above fails, then the first column is selected as the primary key
293 column (assuming one exists).
294
295 Examples:
296
297 My::A->meta->columns(qw(a a_id id));
298 print My::A->meta->primary_key_columns; # "id"
299
300 My::B->meta->columns(qw(b b_id foo));
301 print My::B->meta->primary_key_columns; # "a_id"
302
303 My::D->meta->columns
304 (
305 cnt => { type => 'int' },
306 dub => { type => 'serial' },
307 foo => { type => 'serial'},
308 a_id => { type => 'int' }
309 )
310
311 print My::D->meta->primary_key_columns; # "dub"
312
313 My::C->meta->columns(qw(foo bar baz));
314 print My::C->meta->primary_key_columns; # "foo"
315
316 auto_relationship NAME, RELATIONSHIP_CLASS [, SPEC]
317 Given a relationship name, a
318 Rose::DB::Object::Metadata::Relationship-derived class name, and an
319 optional reference to a hash SPEC of the type passed to
320 Rose::DB::Object::Metadata's add_relationships method, return an
321 appropriately constructed
322 Rose::DB::Object::Metadata::Relationship-derived object.
323
324 If the relationship's type is "one to one" or "many to one", then
325 the relationship's class name is generated by calling
326 related_table_to_class, passing NAME and the convention manager's
327 class as arguments. An attempt is made is load the class. If this
328 fails, the relationship's class name is not set.
329
330 The column map for "one to one" and "many to one" relationships is
331 generated using the same rules used to generate key_columns in the
332 auto_foreign_key method.
333
334 If the relationship's type is "one to many" then the relationship's
335 class name is generated by calling plural_to_singular on NAME, then
336 passing that value along with the convention manager's class to the
337 related_table_to_class method. An attempt is made is load the
338 class. If this fails, the relationship's class name is not set.
339
340 The column map for a "one to many" relationship is only set if both
341 the "local" and "foreign" tables have single-column primary keys.
342 The following ordered list of combinations is considered.
343
344 Given:
345
346 Local class: My::Product
347 Foreign class: My::Price
348 Relationship: prices
349
350 Generate these pieces:
351
352 Name Description Value
353 --------- --------------------------------- -------
354 LTABLE_S Local class_to_table_singular() product
355 LPK Local primary key column name id
356 FPK Foreign primary key column name id
357
358 Consider column maps in this order:
359
360 Value Formula
361 ---------------------- --------------------------
362 { id => 'product' } { LPK => LTABLE_S }
363 { id => 'product_id' } { LPK => <LTABLE_S>_<PK> }
364
365 The first value whose foreign column actually exists in the foreign
366 table is chosen.
367
368 If the relationship's type is "many to many" then the
369 relationship's map_class is chosen from a list of possibilities.
370 This list is generated by constructing singular and plural versions
371 of the local and foreign class names (sans prefixes) and then
372 joining them in various ways, all re-prefixed by the class prefix
373 of the convention manager's class. Example:
374
375 Given:
376
377 Local class: My::Product
378 Foreign class: My::Color
379 Relationship: colors
380
381 Generate these pieces:
382
383 Name Description Value
384 --------- --------------------------------- -------
385 PREFIX Local class prefix My::
386 LCLASS_S Unprefixed local class, singular Product
387 LCLASS_P Unprefixed local class, plural Products
388 FCLASS_S Unprefixed foreign class, singular Color
389 FCLASS_P Unprefixed foreign class, plural Colors
390
391 Consider map class names in this order:
392
393 Value Formula
394 --------------- ---------------------
395 My::ProductsColorsMap <PREFIX><LCLASS_P><FCLASS_P>Map
396 My::ProductColorMap <PREFIX><LCLASS_S><FCLASS_S>Map
397 My::ColorsProductsMap <PREFIX><FCLASS_P><LCLASS_P>Map
398 My::ColorProductMap <PREFIX><FCLASS_S><LCLASS_S>Map
399 My::ProductsColors <PREFIX><LCLASS_P><FCLASS_P>
400 My::ProductColors <PREFIX><LCLASS_S><FCLASS_P>
401 My::ColorsProducts <PREFIX><FCLASS_P><LCLASS_P>
402 My::ColorProducts <PREFIX><FCLASS_S><LCLASS_P>
403 My::ColorMap <PREFIX><FCLASS_S>Map
404 My::ColorsMap <PREFIX><FCLASS_P>Map
405 My::ProductMap <PREFIX><LCLASS_S>Map
406 My::ProductsMap <PREFIX><LCLASS_P>Map
407
408 The first class found that inherits from Rose::DB::Object and is
409 loaded successfully will be chosen as the relationship's map_class.
410
411 auto_table_name
412 Returns a table name for the convention manager's class.
413
414 Class names are singular and table names are plural. To build the
415 table name, the class prefix is removed from the class name,
416 transitions from lowercase letters or digits to uppercase letters
417 have underscores inserted, and the whole thing is converted to
418 lowercase.
419
420 Examples:
421
422 Class Table
423 ----------- --------
424 Product products
425 My::Product products
426 My::BigBox big_boxes
427 My5HatPig my5_hat_pig
428
429 class [CLASS]
430 Get or set the Rose::DB::Object-derived class that this convention
431 manager belongs to.
432
433 class_prefix CLASS
434 Given a class name, return the prefix, if any, before the last
435 component of the namespace, including the final "::". If there is
436 no prefix, an empty string is returned.
437
438 Examples:
439
440 Class Prefix
441 ----------- --------------
442 Product <empty string>
443 My::Product My::
444 A::B::C::D A::B::C::
445
446 class_to_table_plural [CLASS]
447 Given a class name, or the convention manager's class if omitted,
448 return a plural version of the corresponding table name.
449
450 To do this, the output of the class_to_table_singular method is
451 passed to a call to the singular_to_plural method. (The CLASS
452 argument, if any, is passed to the call to
453 class_to_table_singular.)
454
455 Examples:
456
457 Class Table
458 ----------- --------
459 Product products
460 My::Product products
461 My::Box boxes
462
463 class_to_table_singular [CLASS]
464 Given a class name, or the convention manager's class if omitted,
465 return a singular version of the corresponding table name.
466
467 Examples:
468
469 Class Table
470 ----------- --------
471 Product product
472 My::Product product
473 My::Box box
474
475 force_lowercase [BOOL]
476 Get or set a boolean value that indicates whether or not metadata
477 entity names should be forced to lowercase even when the related
478 entity is uppercase or mixed case. ("Metadata entities" are thing
479 like columns, relationships, and foreign keys.) The default value
480 is false.
481
482 is_map_class CLASS
483 Returns true if CLASS is a map class used as part of a many to many
484 relationship, false if it does not.
485
486 The default implementations returns true if CLASS is derived from
487 Rose::DB::Object and its table name looks like a map table name
488 according to the looks_like_map_table method and the
489 looks_like_map_class method returns either true or undef.
490
491 Override this method to control which classes are considered map
492 classes. Note that it may be called several times on the same
493 class at various stages of that class's construction.
494
495 looks_like_map_class CLASS
496 Given the class name CLASS, returns true if it looks like the name
497 of a map class used as part of a many to many relationship, false
498 (but defined) if it does not, and undef if it's unsure.
499
500 The default implementation returns true if CLASS is derived from
501 Rose::DB::Object and has exactly two foreign keys. It returns
502 false (but defined) if CLASS is derived from Rose::DB::Object and
503 has been initialized (or if the foreign keys have been auto-
504 initialized) and the CLASS has no deferred foreign keys. It
505 returns undef otherwise.
506
507 looks_like_map_table TABLE
508 Returns true if TABLE looks like the name of a mapping table used
509 as part of a many to many relationship, false (but defined) if it
510 does not, and undef if it's unsure.
511
512 The default implementation returns true if TABLE is in one of these
513 forms:
514
515 Regex Examples
516 ----------------------- -----------------------------
517 (\w+_){2,}map pig_toe_map, pig_skin_toe_map
518 (\w+_)*\w+_(\w+_)*\w+s pig_toes, pig_skin_toe_jams
519 (\w+_)*\w+s_(\w+_)*\w+s pigs_toes, pig_skins_toe_jams
520
521 It returns false otherwise.
522
523 meta [META]
524 Get or set the Rose::DB::Object::Metadata object associated with
525 the class that this convention manager belongs to.
526
527 plural_to_singular STRING
528 Returns the singular version of STRING. If a
529 plural_to_singular_function is defined, then this method simply
530 passes STRING to that function.
531
532 Otherwise, the following rules are applied, case-insensitively.
533
534 * If STRING ends in "ies", then the "ies" is replaced with "y".
535
536 * If STRING ends in "ses" then the "ses" is replaced with "s".
537
538 * If STRING matches "/[aeiouy]ss$/i", it is returned unmodified.
539
540 For all other cases, the letter "s" is removed from the end of
541 STRING and the result is returned.
542
543 plural_to_singular_function [CODEREF]
544 Get or set a reference to the function used to convert strings to
545 singular. The function should take a single string as an argument
546 and return a singular version of the string. This function is
547 undefined by default.
548
549 related_table_to_class TABLE, LOCAL_CLASS
550 Given a table name and a local class name, return the name of the
551 related class that fronts the table.
552
553 To do this, table_to_class is called with TABLE and the
554 class_prefix of LOCAL_CLASS passed as arguments.
555
556 Examples:
557
558 Table Local Class Related Class
559 ----------- ------------ ----------------
560 prices My::Product My::Price
561 big_hats A::B::FooBar A::B::BigHat
562 a1_steaks Meat A1Steak
563
564 singular_to_plural STRING
565 Returns the plural version of STRING. If a
566 singular_to_plural_function is defined, then this method simply
567 passes STRING to that function. Otherwise, the following rules are
568 applied, case-insensitively, to form the plural.
569
570 * If STRING ends in "x", "ss", or "es", then "es" is appended.
571
572 * If STRING ends in "y" then the "y" is replaced with "ies".
573
574 * If STRING ends in "s" then it is returned as-is.
575
576 * Otherwise, "s" is appended.
577
578 singular_to_plural_function [CODEREF]
579 Get or set a reference to the function used to convert strings to
580 plural. The function should take a single string as an argument
581 and return a plural version of the string. This function is
582 undefined by default.
583
584 table_singular
585 Let TABLE be the return value of the table method called on the
586 meta attribute of this object.
587
588 If tables_are_singular is true, then TABLE is returned as-is.
589 Otherwise, TABLE is passed to the plural_to_singular method and the
590 result is returned. Otherwise, TABLE is returned as-is.
591
592 table_plural
593 Let TABLE be the return value of the table method called on the
594 meta attribute of this object.
595
596 If tables_are_singular is true, then TABLE is passed to the
597 singular_to_plural method and the result is returned. Otherwise,
598 TABLE is returned as-is.
599
600 table_to_class TABLE [, PREFIX]
601 Given a table name and an optional class prefix, return the
602 corresponding class name. The prefix will be appended to the class
603 name, if present. The prefix should end in "::".
604
605 To do this, any letter that follows an underscore ("_") in the
606 table name is replaced with an uppercase version of itself, and the
607 underscore is removed.
608
609 Examples:
610
611 Table Prefix Class
612 ----------- ------ -----------
613 products My:: My::Product
614 products <none> Product
615 big_hats My:: My::BigHat
616 my5_hat_pig <none> My5HatPig
617
618 tables_are_singular [BOOL]
619 Get or set a boolean value that indicates whether or not table
620 names are expected to be singular. The default value is false,
621 meaning that table names are expected to be plural.
622
624 These methods are not part of the public interface, but are supported
625 for use by subclasses. Put another way, given an unknown object that
626 "isa" Rose::DB::Object::Metadata::ConventionManager, there should be no
627 expectation that the following methods exist. But subclasses, which
628 know the exact class from which they inherit, are free to use these
629 methods in order to implement the public API described above.
630
631 init_plural_to_singular_function
632 Override this method and return a reference to a function that
633 takes a single string as an argument and returns a singular version
634 of that string.
635
636 init_singular_to_plural_function
637 Override this method and return a reference to a function that
638 takes a single string as an argument and returns a plural version
639 of that string.
640
642 Much of the richness of a convention manager relies upon the quality of
643 the singular_to_plural and plural_to_singular methods. The default
644 implementations are primitive at best. For example,
645 singular_to_plural will not correctly form the plural of the word
646 "alumnus".
647
648 One easy way to improve this is by setting a custom
649 singular_to_plural_function. Here's an example using the handy
650 Lingua::EN::Inflect module:
651
652 package My::Product;
653 ...
654 use Lingua::EN::Inflect;
655 $cm = __PACKAGE__->meta->convention_manager;
656
657 $cm->singular_to_plural_function(\&Lingua::EN::Inflect::PL);
658
659 print $cm->singular_to_plural('person'); # "people"
660
661 But that's a bit of a pain to do in every single class. An easier way
662 to do it for all of your classes is to make a new
663 Rose::DB::Object::Metadata subclass that overrides the
664 init_convention_manager method, then make a Rose::DB::Object-derived
665 base class that uses your new metadata class. Example:
666
667 package My::DB::Metadata;
668
669 use Rose::DB::Object::Metadata;
670 our @ISA = qw(Rose::DB::Object::Metadata);
671
672 use Lingua::EN::Inflect;
673
674 sub init_convention_manager
675 {
676 my $self = shift;
677
678 # Let the base class make ths convention manager object
679 my $cm = $self->SUPER::init_convention_manager(@_);
680
681 # Set the new singular-to-plural function
682 $cm->singular_to_plural_function(\&Lingua::EN::Inflect::PL);
683
684 # Return the modified convention manager
685 return $cm;
686 }
687
688 ...
689
690 package My::DB::Object;
691
692 use My::DB::Metadata;
693
694 use Rose::DB::Object;
695 our @ISA = qw(Rose::DB::Object);
696
697 sub meta_class { 'My::DB::Metadata' }
698
699 ...
700
701 package My::Person;
702
703 use My::DB::Object;
704 our @ISA = qw(My::DB::Object);
705
706 # The big pay-off: smart plurals!
707 print __PACKAGE__->meta->table; # "people"
708
709 You might wonder why I don't use Lingua::EN::Inflect in
710 Rose::DB::Object::ConventionManager to save you this effort. The
711 answer is that the Lingua::EN::Inflect module adds almost a megabyte of
712 memory overhead on my system. I'd rather not incur that overhead just
713 for the sake of being more clever about naming conventions.
714 Furthermore, as primitive as the default plural-forming is, at least
715 it's deterministic. Guessing what Lingua::EN::Inflect will return is
716 not always easy, and the results can change depending on which version
717 Lingua::EN::Inflect you have installed.
718
720 Here's a complete example of nearly all of the major features of
721 Rose::DB::Object::ConventionManager. Let's start with the database
722 schema. (This example uses PostgreSQL, but any supported database with
723 native foreign key support will work.)
724
725 CREATE TABLE vendors
726 (
727 id SERIAL NOT NULL PRIMARY KEY,
728 name VARCHAR(255)
729 );
730
731 CREATE TABLE colors
732 (
733 code CHAR(3) NOT NULL PRIMARY KEY,
734 name VARCHAR(255)
735 );
736
737 CREATE TABLE products
738 (
739 id SERIAL NOT NULL PRIMARY KEY,
740 name VARCHAR(255),
741 vendor_id INT NOT NULL REFERENCES vendors (id)
742 );
743
744 CREATE TABLE prices
745 (
746 price_id SERIAL NOT NULL PRIMARY KEY,
747 product_id INT NOT NULL REFERENCES products (id),
748 region CHAR(2) NOT NULL DEFAULT 'US',
749 price DECIMAL(10,2) NOT NULL
750 );
751
752 CREATE TABLE product_colors
753 (
754 id SERIAL NOT NULL PRIMARY KEY,
755 product_id INT NOT NULL REFERENCES products (id),
756 color_code CHAR(3) NOT NULL REFERENCES colors (code)
757 );
758
759 Now the classes:
760
761 # Rose::DB subclass to handle the db connection
762 package My::DB;
763
764 use base 'Rose::DB';
765
766 My::DB->register_db
767 (
768 type => 'default',
769 domain => 'default',
770 driver => 'Pg',
771 database => 'test',
772 username => 'postgres',
773 );
774
775 ...
776
777 # Common Rose::DB::Object-derived base class for the other objects
778 package My::Object;
779
780 use My::DB;
781
782 use base 'Rose::DB::Object';
783
784 sub init_db { My::DB->new }
785
786 ...
787
788 package My::Price;
789
790 use base 'My::Object';
791
792 __PACKAGE__->meta->setup
793 (
794 columns =>
795 [
796 price_id => { type => 'serial', not_null => 1 },
797 product_id => { type => 'int' },
798 region => { type => 'char', length => 2, default => 'US' },
799 price => { type => 'decimal', precision => 10, scale => 2 },
800 ],
801
802 foreign_keys => [ 'product' ],
803 );
804
805 ...
806
807 package My::Vendor;
808
809 use base 'My::Object';
810
811 __PACKAGE__->meta->setup
812 (
813 columns =>
814 [
815 id => { type => 'serial', not_null => 1 },
816 name => { type => 'varchar', length => 255 },
817 ],
818 );
819
820 ...
821
822 package My::Color;
823
824 use base 'My::Object';
825
826 __PACKAGE__->meta->setup
827 (
828 columns =>
829 [
830 code => { type => 'char', length => 3, not_null => 1 },
831 name => { type => 'varchar', length => 255 },
832 ],
833 );
834
835 ...
836
837 package My::Product;
838
839 use base 'My::Object';
840
841 __PACKAGE__->meta->setup
842 (
843 columns =>
844 [
845 id => { type => 'serial', not_null => 1 },
846 name => { type => 'varchar', length => 255 },
847 vendor_id => { type => 'int' },
848 ],
849
850 foreign_keys => [ 'vendor' ],
851
852 relationships =>
853 [
854 prices => { type => 'one to many' },
855 colors => { type => 'many to many' },
856 ],
857 );
858
859 ...
860
861 package My::ProductColors;
862
863 use base 'My::Object';
864
865 __PACKAGE__->meta->setup
866 (
867 columns => [ qw(id product_id color_code) ],
868 foreign_keys => [ 'product', 'color' ],
869 );
870
871 Let's add some data:
872
873 INSERT INTO vendors (id, name) VALUES (1, 'V1');
874 INSERT INTO vendors (id, name) VALUES (2, 'V2');
875
876 INSERT INTO products (id, name, vendor_id) VALUES (1, 'A', 1);
877 INSERT INTO products (id, name, vendor_id) VALUES (2, 'B', 2);
878 INSERT INTO products (id, name, vendor_id) VALUES (3, 'C', 1);
879
880 INSERT INTO prices (product_id, region, price) VALUES (1, 'US', 1.23);
881 INSERT INTO prices (product_id, region, price) VALUES (1, 'DE', 4.56);
882 INSERT INTO prices (product_id, region, price) VALUES (2, 'US', 5.55);
883 INSERT INTO prices (product_id, region, price) VALUES (3, 'US', 5.78);
884 INSERT INTO prices (product_id, region, price) VALUES (3, 'US', 9.99);
885
886 INSERT INTO colors (code, name) VALUES ('CC1', 'red');
887 INSERT INTO colors (code, name) VALUES ('CC2', 'green');
888 INSERT INTO colors (code, name) VALUES ('CC3', 'blue');
889 INSERT INTO colors (code, name) VALUES ('CC4', 'pink');
890
891 INSERT INTO product_colors (product_id, color_code) VALUES (1, 'CC1');
892 INSERT INTO product_colors (product_id, color_code) VALUES (1, 'CC2');
893
894 INSERT INTO product_colors (product_id, color_code) VALUES (2, 'CC4');
895
896 INSERT INTO product_colors (product_id, color_code) VALUES (3, 'CC2');
897 INSERT INTO product_colors (product_id, color_code) VALUES (3, 'CC3');
898
899 (Be aware that not all databases are smart enough to track explicitly
900 setting serial column values as shown in the INSERT statements above.
901 Subsequent auto-generated serial values may conflict with the
902 explicitly set serial column values already in the table. Values are
903 set explicitly here to make the examples easier to follow. In "real"
904 code, you should let the serial columns populate automatically.)
905
906 Finally, the classes in action:
907
908 $p = My::Product->new(id => 1)->load;
909
910 print $p->vendor->name, "\n"; # "V1"
911
912 # "US: 1.23, DE: 4.56"
913 print join(', ', map { $_->region .': '. $_->price } $p->prices), "\n";
914
915 # "red, green"
916 print join(', ', map { $_->name } $p->colors), "\n";
917
919 Using Rose::DB::Object's auto-initialization feature, the Perl code can
920 be reduced to an absurd degree. Given the same database schema and
921 data shown in the example above, consider the following classes:
922
923 package My::Auto::Color;
924 use base 'My::Object';
925 __PACKAGE__->meta->auto_initialize;
926 ...
927
928 package My::Auto::Price;
929 use base 'My::Object';
930 __PACKAGE__->meta->auto_initialize;
931 ...
932
933 package My::Auto::ProductColors;
934 use base 'My::Object';
935 __PACKAGE__->meta->auto_initialize;
936 ...
937
938 package My::Auto::Vendor;
939 use base 'My::Object';
940 __PACKAGE__->meta->auto_initialize;
941 ...
942
943 package My::Auto::Product;
944 use base 'My::Object';
945 __PACKAGE__->meta->auto_initialize;
946
947 Not a single table, column, foreign key, or relationship is specified,
948 yet everything still works:
949
950 $p = My::Auto::Product->new(id => 1)->load;
951
952 print $p->vendor->name, "\n"; # "V1"
953
954 # "US: 1.23, DE: 4.56"
955 print join(', ', map { $_->region .': '. $_->price } $p->prices), "\n";
956
957 # "red, green"
958 print join(', ', map { $_->name } $p->colors), "\n";
959
960 More precisely, everything still works provided that you load all the
961 of the related modules. For example, if you load "My::Auto::Product"
962 but don't load "My::Auto::Price" (either from within the
963 "My::Auto::Product" class or in your program itself), then the
964 "My::Auto::Product" will not have a "prices()" method (since your
965 program will have no knowledge of the "My::Auto::Price" class). Use
966 the loader if you want to set up a bunch of related classes
967 automatically without worrying about this kind of thing.
968
969 Anyway, I don't recommend this kind of extreme approach, but it is an
970 effective demonstration of the power of the convention manager.
971
973 John C. Siracusa (siracusa@gmail.com)
974
976 Copyright (c) 2010 by John C. Siracusa. All rights reserved. This
977 program is free software; you can redistribute it and/or modify it
978 under the same terms as Perl itself.
979
980
981
982perl v5.36.0 2022-07R-o2s2e::DB::Object::ConventionManager(3)