Rose::...tadata(3pm)
πΈ Rose::DB::Object::Metadata(3pm) πΈ
π NAME π
Rose::DB::Object::Metadata β Database object metadata. That's the whole name, bestie. It's giving "backstage manager for one database table," and honestly it ate. π
π SYNOPSIS π
okay so here's the exact code menu β all the commands and setup stay character-for-character, no cap:
use Rose::DB::Object::Metadata;
$meta = Rose::DB::Object::Metadata->new(class => 'Product');
# ...or...
$meta = Rose::DB::Object::Metadata->for_class('Product');
#
# Auto-initialization
#
$meta->table('products'); # optional if class name ends with "::Product"
$meta->auto_initialize;
#
# ...or manual setup
#
$meta->setup
(
table => 'products',
columns =>
[
id => { type => 'int', primary_key => 1 },
name => { type => 'varchar', length => 255 },
description => { type => 'text' },
category_id => { type => 'int' },
status =>
{
type => 'varchar',
check_in => [ 'active', 'inactive' ],
default => 'inactive',
},
start_date => { type => 'datetime' },
end_date => { type => 'datetime' },
date_created => { type => 'timestamp', default => 'now' },
last_modified => { type => 'timestamp', default => 'now' },
],
unique_key => 'name',
foreign_keys =>
[
category =>
{
class => 'Category',
key_columns =>
{
category_id => 'id',
}
},
],
relationships =>
[
prices =>
{
type => 'one to many',
class => 'Price',
column_map => { id => 'id_product' },
},
],
);
#
# ...or even more verbose manual setup (old-style, not recommended)
#
$meta->table('products');
$meta->columns
(
id => { type => 'int', primary_key => 1 },
name => { type => 'varchar', length => 255 },
description => { type => 'text' },
category_id => { type => 'int' },
status =>
{
type => 'varchar',
check_in => [ 'active', 'inactive' ],
default => 'inactive',
},
start_date => { type => 'datetime' },
end_date => { type => 'datetime' },
date_created => { type => 'timestamp', default => 'now' },
last_modified => { type => 'timestamp', default => 'now' },
);
$meta->unique_key('name');
$meta->foreign_keys
(
category =>
{
class => 'Category',
key_columns =>
{
category_id => 'id',
}
},
);
$meta->relationships
(
prices =>
{
type => 'one to many',
class => 'Price',
column_map => { id => 'id_product' },
},
);
...
π¦ DESCRIPTION π¦
Rose::DB::Object::Metadata objects store information about a single table in a database: the name of the table, the names and types of columns, any foreign or unique keys, etc. ποΈ That's the core tea.
These metadata objects are also responsible for supplying information to, and creating object methods for, the Rose::DB::Object-derived objects to which they belong.
They also store information about the Rose::DB::Objects that front the database tables they describe. What might normally be thought of as "class data" for the Rose::DB::Object is stored in the metadata object instead, in order to keep the method namespace of the Rose::DB::Object-derived class uncluttered. π
Rose::DB::Object::Metadata objects are per-class singletons; there is one Rose::DB::Object::Metadata object for each Rose::DB::Object-derived class. Metadata objects are almost never explicitly instantiated. Rather, they are automatically created and accessed through Rose::DB::Object-derived objects' meta method. π§
Once created, metadata objects can be populated manually or automatically. Both techniques are shown in the synopsis above. The automatic mode works by asking the database itself for the information. There are some caveats to this approach. See the auto-initialization section for more information. π
Rose::DB::Object::Metadata objects contain three categories of objects that are responsible for creating object methods in Rose::DB::Object-derived classes: columns, foreign keys, and relationships.
- Columns β Column objects are subclasses of
Rose::DB::Object::Metadata::Column. They are intended to store as much information as possible about each column. The particular class of the column object created for a database column is determined by a mapping table. The column class, in turn, is responsible for creating the accessor/mutator method(s) for the column. When it creates these methods, the column class can use (or ignore) any information stored in the column object. β¨ - Foreign keys β Foreign key objects are of the class
Rose::DB::Object::Metadata::ForeignKey. They store information about columns that refer to columns in other tables that are fronted by their ownRose::DB::Object-derived classes. A foreign key object is responsible for creating accessor method(s) to fetch the foreign object from the foreign table. π«Ά - Relationships β Relationship objects are subclasses of
Rose::DB::Object::Metadata::Relationship. They store information about a table's relationship to other tables that are fronted by their ownRose::DB::Object-derived classes. The particular class of the relationship object created for each relationship is determined by a mapping table. A relationship object is responsible for creating accessor method(s) to fetch the foreign objects from the foreign table. π
β¨ AUTO-INITIALIZATION β¨
okay so bestie, manually filling out metadata objects? tedious and repetitive, literally. And here's the cute part: nearly all the info stored in a Rose::DB::Object::Metadata object already exists in the database in some form. So it's reasonable to think, why not just pull that info straight out of the database instead of typing it all by hand? That automatic metadata extraction + subsequent Rose::DB::Object::Metadata object population is called "auto-initialization." π
The auto-init example in the synopsis above is the most succinct variant:
$meta->auto_initialize;
As you can read in the documentation for the auto_initialize method, that's shorthand for individually auto-initializing each part of the metadata object: columns, the primary key, unique keys, and foreign keys. But this brevity comes at a price, bestie: there are many caveats to auto-initialization. π
π Caveats π
π Start-Up Cost π
To retrieve the info needed for auto-initialization, a database connection must be opened and queries must be run. Sometimes those queries include complex joins. And all of these queries must successfully complete before the Rose::DB::Object-derived objects that the Rose::DB::Object::Metadata is associated with can be used. π«Ά
In an environment like mod_perl, server start-up time is precisely when you want to do any expensive operations. But in a command-line script or other short-lived process, the overhead of auto-initializing many metadata objects may become prohibitive. π
Also, don't forget that auto-initialization requires a database connection. Rose::DB::Object-derived objects can sometimes be useful even without a database connection β e.g., to temporarily store information that will never go into the database, or to synthesize data using object methods that have no corresponding database column. When using auto-initialization, this is not possible, because the Rose::DB::Object-derived class won't even load if auto-initialization fails because it could not connect to the database. π
π Detail π
First, auto-initialization cannot generate information that exists only in the mind of the programmer. The most common example is a relationship between two database tables that is either ambiguous or totally unexpressed by the database itself. π§
For example, if a foreign key constraint does not exist, the relationship between rows in two different tables cannot be extracted from the database, and therefore cannot be auto-initialized. Periodt. π
Even within the realm of information that, by all rights, should be available in the database, there are limitations. Although there is a handy DBI API for extracting metadata from databases, unfortunately very few DBI drivers support it fully. Some don't support it at all. In almost all cases, some manual work is required to (often painfully) extract information from the database's "system tables" or "catalog." π
More troublingly, databases do not always provide all the metadata that a human could extract from the series of SQL statement that created the table in the first place. Sometimes the information just isn't in the database to be extracted, having been lost in the process of table creation. Here's just one example. Consider this MySQL table definition:
CREATE TABLE mytable
(
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
code CHAR(6),
flag BOOLEAN NOT NULL DEFAULT 1,
bits BIT(5) NOT NULL DEFAULT '00101',
name VARCHAR(64)
);
Now look at the metadata that MySQL 4 stores internally for this table:
mysql> describe mytable;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | | PRI | NULL | auto_increment |
| code | varchar(6) | YES | | NULL | |
| flag | tinyint(1) | | | 1 | |
| bits | tinyint(1) | | | 101 | |
| name | varchar(64) | YES | | NULL | |
+-------+------------------+------+-----+---------+----------------+
Note the following divergences from the CREATE TABLE statement. π
- The "code" column has changed from
CHAR(6)toVARCHAR(6). This is troublesome if you want the traditional semantics of aCHARtype, namely the padding with spaces of values that are less than the column length. - The "flag" column has changed from
BOOLEANtoTINYINT(1). The default accessor method created for boolean columns has value coercion and formatting properties that are important to this data type. The default accessor created for integer columns lacks these constraints. The metadata object has no way of knowing that "flag" was supposed to be a boolean column, and thus makes the wrong kind of accessor method. It is thus possible to store, say, a value of "7" in the "flag" column. Oops. π - The "bits" column has changed from
BIT(5)toTINYINT(1). As in the case of the "flag" column above, this type change prevents the correct accessor method from being created. The default bitfield accessor method auto-inflates column values intoBit::Vectorobjects, which provide convenient methods for bit manipulation. The default accessor created for integer columns does no such thing. π
Remember that the auto-initialization process can only consider the metadata actually stored in the database. It has no access to the original "create table" statement. Thus, the semantics implied by the original table definition are effectively lost. π
Again, this is just one example of the kind of detail that can be lost in the process of converting your table definition into metadata that is stored in the database. Admittedly, MySQL is perhaps the worst case-scenario, having a well-deserved reputation for disregarding the wishes of table definitions. (The use of implicit default values for "NOT NULL" columns is yet another example.) π
Thankfully, there is a solution to this dilemma. Remember that auto-initialization is actually a multi-step process hiding behind that single call to the auto_initialize method. To correct the sins of the database, simply break the auto-initialization process into its components. For example, here's how to correctly auto-initialize the "mytable" example above:
# Make a first pass at column setup
$meta->auto_init_columns;
# Account for inaccuracies in DBD::mysql's column info by
# replacing incorrect column definitions with new ones.
# Fix CHAR(6) column that shows up as VARCHAR(6)
$meta->column(code => { type => 'char', length => 6 });
# Fix BIT(5) column that shows up as TINYINT(1)
$meta->column(bits => { type => 'bits', bits => 5, default => 101 });
# Fix BOOLEAN column that shows up as TINYINT(1)
$meta->column(flag => { type => 'boolean', default => 1 });
# Do everything else
$meta->auto_initialize;
Note that auto_initialize was called at the end. Without the replace_existing parameter, this call will preserve any existing metadata, rather than overwriting it, so our "corrections" are safe. π
π οΈ Maintenance π οΈ
The price of auto-initialization is eternal vigilance. "What does that mean? Isn't auto-initialization supposed to save time and effort?" Well, yes, but at a cost. In addition to the caveats described above, consider what happens when a table definition changes. π
"Ah ha!" you say, "My existing class will automatically pick up the changes the next time it's loaded! Auto-initialization at its finest!" But is it? What if you added a "NOT NULL" column with no default value? Yes, your existing auto-initialized class will pick up the change, but your existing code will no longer be able to save one these objects. Or what if you're using MySQL and your newly added column is one of the types described above that requires manual tweaking in order to get the desired semantics. Will you always remember to make this change? π
Auto-initialization is not a panacea. Every time you make a change to your database schema, you must also revisit each affected Rose::DB::Object-derived class to at least consider whether or not the metadata needs to be corrected or updated. π
The trade-off may be well worth it, but it's still something to think about. There is, however, a hybrid solution that might be even better. Continue on to the next section to learn more. π¦
π§ Code Generation π§
As described in the section above, auto-initializing metadata at runtime by querying the database has many caveats. An alternate approach is to query the database for metadata just once, and then generate the equivalent Perl code which can be pasted directly into the class definition in place of the call to auto_initialize. β¨
Like the auto-initialization process itself, perl code generation has a convenient wrapper method as well as separate methods for the individual parts. All of the perl code generation methods begin with perl_, and they support some rudimentary code formatting options to help the code conform to you preferred style. Examples can be found with the documentation for each perl_* method. π
This hybrid approach to metadata population strikes a good balance between upfront effort and ongoing maintenance. Auto-generating the Perl code for the initial class definition saves a lot of tedious typing. From that point on, manually correcting and maintaining the definition is a small price to pay for the decreased start-up cost, the ability to use the class in the absence of a database connection, and the piece of mind that comes from knowing that your class is stable, and won't change behind your back in response to an "action at a distance" (i.e., a database schema update). π
β¨ CLASS METHODS β¨
Okay bestie, this is where the class-level magic lives β all the stuff you call on Rose::DB::Object::Metadata itself, not on an instance. Buckle up π
auto_prime_caches [BOOL]β Get or set a boolean that says whetherprime_cachesgets called from inside theinitializemethod. Default is true if the"MOD_PERL"environment variable ($ENV{'MOD_PERL'}) is set to a true value β false otherwise. iykyk πclear_all_dbsβ Nukes thedbattribute of the metadata object for every single registered class. Like a little reset button, no cap.column_type_class TYPE [, CLASS]β Hand it a column type stringTYPEand it returns the name of theRose::DB::Object::Metadata::Column-derived class used to store metadata and build the accessor method(s) for columns of that type. Pass aCLASSand boom βTYPEgets mapped toCLASS. Either way,TYPEis auto-lowercased for you, bestie β¨column_type_classes [MAP]β Get or set the hash mapping column type strings to the names of theRose::DB::Object::Metadata::Column-derived classes used to store metadata and create the accessor method(s) for columns of that type.
Heads up: this hash is class data. If you wanna modify it, the suggestion (straight from the source) is to make your own subclass ofRose::DB::Object::Metadataand set that as themeta_classof yourRose::DB::Objectsubclass. Okay? π
If you pass MAP (a list of type/class pairs, or a reference to a hash of the same), then MAP replaces the current column type mapping. Returns a list of type/class pairs in list context, or a reference to the hash of type/class mappings in scalar context.
The default mapping of type names to class names is:
scalar => Rose::DB::Object::Metadata::Column::Scalar
char => Rose::DB::Object::Metadata::Column::Character
character => Rose::DB::Object::Metadata::Column::Character
varchar => Rose::DB::Object::Metadata::Column::Varchar
varchar2 => Rose::DB::Object::Metadata::Column::Varchar
nvarchar => Rose::DB::Object::Metadata::Column::Varchar
nvarchar2 => Rose::DB::Object::Metadata::Column::Varchar
string => Rose::DB::Object::Metadata::Column::Varchar
text => Rose::DB::Object::Metadata::Column::Text
blob => Rose::DB::Object::Metadata::Column::Blob
bytea => Rose::DB::Object::Metadata::Column::Pg::Bytea
bits => Rose::DB::Object::Metadata::Column::Bitfield
bitfield => Rose::DB::Object::Metadata::Column::Bitfield
bool => Rose::DB::Object::Metadata::Column::Boolean
boolean => Rose::DB::Object::Metadata::Column::Boolean
int => Rose::DB::Object::Metadata::Column::Integer
integer => Rose::DB::Object::Metadata::Column::Integer
tinyint => Rose::DB::Object::Metadata::Column::Integer
smallint => Rose::DB::Object::Metadata::Column::Integer
mediumint => Rose::DB::Object::Metadata::Column::Integer
bigint => Rose::DB::Object::Metadata::Column::BigInt
serial => Rose::DB::Object::Metadata::Column::Serial
bigserial => Rose::DB::Object::Metadata::Column::BigSerial
enum => Rose::DB::Object::Metadata::Column::Enum
num => Rose::DB::Object::Metadata::Column::Numeric
numeric => Rose::DB::Object::Metadata::Column::Numeric
decimal => Rose::DB::Object::Metadata::Column::Numeric
float => Rose::DB::Object::Metadata::Column::Float
float8 => Rose::DB::Object::Metadata::Column::DoublePrecision
'double precision' =>
Rose::DB::Object::Metadata::Column::DoublePrecision
time => Rose::DB::Object::Metadata::Column::Time
interval => Rose::DB::Object::Metadata::Column::Interval
date => Rose::DB::Object::Metadata::Column::Date
datetime => Rose::DB::Object::Metadata::Column::Datetime
timestamp => Rose::DB::Object::Metadata::Column::Timestamp
timestamptz =>
Rose::DB::Object::Metadata::Column::TimestampWithTimeZone
'timestamp with time zone' =>
Rose::DB::Object::Metadata::Column::TimestampWithTimeZone
'datetime year to fraction' =>
Rose::DB::Object::Metadata::Column::DatetimeYearToFraction
'datetime year to fraction(1)' =>
Rose::DB::Object::Metadata::Column::DatetimeYearToFraction1
'datetime year to fraction(2)' =>
Rose::DB::Object::Metadata::Column::DatetimeYearToFraction2
'datetime year to fraction(3)' =>
Rose::DB::Object::Metadata::Column::DatetimeYearToFraction3
'datetime year to fraction(4)' =>
Rose::DB::Object::Metadata::Column::DatetimeYearToFraction4
'datetime year to fraction(5)' =>
Rose::DB::Object::Metadata::Column::DatetimeYearToFraction5
'timestamp with time zone' =>
Rose::DB::Object::Metadata::Column::Timestamp
'timestamp without time zone' =>
Rose::DB::Object::Metadata::Column::Timestamp
'datetime year to second' =>
Rose::DB::Object::Metadata::Column::DatetimeYearToSecond
'datetime year to minute' =>
Rose::DB::Object::Metadata::Column::DatetimeYearToMinute
'datetime year to month' =>
Rose::DB::Object::Metadata::Column::DatetimeYearToMonth
'epoch' => Rose::DB::Object::Metadata::Column::Epoch
'epoch hires' => Rose::DB::Object::Metadata::Column::Epoch::HiRes
array => Rose::DB::Object::Metadata::Column::Array
set => Rose::DB::Object::Metadata::Column::Set
chkpass => Rose::DB::Object::Metadata::Column::Pg::Chkpass
column_type_namesβ Returns the list of registered column type names in list context, or a reference to that array in scalar context. Two vibes, one method π¦convention_manager_class NAME [, CLASS]β Give it a stringNAMEand it hands back the name of theRose::DB::Object::ConventionManager-derived class mapped to that name. Pass aCLASSandNAMEgets mapped toCLASS. Obsessed with the symmetry, honestly.convention_manager_classes [MAP]β Get or set the hash that maps names toRose::DB::Object::ConventionManager-derived class names.
Same energy as before: this hash is class data. Wanna modify it? Make your own subclass ofRose::DB::Object::Metadata, then set it as themeta_classof yourRose::DB::Objectsubclass. Do it properly π
Pass MAP (list of name/class pairs, or a ref to a hash of the same) and MAP replaces the current mapping. Returns a list of name/class pairs in list context, or a ref to the hash of name/class mappings in scalar context.
The default mapping of names to classes is:
default => Rose::DB::Object::ConventionManager
null => Rose::DB::Object::ConventionManager::Null
dbi_prepare_cached [BOOL]β Get or set a boolean saying whether theRose::DB::Object-derived class uses DBI'sprepare_cachedmethod by default (instead of plain oldprepare) when loading, saving, and deleting objects. Default value is true. Caching slay β¨default_column_undef_overrides_default [BOOL]β Get or set the default value of thecolumn_undef_overrides_defaultattribute. Defaults toundef. (Yes, a default for a default. We love layers.)default_manager_base_class [CLASS]β Get or set the default name of the base class this metadata class uses when generating manager classes. Default value is"Rose::DB::Object::Manager". If you wanna override it for one specific metadata object, use thedefault_manager_base_class()object method instead. π«Άfor_class CLASSβ Returns the singleRose::DB::Object::Metadataobject associated withCLASSβ or creates it if it doesn't exist yet.CLASShere is the name of aRose::DB::Object-derived class. One class, one metadata object, main character energy πinit_column_name_to_method_name_mapperβ This class method should return a reference to a subroutine that maps column names to method names β or false if it doesn't wanna do any custom mapping. The default implementation just returns zero (0).
If you do define it, that subroutine should take four arguments: the metadata object, the column name, the column method type, and the method name that would've been used if the mapper subroutine didn't exist. It should return a method name. Build your own little name transformer, bestie π§
prime_all_caches [PARAMS]β Callsprime_cacheson allregistered_classes, passingPARAMSalong to each call.PARAMSare name/value pairs. Valid parameters are:db DBβ ARose::DB-derived object used to figure out which data source the cached metadata gets generated on behalf of. (Every data source has its own set of cached metadata, fr fr.) This parameter is optional β if you don't pass it, then theRose::DB-derived object returned by theinit_dbmethod for each class gets used instead.
relationship_type_class TYPEβ Give it a relationship type stringTYPEand it returns the name of theRose::DB::Object::Metadata::Relationship-derived class used to store metadata and create the accessor method(s) for relationships of that type.relationship_type_classes [MAP]β Get or set the hash mapping relationship type strings to the names of theRose::DB::Object::Metadata::Relationship-derived classes used to store metadata and create object methods that fetch and/or manipulate objects from foreign tables.
You already know the drill: class data. Wanna change it? SubclassRose::DB::Object::Metadataand set that bad boy as themeta_classof yourRose::DB::Objectsubclass π
Pass MAP (list of type/class pairs, or a ref to a hash of the same) and MAP replaces the current relationship type mapping. Returns a list of type/class pairs in list context, or a ref to the hash of type/class mappings in scalar context.
The default mapping of type names to class names is:
'one to one' => Rose::DB::Object::Metadata::Relationship::OneToOne
'one to many' => Rose::DB::Object::Metadata::Relationship::OneToMany
'many to one' => Rose::DB::Object::Metadata::Relationship::ManyToOne
'many to many' => Rose::DB::Object::Metadata::Relationship::ManyToMany
registered_classesβ Returns a list (in list context) or a reference to an array (in scalar context) of the names of all theRose::DB::Object-derived classes registered under this metadata class'sregistry_key. The whole roster, no gatekeeping πregistry_keyβ Returns the string used to groupRose::DB::Object-derived class names in the class registry. The default is"Rose::DB::Object::Metadata". It's giving... the group chat name, honestly π
π CONSTRUCTOR π
π new PARAMS π
Okay so this one returns (or creates, if it's needed) the single Rose::DB::Object::Metadata associated with a particular Rose::DB::Object-derived class, and it modifies or initializes that thing according to PARAMS, where PARAMS are name/value pairs. π
Any object method is a valid parameter name, but bestie, PARAMS must include a value for the "class" parameter, because that's literally how Rose::DB::Object::Metadata objects are mapped to their corresponding Rose::DB::Object-derived class. No "class", no mapping, iykyk.
π OBJECT METHODS π
π add_column ARGS π
This is an alias for the add_columns method. Same energy, shorter name. β¨
π add_columns ARGS π
Add the columns specified by ARGS to the list of columns for the table. It returns the list of columns added in list context, or a reference to an array of columns added in scalar context. Columns can be specified in ARGS in several ways. π«Ά
- If an argument is a subclass of
Rose::DB::Object::Metadata::Column, it is added as-is. - If an argument is a plain scalar, it is taken as the name of a scalar column. A column object of the class returned by the method call
$obj->column_type_class('scalar')is constructed and then added. - Otherwise, only name/value pairs are considered, where the name is taken as the column name and the value must be a reference to a hash.
Now for the hash details, because this is where the lore gets deep:
- If the hash contains the key
"primary_key"with a true value, then the column is marked as aprimary_key_memberand the column name is added to the list of primary key columns by calling theadd_primary_key_columnmethod with the column name as its argument. - If the hash contains the key
"alias", then the value of that key is used as the alias for the column. This is a shorthand equivalent to explicitly calling thealias_columncolumn method. - If the hash contains the key
"temp"and its value is true, then the column is actually added to the list of non-persistent columns. - If the hash contains a key with the same name as a column trigger event type (e.g.,
"on_set","on_load","inflate") then the value of that key must be a code reference or a reference to an array of code references, which will be added to the list of the column's triggers for the specified event type. - If the hash contains the key
"methods", then its value must be a reference to an array or a reference to a hash. Theauto_method_typesof the column are then set to the values of the referenced array, or the keys of the referenced hash. The values of the referenced hash are used to set themethod_namefor their corresponding method types. - If the hash contains the key
"add_methods", then its value must be a reference to an array or a reference to a hash. The values of the referenced array or the keys of the referenced hash are added to the column'sauto_method_types. The values of the referenced hash are used to set themethod_namefor their corresponding method types. - If the
"methods"and"add_methods"keys are both set, a fatal error will occur. π
Then the column_type_class method is called with the value of the "type" hash key as its argument (or "scalar" if that key is missing), returning the name of a column class. Finally, a new column object of that class is constructed and is passed all the remaining pairs in the hash reference, along with the name and type of the column. That column object is then added to the list of columns.
This is done until there are no more arguments to be processed, or until an argument does not conform to one of the required formats, in which case a fatal error occurs.
Example:
$meta->add_columns
(
# Add a scalar column
'name',
# which is roughly equivalent to:
#
# $class = $meta->column_type_class('scalar');
# $col = $class->new(name => 'name');
# (then add $col to the list of columns)
# Add by name/hashref pair with explicit method types
age => { type => 'int', default => 5, methods => [ 'get', 'set' ] },
# which is roughly equivalent to:
#
# $class = $meta->column_type_class('int');
# $col = $class->new(name => 'age',
# type => 'int',
# default => 5);
# $col->auto_method_types('get', 'set');
# (then add $col to the list of columns)
# Add by name/hashref pair with additional method type and name
size => { type => 'int', add_methods => { 'set' => 'set_my_size' } },
# which is roughly equivalent to:
#
# $class = $meta->column_type_class('int');
# $col = $class->new(name => 'size',
# type => 'int',);
# $col->add_auto_method_types('set');
# $col->method_name(set => 'set_my_size');
# (then add $col to the list of columns)
# Add a column object directly
Rose::DB::Object::Metadata::Column::Date->new(
name => 'start_date'),
);
π¦ add_nonpersistent_column ARGS π¦
This is an alias for the add_nonpersistent_columns method. Cute little shortcut. π
πΈ add_nonpersistent_columns ARGS πΈ
This method behaves like the add_columns method, except that it adds to the list of non-persistent columns. See the documentation for the nonpersistent_columns method for more information.
β add_foreign_keys ARGS β
Add foreign keys as specified by ARGS. Each foreign key must have a name that is unique among all other foreign keys in this class. No duplicate names, bestie, that's the rule. π
Foreign keys can be specified in ARGS in several ways:
- If an argument is a
Rose::DB::Object::Metadata::ForeignKeyobject (or subclass thereof), it is added as-is. - Otherwise, only name/value pairs are considered, where the name is taken as the foreign key name and the value must be a reference to a hash.
Then the hash details kick in:
- If the hash contains the key
"methods", then its value must be a reference to an array or a reference to a hash. Theauto_method_typesof the foreign key are then set to the values of the referenced array, or the keys of the referenced hash. The values of the referenced hash are used to set themethod_namefor their corresponding method types. - If the hash contains the key
"add_methods", then its value must be a reference to an array or a reference to a hash. The values of the referenced array or the keys of the referenced hash are added to the foreign key'sauto_method_types. The values of the referenced hash are used to set themethod_namefor their corresponding method types. - If the
"methods"and"add_methods"keys are both set, a fatal error will occur. π
A new Rose::DB::Object::Metadata::ForeignKey object is constructed and is passed all the remaining pairs in the hash reference, along with the name of the foreign key as the value of the "name" parameter. That foreign key object is then added to the list of foreign keys.
This is done until there are no more arguments to be processed, or until an argument does not conform to one of the required formats, in which case a fatal error occurs.
Example:
$meta->add_foreign_keys
(
# Add by name/hashref pair with explicit method type
category =>
{
class => 'Category',
key_columns => { category_id => 'id' },
methods => [ 'get' ],
},
# which is roughly equivalent to:
#
# $fk = Rose::DB::Object::Metadata::ForeignKey->new(
# class => 'Category',
# key_columns => { category_id => 'id' },
# name => 'category');
# $fk->auto_method_types('get');
# (then add $fk to the list of foreign keys)
# Add by name/hashref pair with additional method type and name
color =>
{
class => 'Color',
key_columns => { color_id => 'id' },
add_methods => { set => 'set_my_color' },
},
# which is roughly equivalent to:
#
# $fk = Rose::DB::Object::Metadata::ForeignKey->new(
# class => 'Color',
# key_columns => { color_id => 'id' },
# name => 'color');
# $fk->add_auto_method_types('set');
# $fk->method_name(set => 'set_my_color');
# (then add $fk to the list of foreign keys)
# Add a foreign key object directly
Rose::DB::Object::Metadata::ForeignKey->new(...),
);
For each foreign key added, a corresponding relationship with the same name is added if it does not already exist. The relationship type is determined by the value of the foreign key object's relationship attribute. The default is "many to one". The class of the relationship is chosen by calling relationship_type_class with the relationship type as an argument.
π add_primary_key_column COLUMN π
This method is an alias for add_primary_key_columns. Short and sweet. β¨
π« add_primary_key_columns COLUMNS π«
Add COLUMNS to the list of columns that make up the primary key. COLUMNS can be a list or reference to an array of column names.
π add_relationship ARGS π
This is an alias for the add_relationships method. Same thing, different spelling. π«Ά
π add_relationships ARGS π
Add relationships as specified by ARGS. Each relationship must have a name that is unique among all other relationships in this class. Again: unique names, no cap. π
Relationships can be specified in ARGS in several ways:
- If an argument is a subclass of
Rose::DB::Object::Metadata::Relationship, it is added as-is. - Otherwise, only name/value pairs are considered, where the name is taken as the relationship name and the value must be a reference to a hash.
If the hash contains the key "methods", then its value must be a reference to an array or a reference to a hash. The auto_method_types of the relationship are then set to the values of the referenced array, or the keys of the referenced hash. The values of the referenced hash are used to set the method_name for their corresponding method types.
If the hash has an "add_methods" key, then its value has to be a reference to an array or a reference to a hash. What happens next: the values of the referenced array, or the keys of the referenced hash, get added to the relationship's auto_method_types. And the values of the referenced hash? Those set the method_name for their corresponding method types. π
And if "methods" and "add_methods" are like, both set at the same time? Fatal error, bestie. Straight up. π
Then relationship_type_class gets called with whatever the "type" hash key holds, and it hands back the name of a relationship class.
Finally, a brand-new relationship object of that class gets constructed, and it's passed all the remaining pairs in the hash reference, plus the name and type of the relationship. That object then joins the list of relationships. π
And this whole thing keeps going until there are no more arguments to process β or until an argument doesn't match one of the required formats, in which case: fatal error. π
Example:
$meta->add_relationships
(
# Add by name/hashref pair with explicit method type
category =>
{
type => 'many to one',
class => 'Category',
column_map => { category_id => 'id' },
methods => [ 'get' ],
},
# which is roughly equivalent to:
#
# $class = $meta->relationship_type_class('many to one');
# $rel = $class->new(class => 'Category',
# column_map => { category_id => 'id' },
# name => 'category');
# $rel->auto_method_types('get');
# (then add $rel to the list of relationships)
# Add by name/hashref pair with additional method type and name
color =>
{
type => 'many to one',
class => 'Color',
column_map => { color_id => 'id' },
add_methods => { set => 'set_my_color' },
},
# which is roughly equivalent to:
#
# $class = $meta->relationship_type_class('many to one');
# $rel = $class->new(class => 'Color',
# column_map => { color_id => 'id' },
# name => 'color');
# $rel->add_auto_method_types('set');
# $fk->method_name(set => 'set_my_color');
# (rel add $fk to the list of foreign keys)
# Add a relationship object directly
Rose::DB::Object::Metadata::Relationship::OneToOne->new(...),
);
add_unique_key KEYβ this one's just an alias foradd_unique_keys, no cap β¨add_unique_keys KEYSβ adds new unique keys, and you can hand them over in two whole ways:- if an argument is a
Rose::DB::Object::Metadata::UniqueKeyobject (or a subclass of one), its parent gets set to the metadata object itself, and then it's added π«Ά - otherwise, the argument has to be either a single column name, or a reference to an array of column names, that together make up a unique key. A fresh
Rose::DB::Object::Metadata::UniqueKeygets created with its parent set to the metadata object itself, and then that unique key object is added to this list of unique keys for this class π
- if an argument is a
alias_column NAME, ALIASβ sets the alias for the column named NAME to ALIAS. Sometimes you genuinely need an alias, because the column name collides with an existingRose::DB::Objectmethod name. π Like, picture a column named"save". TheRose::DB::ObjectAPI already has a method calledsave, so obviously that name is not available for the accessor of the"save"column. The fix? Make an alias:
$meta->alias_column(save => 'save_flag');
Check the Rose::DB::Object docs, or just call the method_name_is_reserved method, to figure out whether a method name is reserved. π
allow_inline_column_values [BOOL]β get or set that boolean flag that says whether the associatedRose::DB::Object-derived class should try to inline column values that DBI doesn't handle correctly when they're bound to placeholders viabind_columns. Default value is false. Turning this flag on does reduce the performance ofupdateandinsertoperations on theRose::DB::Object-derived object. But sometimes you have to, because some DBI drivers don't (or straight up can't) always do the right thing when binding values to placeholders in SQL statements. π« For example, take this SQL for the Informix database:
CREATE TABLE test (d DATETIME YEAR TO SECOND);
INSERT INTO test (d) VALUES (CURRENT);
Totally valid Informix SQL β it'll insert a row with the current date and time into the "test" table. β¨ Now look at what happens when you try to do the same thing with DBI placeholders (assume the table was already created per that CREATE TABLE statement up there):
$sth = $dbh->prepare('INSERT INTO test (d) VALUES (?)');
$sth->execute('CURRENT'); # Error!
What you get is an error like this:
DBD::Informix::st execute failed: SQL: -1262: Non-numeric
character in datetime or interval.
Basically, DBD::Informix went and quoted the string "CURRENT", and that string only has special meaning to Informix when it is not quoted. π So to make it work, the value "CURRENT" has to be "inlined" instead of bound to a placeholder, when it's the value of a "DATETIME YEAR TO SECOND" column in an Informix database. Periodt.
auto_load_related_classes [BOOL]β get or set the flag for whether classes related to this class through a foreign key or some other relationship get automatically loaded when this class is initialized. Default value is true. π¦cached_objects_expire_in [DURATION]β only applicable if this metadata object is associated with aRose::DB::Object::Cached-derived class. It literally just calls the class method of the same name that belongs to theRose::DB::Object::Cached-derived class associated with this metadata object. πcatalog [CATALOG]β get or set the database catalog for this class. This setting overrides any setting in the db object. Only use this method if you know the class will always point to a specific catalog, no matter what theRose::DB-derived database handle object specifies. β οΈclass [CLASS]β get or set theRose::DB::Object-derived class associated with this metadata object. This is the class where the accessor methods for each column get created (bymake_methods). πclass_for PARAMSβ returns the name of theRose::DB::Object-derived class associated with the"catalog","schema", and"table"given in the name/value paris in PARAMS. Catalog and/or schema can be left out if they're unknown or inapplicable, and you'll get the "best" match back. Returns undef if no class name is registered under those PARAMS. π§
Heads up: you can also call this as a class method, but it might need explicit"catalog"and/or"schema"arguments when the database supports those concepts and has default implicit values for them.
clear_object_cacheβ only applicable if this metadata object is associated with aRose::DB::Object::Cached-derived class. It just calls the class method of the same name that belongs to theRose::DB::Object::Cached-derived class associated with this metadata object. πΈcolumn NAME [, COLUMN | HASHREF]β get or set the column named NAME.- Just NAME? You get the
Rose::DB::Object::Metadata::Column-derived column object for the column of that name. If there's no such column, you get undef. - Both NAME and COLUMN? Then COLUMN has to be a
Rose::DB::Object::Metadata::Column-derived object. Its name gets set to NAME, then it's stored as the column metadata object for NAME, replacing any existing column. π - Both NAME and HASHREF? Then the combo of NAME and HASHREF has to form a name/value pair suitable for passing to
add_columns. That new column replaces any existing column. π₯
- Just NAME? You get the
columns [ARGS]β get or set the whole list of columns. If ARGS are passed, the column list gets cleared and then ARGS get passed along toadd_columns. Returns a list of column objects in list context, or a reference to an array of column objects in scalar context. β¨column_accessor_method_name NAMEβ returns the name of the"get"method for the column named NAME. Just a shortcut for$meta->column(NAME)->accessor_method_name. πcolumn_accessor_method_namesβ returns a list (in list context) or a reference to the array (in scalar context) of the names of the"set"methods for all the columns, in the order the columns come back fromcolumn_names. βcolumn_aliases [MAP]β get or set the hash that maps column names to their aliases. Pass MAP (a list of name/value pairs or a reference to a hash) and MAP replaces the current alias mapping. Returns a reference to the hash mapping column names to aliases.
Real talk: modifying this map does nothing ifinitialize,make_methods, ormake_column_methodshas already been called for the current class. π
column_mutator_method_name NAMEβ returns the name of the"set"method for the column named NAME. Just a shortcut for$meta->column(NAME)->mutator_method_name. π¦column_mutator_method_namesβ returns a list (in list context) or a reference to the array (in scalar context) of the names of the"set"methods for all the columns, in the order the columns come back fromcolumn_names. πcolumn_namesβ returns a list (in list context) or a reference to an array (in scalar context) of column names. πcolumn_name_to_method_name_mapper [CODEREF]β get or set the code reference to the subroutine used to map column names to method names. If it's undefined, then theinit_column_name_to_method_name_mapperclass method gets called to initialize it. If it's still undefined or false, then the"default"method name is used. π§
If it's defined, that subroutine should take four arguments: the metadata object, the column name, the column method type, and the method name that would be used if the mapper subroutine did not exist. It should return a method name. π«Ά
column_rw_method_name NAMEβ returns the name of theget_setmethod for the column named NAME. This is just a shortcut for$meta->column(NAME)->rw_method_name. β¨column_rw_method_namesβ returns a list (in list context) or a reference to the array (in scalar context) of the names of theget_setmethods for all the columns, in the order that the columns are returned bycolumn_names.column_undef_overrides_default [BOOL]β get or set a boolean value that influences the default value of theundef_overrides_defaultattribute for each column in this class. See the documentation forRose::DB::Object::Metadata::Column'sundef_overrides_defaultattribute for more information. Defaults to the value returned by thedefault_column_undef_overrides_defaultclass method. πconvention_manager [ OBJECT | CLASS | NAME ]β get or set the convention manager for this class. Defaults to the return value of theinit_convention_managermethod.- If
undefis passed, then aRose::DB::Object::ConventionManager::Nullobject is stored instead. - If a
Rose::DB::Object::ConventionManager-derived object is passed, itsmetaattribute is set to this metadata object and then it is used as the convention manager for this class. - If a
Rose::DB::Object::ConventionManager-derived class name is passed, a new object of that class is created with itsmetaattribute set to this metadata object. Then it is used as the convention manager for this class. - If a convention manager name is passed, then the corresponding class is looked up in the convention manager class map, a new object of that class is constructed, its
metaattribute set to this metadata object, and it is used as the convention manager for this class. If there is no class mapped to NAME, a fatal error will occur. π¨ - See the
Rose::DB::Object::ConventionManagerdocumentation for more information on convention managers.
- If
dbβ returns theRose::DB-derived object associated with this metadata object's class. A fatal error will occur ifclassis undefined or if theRose::DBobject could not be created.default_cascade_save [BOOL]β get or set a boolean value that indicates whether or not the class associated with this metadata object will save related objects when the parent object is saved. See the documentation forRose::DB::Object'ssave()method for details. The default value isfalse.default_load_speculative [BOOL]β get or set a boolean value that indicates whether or not the class associated with this metadata object will load speculatively by default. See the documentation forRose::DB::Object'sload()method for details. The default value isfalse.default_update_changes_only [BOOL]β get or set a boolean value that indicates whether or not the class associated with this metadata object will update only an object's modified columns by default (instead of updating all columns). See the documentation forRose::DB::Object'supdate()method for details. The default value isfalse.delete_column NAMEβ delete the column named NAME.delete_columnsβ delete all of the columns.delete_column_type_class TYPEβ delete the type/class mapping entry for the column type TYPE.delete_convention_manager_class NAMEβ delete the name/class mapping entry for the convention manager class mapped to NAME.delete_nonpersistent_column NAMEβ delete the non-persistent column named NAME.delete_nonpersistent_columnsβ delete all of thenonpersistent_columns.delete_relationship NAMEβ delete the relationship named NAME.delete_relationshipsβ delete all of the relationships.delete_relationship_type_class TYPEβ delete the type/class mapping entry for the relationship type TYPE.delete_unique_keysβ delete all of the unique key definitions.error_mode [MODE]β get or set the error mode of theRose::DB::Objectthat fronts the table described by thisRose::DB::Object::Metadataobject. If the error mode is false, then it defaults to the return value of theinit_error_modemethod, which isfatalby default. π±- The error mode determines what happens when a
Rose::DB::Objectmethod encounters an error. Thereturnerror mode causes the methods to behave as described in theRose::DB::Objectdocumentation. All other error modes cause an action to be performed before (possibly) returning as per the documentation (depending on whether or not the "action" is some variation on "throw an exception."). - Valid values of
MODEare:carpβ callCarp::carpwith the value of the object error as an argument.cluckβ callCarp::cluckwith the value of the object error as an argument.confessβ callCarp::confesswith the value of the object error as an argument.croakβ callCarp::croakwith the value of the object error as an argument.fatalβ an alias for thecroakmode.returnβ return a value that indicates that an error has occurred, as described in the documentation for each method.
- In all cases, the object's
errorattribute will also contain the error message.
- The error mode determines what happens when a
first_columnβ returns the first column, determined by the order that columns were added, orundefif there are no columns.foreign_key NAME [, FOREIGNKEY | HASHREF ]β get or set the foreign key named NAME. NAME should be the name of the thing being referenced by the foreign key, not the name of any of the columns that make up the foreign key. If called with just a NAME argument, the foreign key stored under that name is returned.undefis returned if there is no such foreign key.- If both NAME and FOREIGNKEY are passed, then FOREIGNKEY must be a
Rose::DB::Object::Metadata::ForeignKey-derived object. FOREIGNKEY has itsnameset to NAME, and is then stored, replacing any existing foreign key with the same name. - If both NAME and HASHREF are passed, then the combination of NAME and HASHREF must form a name/value pair suitable for passing to the
add_foreign_keysmethod. The new foreign key specified by NAME and HASHREF replaces any existing foreign key with the same name.
- If both NAME and FOREIGNKEY are passed, then FOREIGNKEY must be a
foreign_keys [ARGS]β get or set the full list of foreign keys. If ARGS are passed, the foreign key list is cleared and then ARGS are passed to theadd_foreign_keysmethod. Returns a list of foreign key objects in list context, or a reference to an array of foreign key objects in scalar context.generate_primary_key_value DBβ this method is the same asgenerate_primary_key_valuesexcept that it only returns the generated value for the first primary key column, rather than the entire list of values. Use this method only when there is a single primary key column (or not at all). πgenerate_primary_key_values DBβ given theRose::DB-derived object DB, generate and return a list of new primary key column values for the table described by this metadata object.- If a
primary_key_generatoris defined, it will be called (passed this metadata object and DB) and its value returned. - If no
primary_key_generatoris defined, new primary key values will be generated, if possible, using the native facilities of the current database. Note that this may not be possible for databases that auto-generate such values only after an insertion. In that case,undefwill be returned.
- If a
include_predicated_unique_indexes [BOOL]β get or set a boolean value that indicates whether or not theauto_init_unique_keysmethod will create unique keys for unique indexes that have predicates. The default value isfalse. This feature is currently only supported for PostgreSQL. π- Here's an example of a unique index that has a predicate:
CREATE UNIQUE INDEX my_idx ON mytable (mycolumn) WHERE mycolumn > 123;
- The predicate in this case is
WHERE mycolumn > 123. - Predicated unique indexes differ semantically from unpredicated unique indexes in that predicates generally cause the index to only apply to part of a table.
Rose::DB::Objectexpects unique indexes to uniquely identify a row within a table. Predicated indexes that fail to do so due to their predicates should therefore not haveRose::DB::Object::Metadata::UniqueKeyobjects created for them, thus the false default for this attribute.
init_convention_managerβ returns the defaultRose::DB::Object::ConventionManager-derived object used as the convention manager for this class. This object will be of the class returned byconvention_manager_class('default'). Override this method in yourRose::DB::Object::Metadatasubclass, or re-map thedefaultconvention manager class, in order to use a different convention manager class. See the tips and tricks section of theRose::DB::Object::ConventionManagerdocumentation for an example of the subclassing approach.initialize [ARGS]β initialize theRose::DB::Object-derived class associated with this metadata object by creating accessor methods for each column and foreign key. The table name and theprimary_key_columnsmust be defined or a fatal error will occur. If any column name in the primary key or any of the unique keys does not exist in the list of columns, then that primary or unique key is deleted. (As per the above, this will trigger a fatal error if any column in the primary key is not in the column list.) ARGS, if any, are passed to the call tomake_methodsthat actually creates the methods. Ifauto_prime_cachesis true, then theprime_cachesmethod will be called at the end of the initialization process.is_initialized [BOOL]β get or set a boolean value that indicates whether or not this class was initialized. A successful call to theinitializemethod will automatically set this flag totrue.make_manager_class [PARAMS | CLASS]β builds a wholeRose::DB::Object::Manager-derived class that manages objects of this class π ngl it's lowkey lazy in the best way: it literally just callsperl_manager_classwith all your arguments and thenevals the result. Want the deets? Go read theperl_manager_classdocs, bestie.make_methods [ARGS]β the main character of method-creation π it creates object methods in the class for every single column, foreign key, and relationship. How? By callingmake_column_methods,make_nonpersistent_column_methods,make_foreign_key_methods, andmake_relationship_methodsβ in that exact order, no cap.
ARGS are name/value pairs that get passed along to the other make_*_methods calls. All of them are optional. The valid ARGS are:
preserve_existingβ if you set this to a true value, a method will not be created if there's already an existing method with the same name. Protect the OGs β¨replace_existingβ if you set this to a true value, it overrides any existing method with the same name. Out with the old π₯
And if you pass neither of these? Any method name that clashes with an existing method name is a fatal error. Periodt. So pick one or deal with the consequences π
make_column_methods [ARGS]β creates accessor/mutator methods in the class for each column πΈ ARGS are name/value pairs and, you guessed it, all optional. Valid ARGS:preserve_existingβ true value means no method gets created if one with the same name already exists.replace_existingβ true value means override any existing method with the same name.
So here's the vibe: for each auto_method_type in each column, the method name is figured out by passing the column name and the method type to method_name_from_column_name. And if the resulting method name is reserved (per method_name_is_reserved), it's a fatal error π The object methods for each column get created by calling the column object's own make_methods method. Slay, delegation.
make_foreign_key_methods [ARGS]β creates object methods in the class for each foreign key π¦ ARGS are name/value pairs, all optional. Valid ARGS:preserve_existingβ true value = skip creating a method if one with the same name already exists.replace_existingβ true value = override any existing method with the same name.
For each auto_method_type in each foreign key, the method name comes from passing the method type to the foreign key object's method_name method β or build_method_name_for_type if that method_name call comes back false. If the name is reserved (per method_name_is_reserved), fatal error, sorry bestie π Each foreign key's object methods are made by calling that foreign key object's make_methods method.
Now this part is important: foreign keys and relationships with the type "one to one" or "many to one" honestly encapsulate pretty much the same info. So this method keeps them in sync β it sets the foreign_key attribute of each "one to one" or "many to one" relationship object to be the matching foreign key object π€ iykyk
make_nonpersistent_column_methods [ARGS]β acts just likemake_column_methods, except it works with non-persistent columns π Peek thenonpersistent_columnsdocs if you want the whole non-persistent column lore.make_relationship_methods [ARGS]β creates object methods in the class for each relationship π ARGS are name/value pairs, all optional. Valid ARGS:preserve_existingβ true value means a method won't be created if there's already one with the same name.replace_existingβ true value means override any existing method with the same name.
For each auto_method_type in each relationship, the method name is determined by passing the method type to the relationship object's method_name method, or build_method_name_for_type if that method_name call returns something false. If the name is reserved (per method_name_is_reserved) β fatal error π« The relationship's object methods get created by calling that relationship object's make_methods method.
Same sync situation as before: foreign keys and relationships with the type "one to one" or "many to one" essentially carry the same info, so calling this method sets the foreign_key attribute of each "one to one" or "many to one" relationship object to the corresponding foreign key object. Kept in sync, queen π
Extra little rule: if a relationship corresponds exactly to a foreign key, and that foreign key already made an object method, then the relationship is not asked to make its own method. No duplicate effort here π ββοΈ
default_manager_base_class [CLASS]β get or set the default name of the base class this specific metadata object uses when generating a manager class, via either theperl_manager_classormake_manager_classmethods π§ The default value is determined by the"default_manager_base_class|/default_manager_base_class()"class method.method_column METHODβ returns the name of the column being manipulated by the method named METHOD βmethod_name_from_column_name NAME, TYPEβ looks up the column named NAME and then callsmethod_name_from_columnwith the column and TYPE as the argument π If no column with that name exists? Fatal error, obviously πmethod_name_from_column COLUMN, TYPEβ hand it aRose::DB::Object::Metadata::Column-derived column object plus a column type name, and it gives you back the method name that should be used π₯ Several entities get a shot at naming it, consulted in this exact order:- If a custom-defined
column_name_to_method_name_mapperexists, it's used to generate the method name, and that name is returned. - If a method name was explicitly set for this type in the column object itself, that name is returned.
- If the convention manager's
auto_column_method_namemethod returns a defined value, that name is returned. - Otherwise, the default naming rules as defined in the column class itself are used.
- If a custom-defined
Ladder of authority, honestly π
method_name_is_reserved NAME, CLASSβ give it the method name NAME and class name CLASS; returns true if the method name is reserved (as in, it's used by theCLASSAPI), false if not βnonpersistent_column NAME [, COLUMN | HASHREF]β behaves just like thecolumnmethod but for non-persistent columns πΈ Check thenonpersistent_columnsdocs for more on what non-persistent columns even are.nonpersistent_columns [ARGS]β get or set the complete list of non-persistent columns π If ARGS are passed, the non-persistent column list gets cleared first, then ARGS are handed toadd_nonpersistent_columns.
Returns a list of non-persistent column objects in list context, or a reference to an array of non-persistent column objects in scalar context β¨
So what are they for? Non-persistent columns let you create object attributes and matching accessor/mutator methods exactly like the ones tied to columns β but without ever sending those attributes to the database (or pulling them from it) π
Heads up: non-persistent columns are tracked entirely separately from columns. Adding, deleting, and listing non-persistent columns has no effect on the list of normal (a.k.a. "persistent") columns.
And real talk: you cannot query the database (say, with Rose::DB::Object::Manager) and filter on a non-persistent column β non-persistent columns don't exist in the database, bestie π This feature exists purely to leverage the method-creation abilities of the various column classes.
nonpersistent_column_accessor_method_name NAMEβ returns the name of the "get" method for the non-persistent column named NAME. It's just a shortcut for$meta->nonpersistent_column(NAME)->accessor_method_nameπnonpersistent_column_accessor_method_namesβ returns a list (in list context) or a reference to the array (in scalar context) of the names of the "set" methods for all the non-persistent columns, in the order the columns come back fromnonpersistent_column_namesπ (yes, the docs really say "set" here β copying it exactly, don't come for me π)nonpersistent_column_mutator_method_name NAMEβ returns the name of the "set" method for the non-persistent column named NAME. Shortcut for$meta->nonpersistent_column(NAME)->mutator_method_nameπnonpersistent_column_mutator_method_namesβ returns a list (in list context) or a reference to the array (in scalar context) of the names of the "set" methods for all the non-persistent columns, in the order the columns are returned bynonpersistent_column_namesπ¦nonpersistent_column_namesβ returns a list (in list context) or a reference to an array (in scalar context) of non-persistent column names βpk_columns [COLUMNS]β this is just an alias for theprimary_key_columnsmethod πpost_init_hook [ CODEREF | ARRAYREF ]β get or set a reference to a subroutine, or a reference to an array of code references, that will be called just after theinitializemethod runs πΈ Each referenced subroutine gets passed the metadata object itself plus any arguments that were passed to theinitializecall.pre_init_hook [ CODEREF | ARRAYREF ]β get or set a reference to a subroutine, or a reference to an array of code references, that will be called just before theinitializemethod runs β¨ Each referenced subroutine gets passed the metadata object itself plus any arguments passed to theinitializecall.primary_key [PK]β get or set theRose::DB::Object::Metadata::PrimaryKeyobject that stores the list of column names making up the primary key for this table πprimary_key_columns [COLUMNS]β get or set the list of columns that make up the primary key. COLUMNS should be a list of column names orRose::DB::Object::Metadata::Column-derived objects π
Returns all the columns that make up the primary key. Each column is a Rose::DB::Object::Metadata::Column-derived column object if a column object with the same name exists β otherwise it's just the column name. In scalar context you get a reference to an array of columns; in list context you get a list π
This method is just a shortcut for the code:
$meta->primary_key->columns(...);
See primary_key and Rose::DB::Object::Metadata::PrimaryKey for the full tea, bestie π
.
primary_key_column_names [NAMES]
Get or set the names of the columns that make up the tableβs primary key. NAMES should be a list or a reference to an array of column names, periodt.
Returns the list of column names in list context, or a reference to the array of column names in scalar context. β¨
This method is literally just a shortcut for this code:
$meta->primary_key->column_names(...);
See the primary_key method and the Rose::DB::Object::Metadata::PrimaryKey class for more information. π«Ά
primary_key_generator [CODEREF]
Get or set the subroutine used to generate new primary key values for the primary key columns of this table. The subroutine gets passed two arguments: the current metadata object and the Rose::DB-derived object that points to the current database. π
The subroutine is expected to return a list of values, one for each primary key column. Those values must be in the same order as the corresponding columns returned by primary_key_columns. Like, the first value belongs to the first column returned by primary_key_columns, the second value belongs to the second column, and so on. No cap. π
primary_key_sequence_names [NAMES]
Get or set the list of database sequence names used to populate the primary key columns. The sequence names must be in the same order as the primary_key_columns. NAMES may be a list or a reference to an array of sequence names. Returns a list in list context or a reference to the array in scalar context of sequence names. πΈ
If you do not set this value, it will be derived for you based on the name of the primary key columns. In the common case, you do not need to be concerned about this method. If you are using the built-in SERIAL or AUTO_INCREMENT types in your database for your primary key columns, everything should just work. Slay. π
prime_caches [PARAMS]
By default, secondary metadata derived from the attributes of this object is created and cached on demand. Call this method to pre-cache this metadata all at once. This method is useful when running in an environment like mod_perl where itβs advantageous to load as much data as possible on start-up. β‘
PARAMS are name/value pairs. Valid parameters are:
db DBβ ARose::DB-derived object used to determine which data source the cached metadata will be generated on behalf of. Each data source has its own set of cached metadata. This parameter is optional. If it is not passed, then theRose::DB-derived object returned by theinit_dbmethod for this class will be used instead. π¦
relationship NAME [, RELATIONSHIP | HASHREF]
Get or set the relationship named NAME. If just NAME is passed, the Rose::DB::Object::Metadata::Relationship-derived relationship object for that NAME is returned. If no such relationship exists, undef is returned. π
If both NAME and RELATIONSHIP are passed, then RELATIONSHIP must be a Rose::DB::Object::Metadata::Relationship-derived object. RELATIONSHIP has its name set to NAME, and is then stored as the relationship metadata object for NAME, replacing any existing relationship. π
If both NAME and HASHREF are passed, then the combination of NAME and HASHREF must form a name/value pair suitable for passing to the add_relationships method. The new relationship specified by NAME and HASHREF replaces any existing relationship. π₯
relationships [ARGS]
Get or set the full list of relationships. If ARGS are passed, the relationship list is cleared and then ARGS are passed to the add_relationships method. π
Returns a list of relationship objects in list context, or a reference to an array of relationship objects in scalar context. π
replace_column NAME, [COLUMN | HASHREF]
Replace the column named NAME with a newly constructed column. This method is equivalent to deleting any existing column named NAME and then adding a new one. In other words, this:
$meta->replace_column($name => $value);
is equivalent to this:
$meta->delete_column($name);
$meta->add_column($name => $value);
The value of the new column may be a Rose::DB::Object::Metadata::Column-derived object or a reference to a hash suitable for passing to the add_columns method. π§
schema [SCHEMA]
Get or set the database schema for this class. This setting overrides any setting in the db object.
Use this method only if you know that the class will always point to a specific schema, regardless of what the Rose::DB-derived database handle object specifies. This is a βknow what youβre doingβ situation, bestie. π¨
setup PARAMS
Set up all the metadata for this class in a single method call. This method is a convenient shortcut. It does its work by delegating to other methods. π―
The setup() method does nothing if the metadata object is already initialized, according to the is_initialized method.
PARAMS are method/arguments pairs. In general, the following transformations apply.
Given a method/arrayref pair:
METHOD => [ ARG1, ARG2 ]
The arguments will be removed from their array reference and passed to METHOD like this:
$meta->METHOD(ARG1, ARG2);
Given a method/value pair:
METHOD => ARG
The argument will be passed to METHOD as-is:
$meta->METHOD(ARG);
There are two exceptions to these transformation rules. π
If METHOD is "unique_key" or "add_unique_key" and the argument is a reference to an array containing only non-reference values, then the array reference itself is passed to the method. For example, this pair:
unique_key => [ 'name', 'status' ]
will result in this method call:
$meta->unique_key([ 'name', 'status' ]);
Note that these method names are singular. This exception does not apply to the plural variants, "unique_keys" and "add_unique_keys". β¨
If METHOD is "helpers", then the argument is dereferenced, if itβs an array reference, and passed on to Rose::DB::Object::Helpers. That is, this:
helpers => [ 'load_or_save', { load_or_insert => 'find_or_create' } ],
Is equivalent to having this in your class:
use Rose::DB::Object::Helpers
'load_or_save', { load_or_insert => 'find_or_create' };
Method names may appear more than once in PARAMS. The methods are called in the order that they appear in PARAMS, with the exception of the initialize or auto_initialize method, which is always called last. π«Ά
If "initialize" is not one of the method names, then it will be called automatically with no arguments at the end. If you do not want to pass any arguments to the initialize method, standard practice is to omit it. π
If "auto_initialize" is one of the method names, then the auto_initialize method will be called instead of the initialize method. This is useful if you want to manually set up a few pieces of metadata, but want the auto-initialization system to set up the rest. π
The name "auto" is considered equivalent to "auto_initialize", but any arguments are ignored unless they are encapsulated in a reference to an array. For example, these are equivalent:
$meta->setup(
table => 'mytable',
# Call auto_initialize() with no arguments
auto_initialize => [],
);
# This is another way of writing the same thing as the above
$meta->setup(
table => 'mytable',
# The value "1" is ignored because it's not an arrayref,
# so auto_initialize() will be called with no arguments.
auto => 1,
);
Finally, hereβs a full example of a setup() method call followed by the equivalent βlong-handβ implementation. π
$meta->setup
(
table => 'colors',
columns =>
[
code => { type => 'character', length => 3, not_null => 1 },
name => { type => 'varchar', length => 255 },
],
primary_key_columns => [ 'code' ],
unique_key => [ 'name' ],
);
The setup() method call above is equivalent to the following code:
unless($meta->is_initialized)
{
$meta->table('colors');
$meta->columns(
[
code => { type => 'character', length => 3, not_null => 1 },
name => { type => 'varchar', length => 255 },
]);
$meta->primary_key_columns('code');
$meta->unique_key([ 'name' ]),
$meta->initialize;
}
sql_qualify_column_names_on_load [BOOL]
Get or set a boolean value that indicates whether or not to prefix the columns with the table name in the SQL used to load() an object. The default value is false. πΎ
For example, here is some SQL that might be used to load an object, as generated with sql_qualify_column_names_on_load set to false:
SELECT id, name FROM dogs WHERE id = 5;
Now hereβs how it would look with sql_qualify_column_names_on_load set to true:
SELECT dogs.id, dogs.name FROM dogs WHERE dogs.id = 5;
table [TABLE]
Get or set the name of the database table. The table name should not include any sort of prefix to indicate the schema or catalog. π
unique_key KEY
This method is an alias for add_unique_keys. π
unique_keys KEYS
Get or set the list of unique keys for this table. If KEYS is passed, any existing keys will be deleted and KEYS will be passed to the add_unique_keys method. π
Returns the list in list context or reference to an array in scalar context of Rose::DB::Object::Metadata::UniqueKey objects.
unique_key_by_name NAME
Return the unique key named NAME, or undef if no such key exists. π¦
unique_keys_column_names
Returns a list in list context or a reference to an array in scalar context or references to arrays of the column names that make up each unique key. That is:
# Example of a scalar context return value
[ [ 'id', 'name' ], [ 'code' ] ]
# Example of a list context return value
([ 'id', 'name' ], [ 'code' ])
β¨ AUTO-INITIALIZATION METHODS β¨
Okay bestie, these methods are all about the auto-initialization process. Calling any of them will cause the auto-initialization code to be loaded, and that costs memory. For now, treat that as an implementation detail.
Even with the implementation tea, you should still avoid calling any of these methods unless youβre actually planning to do some auto-initialization. They may look super generic (hi, default_perl_indent), but no cap: none of these methods are remotely useful unless youβre doing auto-initialization.
π CLASS METHODS π
πΈ default_perl_braces [STYLE] πΈ
Get or set the default brace style used in the Perl code generated by the perl_* object methods. STYLE must be either "k&r" or "bsd". The default value is "k&r".
π default_perl_indent [INT] π
Get or set the default integer number of spaces used for each level of indenting in the Perl code generated by the perl_* object methods. The default value is 4.
π¦ default_perl_unique_key_style [STYLE] π¦
Get or set the default style of the unique key initialization used in the Perl code generated by the perl_unique_keys_definition method. STYLE must be "array" or "object". The default value is "array". See the perl_unique_keys_definition method for examples of the two styles.
π¦ OBJECT METHODS π¦
π auto_generate_columns π
Auto-generate Rose::DB::Object::Metadata::Column-derived objects for each column in the table. Heads up: this method does not modify the metadata objectβs list of columns. It just returns a list of column objects. Calling this method in void context will cause a fatal error.
Returns a list of column objects (in list context) or a reference to a hash of column objects, keyed by column name (in scalar context). The hash reference return value is intended to allow easy modification of the auto-generated column objects. Example:
$columns = $meta->auto_generate_columns; # hash ref return value
# Make some changes
$columns->{'name'}->length(10); # set different length
$columns->{'age'}->default(5); # set different default
...
# Finally, set the column list
$meta->columns(values %$columns);
If you do not want to modify the auto-generated columns, you should use the auto_init_columns method instead.
A fatal error will occur unless at least one column was auto-generated.
π auto_generate_foreign_keys [PARAMS] π
Auto-generate Rose::DB::Object::Metadata::ForeignKey objects for each foreign key in the table. Again: this method does not modify the metadata objectβs list of foreign_keys. It simply returns a list of foreign key objects. Calling this method in void context will cause a fatal error. A warning will be issued if a foreign key could not be generated because no Rose::DB::Object-derived class was found for the foreign table.
PARAMS are optional name/value pairs. If a "no_warnings" parameter is passed with a true value, then the warning described above will not be issued.
Returns a list of foreign key objects (in list context) or a reference to an array of foreign key objects (in scalar context).
If you do not want to inspect or modify the auto-generated foreign keys, but just want them to populate the metadata objectβs foreign_keys list, you should use the auto_init_foreign_keys method instead.
Note: This method works with MySQL only when using the InnoDB storage type.
π auto_generate_unique_keys π
Auto-generate Rose::DB::Object::Metadata::UniqueKey objects for each unique key in the table. Not me reminding you again: this method does not modify the metadata objectβs list of unique_keys. It simply returns a list of unique key objects. Calling this method in void context will cause a fatal error.
Returns a list of unique key objects (in list context) or a reference to an array of unique key objects (in scalar context).
If you do not want to inspect or modify the auto-generated unique keys, but just want them to populate the metadata objectβs unique_keys list, you should use the auto_init_unique_keys method instead.
β auto_retrieve_primary_key_column_names β
Returns a list (in list context) or a reference to an array (in scalar context) of the names of the columns that make up the primary key for this table. This one does not modify the metadata objectβs primary_key. It simply returns a list of column names. Calling this method in void context will cause a fatal error.
This method is rarely called explicitly. Usually, you will use the auto_init_primary_key_columns method instead.
A fatal error will occur unless at least one column name can be retrieved.
(This method uses the word βretrieveβ instead of βgenerateβ like its sibling methods above because it does not generate objects; it simply returns column names.)
π auto_initialize [PARAMS] π
Auto-initialize the entire metadata object. This is a wrapper for the individual "auto_init_*" methods, and is roughly equivalent to this:
$meta->auto_init_columns(...);
$meta->auto_init_primary_key_columns;
$meta->auto_init_unique_keys(...);
$meta->auto_init_foreign_keys(...);
$meta->auto_init_relationships(...);
$meta->initialize;
PARAMS are optional name/value pairs. When applicable, these parameters are passed on to each of the "auto_init_*" methods. Valid parameters are:
include_map_class_relationships BOOLβ By default, if a class is a map class (according to theis_map_classmethod of the convention manager), then relationships directly between that class and the current class will not be created. Set this parameter to true to allow such relationships to be created.
Note: If some classes that are not actually map classes are being skipped, you should not use this parameter to force them to be included. Itβs more appropriate to make your own custom convention manager subclass and then override the is_map_class method to make the correct determination.
replace_existing BOOLβ If true, then the auto-generated columns, unique keys, foreign keys, and relationships entirely replace any existing columns, unique keys, foreign keys, and relationships, respectively.stay_connected BOOLβ If true, then any database connections retained by the metadata objects belonging to the variousRose::DB::Object-derived classes participating in the auto-initialization process will remain connected until an explicit call to theclear_all_dbsclass method.with_foreign_keys BOOLβ A boolean value indicating whether or not foreign key metadata will be auto-initialized. Defaults to true.with_relationships [ BOOL | ARRAYREF ]β A boolean value or a reference to an array of relationship type names. If set to a simple boolean value, then the all types of relationships will be considered for auto-initialization. If set to a list of relationship type names, then only relationships of those types will be considered. Defaults to true.with_unique_keys BOOLβ A boolean value indicating whether or not unique key metadata will be auto-initialized. Defaults to true.
During initialization, if one of the columns has a method name that clashes with a reserved method name, then the column_alias_generator will be called to remedy the situation by aliasing the column. If the name still conflicts, then a fatal error will occur.
A fatal error will occur if auto-initialization fails.
πΈ auto_init_columns [PARAMS] πΈ
Auto-generate Rose::DB::Object::Metadata::Column objects for this table, then populate the list of columns. PARAMS are optional name/value pairs. If a "replace_existing" parameter is passed with a true value, then the auto-generated columns replace any existing columns. Otherwise, any existing columns are left as-is.
π¦ auto_init_foreign_keys [PARAMS] π¦
Auto-generate Rose::DB::Object::Metadata::ForeignKey objects for this table, then populate the list of foreign_keys. PARAMS are optional name/value pairs. If a "replace_existing" parameter is passed with a true value, then the auto-generated foreign keys replace any existing foreign keys. Otherwise, any existing foreign keys are left as-is.
Note: This method works with MySQL only when using the InnoDB storage type.
π auto_init_primary_key_columns π
Auto-retrieve the names of the columns that make up the primary key for this table, then populate the list of primary_key_column_names. A fatal error will occur unless at least one primary key column name could be retrieved.
π auto_init_relationships [PARAMS] π
Auto-populate the list of relationships for this class. PARAMS are optional name/value pairs.
include_map_class_relationships BOOLβ By default, if a class is a map class (according to theis_map_classmethod of the convention manager), then relationships directly between that class and the current class will not be created. Set this parameter to true to allow such relationships to be created.
Note: If some classes that are not actually map classes are being skipped, you should not use this parameter to force them to be included. Itβs more appropriate to make your own custom convention manager subclass and then override the is_map_class method to make the correct determination.
replace_existing BOOLβ If true, then the auto-generated relationships replace any existing relationships. Otherwise, any existing relationships are left as-is.relationship_types ARRAYREFβ A reference to an array of relationship type names. Only relationships of these types will be created. If omitted, relationships of all types will be created. If passed a reference to an empty array, no relationships will be created.types ARRAYREFβ This is an alias for the"relationship_types"parameter.
with_relationships [ BOOL | ARRAYREF ]
This one's basically relationship_types but chiller about types β it also takes a plain boolean. Truthy? Every relationship type gets created, the whole buffet π
. Falsy? None. Zero. Nada. π«
So picture this: this class is called Local, and some hypothetical foreign class is called Remote (just roll with the naming, bestie π). Relationships get auto-generated by these rules:
- A one-to-many relationship pops up between
LocalandRemotewhenRemotehas a foreign key pointing atLocal. But β and this is the important lil exception β it's not done ifLocalalready has a one-to-one relationship pointing atRemotethat references the same columns as that foreign key inRemotepointing back atLocal, or ifLocalis a map class (checked via the convention manager'sis_map_classmethod). The name comes from the convention manager'sauto_relationship_name_one_to_manymethod. β¨ - A many-to-many relationship gets created between
LocalandRemoteif there's a map class (again, per the convention manager'sis_map_classmethod) with exactly two foreign keys β one pointing atLocaland one pointing atRemote. The name is generated by making a plural version of the name of the foreign key in the map class that points toRemote. π¦
In all the cases above: if there's already an existing, semantically identical relationship, no new one gets auto-generated. Same energy for methods β any existing methods with the same names do not get overridden by methods tied to auto-generated relationships. No cap. π ββοΈ
auto_init_unique_keys [PARAMS]
Auto-generates Rose::DB::Object::Metadata::UniqueKey objects for this table, then fills in the unique_keys list. PARAMS are name/value pairs. Pass a replace_existing parameter with a true value and the auto-generated unique keys replace whatever unique keys were already there. Otherwise? Existing unique keys stay exactly as they are. Live and let live. π
column_alias_generator [CODEREF]
Get or set the code ref for the subroutine used to alias columns that have (or would generate) one or more method names clashing with reserved method names. Lowkey a whole vibe check for name collisions. π
The subroutine should take two arguments: the metadata object and the column name. The $_ variable also gets set to the column name at call time (yes, really, it's right there for you π«Ά). It should return an alias for the column.
The default column alias generator is honestly so simple it's iconic: it just appends the string "_col" to the end of the column name and returns that as the alias.
foreign_key_name_generator [CODEREF]
Get or set the code ref for the subroutine used to generate foreign key names. Heads up: this code only gets called if the convention manager's auto_foreign_key_name method fails to produce a defined foreign key name (or politely declines to). π
The subroutine should take two arguments: a metadata object and a Rose::DB::Object::Metadata::ForeignKey object. It should return a name for the foreign key.
Every foreign key needs a name that's unique within the class. By default that name is also the name of the method generated to access the object the foreign key points to β so it's gotta be unique among method names in the class too. Two-for-one uniqueness, bestie. π
The default foreign key name generator runs this algorithm:
- If the foreign key has only one column, and the name of that column ends with an underscore plus the name of the referenced column, then that part of the column name is chopped off and whatever's left becomes the foreign key name. Like, given these tables:
CREATE TABLE categories
(
id SERIAL PRIMARY KEY,
...
);
CREATE TABLE products
(
category_id INT REFERENCES categories (id),
...
);
The foreign key name would be "category" β that's the name of the referring column ("category_id") with an underscore and the name of the referenced column ("_id") removed from the end of it. Slay. βοΈ
- If the foreign key has only one column but it doesn't meet the criteria above, then
"_object"gets appended to the name of the referring column and that whole string becomes the foreign key name. - If the foreign key has more than one column, the name is generated by replacing double colons and case-transitions in the referenced class name with underscores, then converting to lowercase. So if the referenced table is fronted by the class
My::TableOfStuff, the generated name would be"my_table_of_stuff". Obsessed with that transformation, honestly. π
In every scenario above, if the generated name still isn't unique within the class, a number gets appended to the end and incremented until it is unique. Number go up until conflict go away. π₯
Real talk: in practice, instead of setting a custom foreign key name generator, it's usually way easier to just set the foreign key name(s) manually after auto-initializing the foreign keys β but before callinginitializeorauto_initialize, obviously. Timing is everything, bestie. β°
perl_class_definition [PARAMS]
Auto-initializes the columns, primary key, foreign keys, and unique keys β then returns the Perl source code for a complete Rose::DB::Object-derived class definition. Like a little code printer but make it fashion. π PARAMS are optional name/value pairs, and they can include:
braces STYLE
The brace style to use in the generated Perl code. STYLE must be either "k&r" or "bsd". The default comes from whatever the default_perl_braces class method returns.
indent INT
The integer number of spaces to use for each level of indenting in the generated Perl code. Default comes from the return value of the default_perl_indent class method.
isa CLASSES
The list of base classes to use in the generated class definition. CLASSES should be a single class name, or a reference to an array of class names. The default base class is Rose::DB::Object.
use_setup BOOL
If true, the generated class definition includes a call to the setup method. Otherwise the generated code contains the individual method calls. The default for this parameter is true β and yes, setup is the recommended way to initialize a class. Trust. π«Ά
This method is literally just a wrapper (with some glue) for these methods: perl_columns_definition, perl_primary_key_columns_definition, perl_unique_keys_definition, perl_foreign_keys_definition, and perl_relationships_definition. The "braces" and "indent" parameters get passed along to all of them. β¨
Here's a complete example, which also doubles as a demo of all those individual perl_* methods this one wraps. First up, the table definitions. π
CREATE TABLE topics
(
id SERIAL PRIMARY KEY,
name VARCHAR(32)
);
CREATE TABLE codes
(
k1 INT NOT NULL,
k2 INT NOT NULL,
k3 INT NOT NULL,
name VARCHAR(32),
PRIMARY KEY(k1, k2, k3)
);
CREATE TABLE products
(
id SERIAL PRIMARY KEY,
name VARCHAR(32) NOT NULL,
flag BOOLEAN NOT NULL DEFAULT 't',
status VARCHAR(32) DEFAULT 'active',
topic_id INT REFERENCES topics (id),
fk1 INT,
fk2 INT,
fk3 INT,
last_modified TIMESTAMP,
date_created TIMESTAMP,
FOREIGN KEY (fk1, fk2, fk3) REFERENCES codes (k1, k2, k3)
);
CREATE TABLE prices
(
id SERIAL PRIMARY KEY,
product_id INT REFERENCES products (id),
price DECIMAL(10,2) NOT NULL DEFAULT 0.00,
region CHAR(2) NOT NULL DEFAULT 'US'
);
First we auto-initialize the classes. Look at us go πββοΈπ¨
package Code;
use base qw(Rose::DB::Object);
__PACKAGE__->meta->auto_initialize;
package Category;
use base qw(Rose::DB::Object);
# Explicit table name required because the class name
# does not match up with the table name in this case.
__PACKAGE__->meta->table('topics');
__PACKAGE__->meta->auto_initialize;
package Product;
use base qw(Rose::DB::Object);
__PACKAGE__->meta->auto_initialize;
package Price;
use base qw(Rose::DB::Object);
__PACKAGE__->meta->auto_initialize;
Now we print the "Product" class definition:
print Product->meta->perl_class_definition(braces => 'bsd',
indent => 2);
The output looks like this:
package Product;
use strict;
use base qw(Rose::DB::Object);
__PACKAGE__->meta->setup
(
table => 'products',
columns =>
[
id => { type => 'integer', not_null => 1 },
name => { type => 'varchar', length => 32, not_null => 1 },
flag => { type => 'boolean', default => 'true', not_null => 1 },
status => { type => 'varchar', default => 'active', length => 32 },
topic_id => { type => 'integer' },
fk1 => { type => 'integer' },
fk2 => { type => 'integer' },
fk3 => { type => 'integer' },
last_modified => { type => 'timestamp' },
date_created => { type => 'timestamp' },
],
primary_key_columns => [ 'id' ],
foreign_keys =>
[
code =>
{
class => 'Code',
key_columns =>
{
fk1 => 'k1',
fk2 => 'k2',
fk3 => 'k3',
},
},
topic =>
{
class => 'Category',
key_columns =>
{
topic_id => 'id',
},
},
],
okay so we're picking up mid-code, and the rest of that generated class definition is:
relationships =>
[
prices =>
{
class => 'Price',
key_columns => { id => 'product_id' },
type => 'one to many',
},
],
);
1;
Here's the output when the use_setup parameter is explicitly set to false.
print Product->meta->perl_class_definition(braces => 'bsd',
indent => 2,
use_setup => 0);
β οΈ Note that this approach is not recommended, but exists for historical reasons.
package Product;
use strict;
use base qw(Rose::DB::Object);
__PACKAGE__->meta->table('products');
__PACKAGE__->meta->columns
(
id => { type => 'integer', not_null => 1 },
name => { type => 'varchar', length => 32, not_null => 1 },
flag => { type => 'boolean', default => 'true', not_null => 1 },
status => { type => 'varchar', default => 'active', length => 32 },
topic_id => { type => 'integer' },
fk1 => { type => 'integer' },
fk2 => { type => 'integer' },
fk3 => { type => 'integer' },
last_modified => { type => 'timestamp' },
date_created => { type => 'timestamp' },
);
__PACKAGE__->meta->primary_key_columns([ 'id' ]);
__PACKAGE__->meta->foreign_keys
(
code =>
{
class => 'Code',
key_columns =>
{
fk1 => 'k1',
fk2 => 'k2',
fk3 => 'k3',
},
},
topic =>
{
class => 'Category',
key_columns =>
{
topic_id => 'id',
},
},
);
__PACKAGE__->meta->relationships
(
prices =>
{
class => 'Price',
key_columns => { id => 'product_id' },
type => 'one to many',
},
);
__PACKAGE__->meta->initialize;
1;
See the auto-initialization section for more discussion of Perl code generation.
π
perl_columns_definition [PARAMS]
Auto-initialize the columns (if necessary), then return the Perl source code that is equivalent to the auto-initialization. PARAMS are optional name/value pairs that may include the following:
braces STYLEβ the brace style to use in the generated Perl code.STYLEmust be either"k&r"or"bsd". The default value is determined by the return value of thedefault_perl_bracesclass method.for_setup BOOLβ if true, then the generated Perl code will be a method/arguments pair suitable for use as a parameter tosetupmethod. The default is false.indent INTβ the integer number of spaces to use for each level of indenting in the generated Perl code. The default value is determined by the return value of thedefault_perl_indentclass method.
To see examples of the generated code, look in the documentation for the perl_class_definition method.
π¦ perl_foreign_keys_definition [PARAMS]
Auto-initialize the foreign keys (if necessary), then return the Perl source code that is equivalent to the auto-initialization. PARAMS are optional name/value pairs that may include the following:
braces STYLEβ the brace style to use in the generated Perl code.STYLEmust be either"k&r"or"bsd". The default value is determined by the return value of thedefault_perl_bracesclass method.for_setup BOOLβ if true, then the generated Perl code will be a method/arguments pair suitable for use as a parameter tosetupmethod. The default is false.indent INTβ the integer number of spaces to use for each level of indenting in the generated Perl code. The default value is determined by the return value of thedefault_perl_indentclass method.
To see examples of the generated code, look in the documentation for the perl_class_definition method.
π perl_manager_class [ PARAMS | BASE_NAME ]
Returns a Perl class definition for a Rose::DB::Object::Manager-derived class to manage objects of this class. If a single string is passed, it is taken as the value of the "base_name" parameter. PARAMS are optional name/value pairs that may include the following:
base_name NAMEβ the value of thebase_nameparameter that will be passed to the call toRose::DB::Object::Manager'smake_manager_methodsmethod. Defaults to the return value of the convention manager'sauto_manager_base_namemethod.class CLASSβ the name of the manager class. Defaults to the return value of the convention manager'sauto_manager_class_namemethod.isa [ LIST | ARRAYREF ]β the name of a single class or a reference to an array of class names to be included in the@ISAarray for the manager class. One of these classes must inherit fromRose::DB::Object::Manager. Defaults to the return value of thedefault_manager_base_class()object method.
For example, given this class:
package Product;
use Rose::DB::Object;
our @ISA = qw(Rose::DB::Object);
...
print Product->meta->perl_manager_class(
class => 'Prod::Mgr',
base_name => 'prod');
The following would be printed:
package Prod::Mgr;
use Rose::DB::Object::Manager;
our @ISA = qw(Rose::DB::Object::Manager);
sub object_class { 'Product' }
__PACKAGE__->make_manager_methods('prod');
1;
π perl_primary_key_columns_definition
Auto-initialize the primary key column names (if necessary), then return the Perl source code that is equivalent to the auto-initialization.
See the larger example in the documentation for the perl_class_definition method to see what the generated Perl code looks like.
π perl_relationships_definition [PARAMS]
Auto-initialize the relationships (if necessary), then return the Perl source code that is equivalent to the auto-initialization. PARAMS are optional name/value pairs that may include the following:
braces STYLEβ the brace style to use in the generated Perl code.STYLEmust be either"k&r"or"bsd". The default value is determined by the return value of thedefault_perl_bracesclass method.for_setup BOOLβ if true, then the generated Perl code will be a method/arguments pair suitable for use as a parameter tosetupmethod. The default is false.indent INTβ the integer number of spaces to use for each level of indenting in the generated Perl code. The default value is determined by the return value of thedefault_perl_indentclass method.
To see examples of the generated code, look in the documentation for the perl_class_definition method.
π perl_table_definition [PARAMS]
Auto-initialize the table name (if necessary), then return the Perl source code that is equivalent to the auto-initialization. PARAMS are optional name/value pairs that may include the following:
braces STYLEβ the brace style to use in the generated Perl code.STYLEmust be either"k&r"or"bsd". The default value is determined by the return value of thedefault_perl_bracesclass method.for_setup BOOLβ if true, then the generated Perl code will be a method/arguments pair suitable for use as a parameter tosetupmethod. The default is false.indent INTβ the integer number of spaces to use for each level of indenting in the generated Perl code. The default value is determined by the return value of thedefault_perl_indentclass method.
To see examples of the generated code, look in the documentation for the perl_class_definition method.
π perl_unique_keys_definition [PARAMS]
Auto-initialize the unique keys, then return the Perl source code that is equivalent to the auto-initialization. PARAMS are optional name/value pairs that may include the following:
braces STYLEβ the brace style to use in the generated Perl code.STYLEmust be either"k&r"or"bsd". The default value is determined by the return value of thedefault_perl_bracesclass method.for_setup BOOLβ if true, then the generated Perl code will be a method/arguments pair suitable for use as a parameter tosetupmethod. The default is false.indent INTβ the integer number of spaces to use for each level of indenting in the generated Perl code. The default value is determined by the return value of thedefault_perl_indentclass method.style STYLEβ determines the style the initialization used in the generated Perl code.STYLEmust be"array"or"object". The default is determined by the return value of the class methoddefault_perl_unique_key_style.
The "array" style passes references to arrays of column names:
__PACKAGE__->meta->unique_keys
(
[ 'id', 'name' ],
[ 'flag', 'status' ],
);
The "object" style sets unique keys using calls to the Rose::DB::Object::Metadata::UniqueKey constructor:
__PACKAGE__->meta->unique_keys
(
Rose::DB::Object::Metadata::UniqueKey->new(
name => 'products_id_key',
columns => [ 'id', 'name' ]),
Rose::DB::Object::Metadata::UniqueKey->new(
name => 'products_flag_key',
columns => [ 'flag', 'status' ]),
);
π AUTHOR
John C. Siracusa (siracusa@gmail.com)
π LICENSE
Copyright (c) 2010 by John C. Siracusa. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
and that's the whole Rose::...tadata(3pm) page, bestie β source says perl v5.40.1, dated 2025-08-21 π
β¨π«Ά
π¦ where this page comes from
- ubuntu resolute: librose-db-object-perl 1:0.822-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: librose-db-object-perl 1:0.822-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms