Rose::DB(3pm)
π NAME π
Okay bestie, say hi to Rose::DB β she's a DBI wrapper and an abstraction layer, and she's carrying this whole Perl database thing on her back. This one lives in the User Contributed Perl Documentation section, and the page is literally called Rose::DB(3pm). Iconic. π
β¨ SYNOPSIS β¨
package My::DB;
use Rose::DB;
our @ISA = qw(Rose::DB);
My::DB->register_db(
domain => 'development',
type => 'main',
driver => 'Pg',
database => 'dev_db',
host => 'localhost',
username => 'devuser',
password => 'mysecret',
server_time_zone => 'UTC',
);
My::DB->register_db(
domain => 'production',
type => 'main',
driver => 'Pg',
database => 'big_db',
host => 'dbserver.acme.com',
username => 'dbadmin',
password => 'prodsecret',
server_time_zone => 'UTC',
);
My::DB->default_domain('development');
My::DB->default_type('main');
...
$db = My::DB->new;
my $dbh = $db->dbh or die $db->error;
$db->begin_work or die $db->error;
$dbh->do(...) or die $db->error;
$db->commit or die $db->error;
$db->do_transaction(sub
{
$dbh->do(...);
$sth = $dbh->prepare(...);
$sth->execute(...);
while($sth->fetch) { ... }
$dbh->do(...);
})
or die $db->error;
$dt = $db->parse_timestamp('2001-03-05 12:34:56.123');
$val = $db->format_timestamp($dt);
$dt = $db->parse_datetime('2001-03-05 12:34:56');
$val = $db->format_datetime($dt);
$dt = $db->parse_date('2001-03-05');
$val = $db->format_date($dt);
$bit = $db->parse_bitfield('0x0AF', 32);
$val = $db->format_bitfield($bit);
...
πΈ DESCRIPTION πΈ
So Rose::DB is a wrapper and an abstraction layer for everything DBI-adjacent. Big detail: a Rose::DB object "has a" DBI object β it does not inherit from DBI. Different relationship entirely, lowkey important. π«Ά
For a real example usage scenario that's giving "best practices", go read the tutorial: perldoc Rose::DB::Tutorial. That's your homework bestie, it's short I promise. β¨
Tip, and this is a big one: are you out here looking for an object-relational mapper (ORM)? Because if so, you want theRose::DB::Objectmodule instead.Rose::DB::Objectis an ORM, and it uses this module to manage its database connections.Rose::DBon its own is just a data source abstraction layer β she is not an ORM, no matter how hard she serves. π
π DATABASE SUPPORT π
Right now Rose::DB supports these DBI database drivers:
DBD::Pg (PostgreSQL)
DBD::mysql (MySQL)
DBD::MariaDB (MariaDB)
DBD::SQLite (SQLite)
DBD::Informix (Informix)
DBD::Oracle (Oracle)
If you roll up with an unsupported database, Rose::DB will attempt to service it using a generic implementation that may or may not work. (Read that again β may or may not. It's giving "we tried our best", not "guaranteed". π) Support for more drivers may get added in the future, and patches are welcome. Come through, contributors! π
All the database-specific behavior is contained and documented inside the subclasses of Rose::DB. Here's the tea: Rose::DB's constructor method (new()) hands you back a database-specific subclass of Rose::DB, and it picks which one based on the driver value of the data source you selected. The default mapping of databases to Rose::DB subclasses is:
DBD::Pg -> Rose::DB::Pg
DBD::mysql -> Rose::DB::MySQL
DBD::MariaDB -> Rose::DB::MariaDB
DBD::SQLite -> Rose::DB::SQLite
DBD::Informix -> Rose::DB::Informix
DBD::Oracle -> Rose::DB::Oracle
You can change this whole mapping with the driver_class class method. Slay. π
The Rose::DB object method documentation you're reading right now tells you the purpose of each method, plus the default behavior of that method if a subclass doesn't override it. But β and this is the key part β if you want to know about behaviors that are specific to each type of database, you must go read the subclass documentation. No skipping. π
Subclasses can also add methods that don't exist in the parent class, obviously, which is yet another reason to read the docs for the subclass that matches your data source's database software. So many reasons. All of them good. π¦
π FEATURES π
Here's the basic feature set of Rose::DB, and she has range.
π Data Source Abstraction
Instead of dealing with "databases" that exist on "hosts" or that you find via some vendor-specific addressing scheme, Rose::DB deals in "logical" data sources. Each logical data source is currently backed by a single "physical" database (basically a single DBI connection). One to one. Periodt.
Multiplexing, fail-over, and other more complex relationships between logical data sources and physical databases are not part of Rose::DB. Some basic types of fail-over may get added to Rose::DB in the future, but right now the mapping is strictly one-to-one. (Also, the author is currently inclined to encourage multiplexing functionality to live in a layer above Rose::DB, rather than inside it or in a subclass of it. So there's that.)
The driver type of the data source is what determines the functionality of all the methods that do vendor-specific stuff β like column value parsing and formatting. π§
Rose::DB identifies data sources using a two-level namespace made of a "domain" and a "type". Both of those are arbitrary strings. If you leave them unspecified, the default domain and default type (reachable via Rose::DB's default_domain and default_type class methods) get assumed. No cap.
There are lots of ways to use this two-level namespace, but the most common is: use the domain to represent the current environment (think "development", "staging", "production") and then use the type to identify the logical data source within that environment (think "report", "main", "archive").
A typical deployment scenario will set the default domain using the default_domain class method as part of the configure/install process. Then inside your application code, Rose::DB objects can be constructed by specifying type alone:
$main_db = Rose::DB->new(type => 'main');
$archive_db = Rose::DB->new(type => 'archive');
And if there's only one database type, then every Rose::DB object can be instantiated with a bare constructor call like this:
$db = Rose::DB->new;
Again β remember, this is just one of many possible uses of domain and type. You can create arbitrarily complex scenarios by nesting namespaces within one or both parameters (very much like how Perl uses "::" to build a multi-level namespace out of single strings). Go feral, bestie. π₯
The important point is the abstraction of data sources, so they can be identified and referred to using a vocabulary that is entirely independent of the actual DSN (data source names) that DBI uses behind the scenes. That's the whole vibe check right there. β
π Database Handle Life-Cycle Management
When a Rose::DB object gets destroyed while it's still holding an active DBI database handle, that handle is explicitly disconnected before destruction. Rose::DB supports a simple retain/release reference-counting system which lets a database handle out-live its parent Rose::DB object. She's not clingy. π
In the simplest case, Rose::DB could be used purely for her data source abstraction features. For example, transiently creating a Rose::DB and then retaining its DBI database handle before it gets destroyed:
$main_dbh = Rose::DB->new(type => 'main')->retain_dbh
or die Rose::DB->error;
$aux_dbh = Rose::DB->new(type => 'aux')->retain_dbh
or die Rose::DB->error;
But if the database handle was simply extracted via the dbh method instead of being retained with retain_dbh, it would be disconnected by the time the statement finished. Like so:
# WRONG: $dbh will be disconnected immediately after the assignment!
$dbh = Rose::DB->new(type => 'main')->dbh or die Rose::DB->error;
Not me warning you twice about this one. If you only take one thing from this section, take thatretain_dbhline.dbhalone will ghost you the second the statement ends. π
π¦ Vendor-Specific Column Value Parsing and Formatting
Certain semantically identical column types get handled differently in different databases. Date and time columns are the poster children for this. Even though lots of databases store month, day, year, hours, minutes, and seconds using a "datetime" column type, there will likely be significant differences in how each of those databases expects to receive such values, and in how they get returned. It's giving chaos. πͺοΈ
Rose::DB is the one responsible for converting the wide range of vendor-specific column values for a particular column type into a single form that's convenient to use inside Perl code. And she handles the opposite task too β taking input from the Perl side and converting it into the appropriate format for a specific database. Not every column type that exists in the supported databases is handled by Rose::DB, but support will expand in the future. Patience, queen. π
Many column types are specific to a single database and don't exist anywhere else. When it's reasonable to do so, vendor-specific column types may be "emulated" by Rose::DB for the benefit of other databases. For example, an ARRAY value may be stored as a specially formatted string in a VARCHAR field in a database that doesn't have a native ARRAY column type. Cute workaround honestly. π
But β and here's the plot twist β Rose::DB does NOT attempt to present a unified column type system. If a column type doesn't exist in a particular kind of database, you should have no expectation that Rose::DB will be able to parse and format that value type on behalf of that database. She said what she said. π
π High-Level Transaction Support
You can start, commit, and roll back transactions in a whole bunch of ways using the DBI database handle directly. Rose::DB provides wrappers that do the same things, but with different error handling and return values. So it's the same dance, different choreography. π
There's also a method (do_transaction) that will execute arbitrary code inside a single transaction, automatically handling rollback on failure and commit on success. Main character behavior, honestly β she handles the messy parts so you don't have to. πβ¨
π SUBCLASSING π
okay so bestie, subclassing is strongly encouraged and it generally does exactly what you'd expect. π (there's a whole tutorial with a complete example if you want the full tour.) but there's this one lil question that always comes up: how does class data get shared with subclasses? so here's the tea, per piece of class data:
alias_db,modify_db,register_db,unregister_db,unregister_domainβ by default, every subclass shares the same data source "registry" withRose::DB. if you want your subclass to have its own private registry (which is the recommended glow-up), go look at the example in the docs for theregistrymethod down below.default_domain,default_typeβ if you call these with no arguments, and the attribute was never set for this class, then it kicks off a left-most, breadth-first search of the parent classes. the value it returns comes from the first parent class it bumps into that has ever had this attribute set.
(these attributes use the inheritable_scalar method type, as defined in Rose::Class::MakeMethods::Generic.) β¨
driver_class,default_connect_optionsβ these hashes of attributes get inherited by subclasses using a one-time, shallow copy from a superclass. any subclass that accesses or manipulates the hash in any way will immediately get its own private copy of the hash β exactly as it existed in the superclass at the moment of that access or manipulation. π«Ά
the superclass it copies from is the closest ("least super") class that has ever accessed or manipulated this hash. and the copy is "shallow", meaning it only duplicates the keys and values. reference values are not recursively copied.
setting the hash to undef (via the 'reset' interface) will make it get re-copied from a superclass the next time it's accessed.
(these attributes use the inheritable_hash method type, as defined in Rose::Class::MakeMethods::Generic.)
πΎ SERIALIZATION πΎ
ngl bestie, this part is a lil spicy. π₯ a Rose::DB object may contain a DBI database handle, and DBI database handles usually don't survive the serialize process intact. Rose::DB objects also hide database passwords inside closures, and those also don't serialize well. so for a Rose::DB object to actually survive serialization, you need custom hooks. periodt.
Rose::DB does have hooks for the Storable serialization module, but there's an important caveat. since Rose::DB objects are blessed into a dynamically generated class (derived from the driver class), you must load your Rose::DB-derived class with all its registered data sources before you can successfully thaw a frozen Rose::DB-derived object. here's an example. π
imagine this is your Rose::DB-derived class:
package My::DB;
use Rose::DB;
our @ISA = qw(Rose::DB);
My::DB->register_db(
domain => 'dev',
type => 'main',
driver => 'Pg',
...
);
My::DB->register_db(
domain => 'prod',
type => 'main',
driver => 'Pg',
...
);
My::DB->default_domain('dev');
My::DB->default_type('main');
in one program, a My::DB object gets frozen using Storable:
# my_freeze_script.pl
use My::DB;
use Storable qw(nstore);
# Create My::DB object
$db = My::DB->new(domain => 'dev', type => 'main');
# Do work...
$db->dbh->db('CREATE TABLE some_table (...)');
...
# Serialize $db and store it in frozen_data_file
nstore($db, 'frozen_data_file');
now another program wants to thaw out that My::DB object and use it. to do that, it must be sure to load the My::DB module (which registers all its data sources when loaded) before it tries to deserialize the My::DB object that my_freeze_script.pl serialized. π§
# my_thaw_script.pl
# IMPORTANT: load db modules with all data sources registered before
# attempting to deserialize objects of this class.
use My::DB;
use Storable qw(retrieve);
# Retrieve frozen My::DB object from frozen_data_file
$db = retrieve('frozen_data_file');
# Do work...
$db->dbh->db('DROP TABLE some_table');
...
quick note, bestie: this whole rule about loading a Rose::DB-derived class with all its data sources registered before deserializing such an object only applies if the serialization happened in a different process. if you freeze and thaw within the same process, you don't have to worry about it at all. easy. πββοΈ
π ENVIRONMENT π
there are two ways to alter the initial Rose::DB data source registry:
- the
ROSEDB_DEVINITfile or module, which can add, modify, or remove data sources and alter the default domain and type. π - the
ROSEDBRCfile, which can modify existing data sources.
π ROSEDB_DEVINIT π
the ROSEDB_DEVINIT file or module is used during development, usually to set up data sources for a particular developer's database or project. if the ROSEDB_DEVINIT environment variable is set, it should be the name of a Perl module or file. if it's a Perl module and that module has a fixup() subroutine, that sub will be called as a class method after the module is loaded. β¨
if the ROSEDB_DEVINIT environment variable is not set, or if the specified file doesn't exist or has errors, then it defaults to the package name Rose::DB::Devel::Init::username, where username is the account name of the current user.
note: if thegetpwuid()function is unavailable (as it often is on Windows versions of perl), then this default does not apply, and the loading of the module namedRose::DB::Devel::Init::usernameis not attempted. π
the ROSEDB_DEVINIT file or module may contain arbitrary Perl code, which will be loaded and evaluated in the context of Rose::DB. example:
Rose::DB->default_domain('development');
Rose::DB->modify_db(domain => 'development',
type => 'main_db',
database => 'main',
username => 'jdoe',
password => 'mysecret');
1;
remember to end the file with a true value, bestie. don't forget or it's giving sad. π
the ROSEDB_DEVINIT file or module must be read explicitly by calling the auto_load_fixups class method.
π¦ ROSEDBRC π¦
the ROSEDBRC file contains configuration "fix-up" information. this file is most often used to dynamically set passwords that are too sensitive to be included directly in the source code of a Rose::DB-derived class. π€«
the path to the fix-up file is determined by the ROSEDBRC environment variable. if that variable isn't set, or if the file it points to doesn't exist, then it defaults to /etc/rosedbrc.
this file should be in YAML format. to read it, you must have either YAML::Syck or some reasonably modern version of YAML installed (0.66 or later is recommended). YAML::Syck will be preferred if both are installed. π
the ROSEDBRC file's contents have the following structure:
---
somedomain:
sometype:
somemethod: somevalue
---
otherdomain:
othertype:
othermethod: othervalue
each entry modifies an existing registered data source. any valid registry entry object method can be used (in place of somemethod and othermethod in the YAML example above).
this file must be read explicitly by calling the auto_load_fixups class method after you've set up all your data sources. example:
package My::DB;
use Rose::DB;
our @ISA = qw(Rose::DB);
__PACKAGE__->use_private_registry;
# Register all data sources
__PACKAGE__->register_db(
domain => 'development',
type => 'main',
driver => 'Pg',
database => 'dev_db',
host => 'localhost',
username => 'devuser',
password => 'mysecret',
);
...
# Load fix-up files, if any
__PACKAGE__->auto_load_fixups;
β CLASS METHODS β
πΈ alias_db PARAMS
makes one data source an alias for another by pointing them both at the same registry entry. PARAMS are name/value pairs that must include domain and type values for both the source and alias parameters. example:
Rose::DB->alias_db(source => { domain => 'dev', type => 'main' },
alias => { domain => 'dev', type => 'aux' });
this makes the dev/aux data source point to the same registry entry as the dev/main data source. modifications to either registry entry (via modify_db) will be reflected in both. π₯
πΈ auto_load_fixups
attempts to load both the YAML-based ROSEDBRC and the Perl-based ROSEDB_DEVINIT fix-up files, if any exist, in that order. the ROSEDBRC file will modify the data source registry of the calling class. see the ENVIRONMENT section above for more info. β¨
πΈ db_cache [CACHE]
get or set the Rose::DB::Cache-derived object used to cache Rose::DB objects on behalf of this class. if no such object exists, a new cache object of db_cache_class class will be created, stored, and returned. π«Ά
πΈ db_cache_class [CLASS]
get or set the name of the Rose::DB::Cache-derived class used to cache Rose::DB objects on behalf of this class. the default value is Rose::DB::Cache.
πΈ db_exists PARAMS
returns true if the data source specified by PARAMS is registered, false otherwise. PARAMS are name/value pairs for domain and type. if they're omitted, they default to default_domain and default_type, respectively. if default values don't exist, a fatal error will occur. π if a single value is passed instead of name/value pairs, it's taken as the value of the type parameter.
πΈ default_connect_options [HASHREF | PAIRS]
get or set the default DBI connect options hash. if a reference to a hash is passed, it replaces the default connect options hash. if a series of name/value pairs is passed, they're added to the default connect options hash. π
the default set of default connect options is:
AutoCommit => 1,
RaiseError => 1,
PrintError => 1,
ChopBlanks => 1,
Warn => 0,
see the connect_options object method for more info on how the default connect options are used.
πΈ default_domain [DOMAIN]
get or set the default data source domain. see the "Data Source Abstraction" section for more on data source domains. π
πΈ default_type [TYPE]
get or set the default data source type. see the "Data Source Abstraction" section for more on data source types. β
driver_class DRIVER [, CLASS] π
Bestie, this is the driver-to-class matchmaker. Give it just a DRIVER and it hands you back the subclass used for that driver. Give it DRIVER and CLASS and you're setting which subclass that driver should use.
The DRIVER argument gets automatically converted to lowercase, no cap β driver names are effectively case-insensitive, so don't sweat the capitalization. β¨
$class = Rose::DB->driver_class('Pg'); # get
Rose::DB->driver_class('pg' => 'MyDB::Pg'); # set
Out of the box, the default mapping of driver names to class names is:
mysql -> Rose::DB::MySQL
mariadb -> Rose::DB::MariaDB
pg -> Rose::DB::Pg
informix -> Rose::DB::Informix
sqlite -> Rose::DB::SQLite
oracle -> Rose::DB::Oracle
generic -> Rose::DB::Generic
That special "generic" driver name? It's the fallback queen π β the class mapped to "generic" is used for any driver name that doesn't have an entry in the map.
Wanna know how the driver influences the class of objects returned by the constructor? Go read the docs for the new method. iykyk. π¦
default_keyword_function_calls [BOOL] β
Gets or sets a boolean default value for the keyword_function_calls object attribute. And where does it come from if you're not setting it yourself? It defaults to the value of the ROSE_DB_KEYWORD_FUNCTION_CALLS environment variable, if that's set to a defined value β and false otherwise. Simple as. π
modify_db PARAMS π
Ok so this one modifies a data source. You hand it PARAMS β name/value pairs, obviously β and it sets the attributes you specified. Literally any Rose::DB object method that sets a data source configuration value is a valid parameter name. Go off. π₯
# Set new username for data source identified by domain and type
Rose::DB->modify_db(domain => 'test',
type => 'main',
username => 'tester');
Your PARAMS should really include values for both the "type" and "domain" parameters, because those two attributes are what identify the data source. Omit them and they default to default_domain and default_type, respectively β and if those default values don't exist, you get a fatal error. π Also, if there's no data source defined for the specified "type" and "domain", that's another fatal error. No source, no service.
prepare_cache_for_apache_fork π«Ά
Cute little convenience method, and it's equivalent to exactly this call:
Rose::DB->db_cache->prepare_for_apache_fork()
Any arguments you pass to this method get passed on to that call to the db_cache's prepare_for_apache_fork method.
Please read the Rose::DB::Cache documentation β particularly the documentation for the use_cache_during_apache_startup method β for the full tea. πΈ
register_db PARAMS π
Registering a brand new data source, let's gooo! π PARAMS are name/value pairs, and (same deal as modify_db) any Rose::DB object method that sets a data source configuration value is a valid parameter name.
The rules of the game:
PARAMSmust include a value for the"driver"parameter.- If the
"type"or"domain"parameters are omitted or undefined, they default to the return values of thedefault_typeanddefault_domainclass methods, respectively. - The
"type"and"domain"are used to identify the data source. If either one is missing, a fatal error will occur. See the "Data Source Abstraction" section for more info on data source types and domains. - The
"driver"is what determines which class objects will be blessed into by theRose::DBconstructor,new. The driver name is automatically converted to lowercase. If it's missing, a fatal error will occur.
In most deployment scenarios, register_db gets called early in the compilation process, so that all the registered data sources are already available when the "real" code runs.
Database registration can go directly in your Rose::DB subclass, and honestly that's the recommended approach. Like so:
package My::DB;
use Rose::DB;
our @ISA = qw(Rose::DB);
# Use a private registry for this class
__PACKAGE__->use_private_registry;
# Register data sources
My::DB->register_db(
domain => 'development',
type => 'main',
driver => 'Pg',
database => 'dev_db',
host => 'localhost',
username => 'devuser',
password => 'mysecret',
);
My::DB->register_db(
domain => 'production',
type => 'main',
driver => 'Pg',
database => 'big_db',
host => 'dbserver.acme.com',
username => 'dbadmin',
password => 'prodsecret',
);
...
Another possible approach: consolidate all your data source registration into a single module, then use that module early on in the code path. Picture a mod_perl web server environment, bestie:
# File: MyCorp/DataSources.pm
package MyCorp::DataSources;
My::DB->register_db(
domain => 'development',
type => 'main',
driver => 'Pg',
database => 'dev_db',
host => 'localhost',
username => 'devuser',
password => 'mysecret',
);
My::DB->register_db(
domain => 'production',
type => 'main',
driver => 'Pg',
database => 'big_db',
host => 'dbserver.acme.com',
username => 'dbadmin',
password => 'prodsecret',
);
...
# File: /usr/local/apache/conf/startup.pl
use My::DB; # your Rose::DB subclass
use MyCorp::DataSources; # register all data sources
...
Data source registration can happen at any time, of course β but it's most useful when all your application code can simply assume that every data source is already registered. Doing the registration as early as possible (like directly in your Rose::DB subclass, or in a "startup.pl" file that gets loaded from an apache/mod_perl web server's "httpd.conf" file) is the best way to create that kind of environment. π
Note that the data source registry serves as an initial source of information for Rose::DB objects. Once an object is instantiated, it is independent of the registry. Changes to an object are not reflected in the registry, and changes to the registry are not reflected in existing objects. Periodt. π
registry [REGISTRY] π§Ί
Gets or sets the Rose::DB::Registry-derived object that manages and stores the data source registry. With no argument, it defaults to an "empty" Rose::DB::Registry object.
Careful bestie: setting a new registry will replace the existing registry and all the data sources registered in it. Like, all of them. π«
Also note that Rose::DB subclasses will inherit the base class's Rose::DB::Registry object, which means they inherit all existing registry entries and share the same registry namespace as the base class. Whether that's what you want... is a whole conversation. (It may or may not be. π)
In most cases, it's wise to give your subclass its own private registry if it inherits directly from Rose::DB. To do that, just set a new registry object in your subclass:
package My::DB;
use Rose::DB;
our @ISA = qw(Rose::DB);
# Create a private registry for this class:
#
# either explicitly:
# use Rose::DB::Registry;
# __PACKAGE__->registry(Rose::DB::Registry->new);
#
# or use the convenience method:
__PACKAGE__->use_private_registry;
...
Further subclasses of "My::DB" may then inherit its registry object β if they want to β or they can create their own private registries the exact same way shown above. β¨
unregister_db PARAMS π¦
Bye bye, data source! Unregisters the data source having the "type" and "domain" specified in PARAMS, where PARAMS are name/value pairs. Returns true if the data source was unregistered successfully, false if it didn't exist in the first place.
Rose::DB->unregister_db(type => 'main', domain => 'test');
PARAMS must include values for both the "type" and "domain" parameters, since those two attributes identify the data source. If either one is missing β fatal error, sorry bestie. π
Unregistering a data source removes all knowledge of it. That may be harmful to any existing Rose::DB objects that are associated with that data source. Not a vibe to do casually. π
unregister_domain DOMAIN πͺοΈ
Unregisters an entire domain. Returns true if the domain was unregistered successfully, false if it didn't exist in the first place. Example:
Rose::DB->unregister_domain('test');
And this one's the big one: unregistering a domain removes all knowledge of all of the data sources that existed under it. This may be harmful to any existing Rose::DB objects associated with any of those data sources. Beware. π
use_cache_during_apache_startup [BOOL] π
Another little convenience method, and it's equivalent to exactly this call:
Rose::DB->db_cache->use_cache_during_apache_startup(...)
The boolean argument you pass to this method gets passed on to the call to the db_cache's use_cache_during_apache_startup method.
Please read the Rose::DB::Cache's use_cache_during_apache_startup documentation for more information. π«Ά
use_private_registry π
This method is the one that gives a class its own private registry. In other words, this:
__PACKAGE__->use_private_registry;
is roughly equivalent to this:
use Rose::DB::Registry;
__PACKAGE__->registry(Rose::DB::Registry->new);
β¨ CONSTRUCTORS β¨
π new PARAMS
okay so bestie, this one builds you a brand new object from PARAMS, and PARAMS are just name/value pairs. literally any object method can be a parameter name, so go wild. example time:
$db = Rose::DB->new(type => 'main', domain => 'qa');
and if you pass just one single argument to new, it gets used as the type value. iconic, honestly:
$db = Rose::DB->new(type => 'aux');
$db = Rose::DB->new('aux'); # same thing
every single Rose::DB object is tied to a particular data source, and that data source is defined by the type and domain values. if those aren't in PARAMS, the defaults get used. so if you do not want the defaults for the type and domain attributes, you gotta say so in the constructor PARAMS. no cap.
you can set those defaults with the default_type and default_domain class methods. and for the whole scoop on data sources, go read the "Data Source Abstraction" section. π
so the object attributes get set from the registry entry that the type and domain parameters point to. and that registry entry must exist, or it's a fatal error β with exactly one exception, keep reading. any extra PARAMS you pass will override whatever values came out of the registry entry.
now, the exception bestie: if you don't pass type and domain params but you do pass a driver param, you get a new "empty" object back. examples:
# This is ok, even if no registered data sources exist
$db = Rose::DB->new(driver => 'sqlite');
the object new gives you back is derived from a database-specific driver class, picked based on the driver value of the selected data source. and if there's no registered data source for the type and domain you specified? fatal error. sorry queen. π
the default driver-to-class mapping is literally this:
pg -> Rose::DB::Pg
mysql -> Rose::DB::MySQL
mariadb -> Rose::DB::MariaDB
informix -> Rose::DB::Informix
oracle -> Rose::DB::Oracle
sqlite -> Rose::DB::SQLite
and you can swap that mapping out with the driver_class class method. slay. π
π new_or_cached PARAMS
this one either constructs or returns a Rose::DB object based on PARAMS, where PARAMS are any name/value pairs you could hand to the new method. if the db_cache's get_db method returns an existing Rose::DB object that matches PARAMS, boom, that's what you get back. otherwise a fresh Rose::DB object gets created, dropped into the db_cache, and then returned to you. π«Ά
go check the Rose::DB::Cache documentation to learn about the cache API and the default implementation. iykyk.
π¦ OBJECT METHODS π¦
π₯ begin_work
tries to start a transaction by calling the begin_work method on the DBI database handle.
if it needs to, it'll construct the database handle and connect to the current data source first. if that fails, undef comes back. and if there's no registered data source for the current type and domain, fatal error, periodt.
if the AutoCommit database handle attribute is false, the handle is assumed to already be in a transaction, so Rose::DB::Constants::IN_TRANSACTION (-1) is returned. if the call to DBI's begin_work method succeeds, you get 1. if it fails, undef. that's the whole vibe check.
π commit
tries to commit the current transaction by calling the commit method on the DBI database handle. if the DBI database handle doesn't exist or isn't connected, 0 is returned. rude but okay.
if the AutoCommit database handle attribute is true, the handle is assumed to not be in a transaction and Rose::DB::Constants::IN_TRANSACTION (-1) is returned. if the call to DBI's commit method succeeds, 1 is returned. if it fails, undef.
πΈ connect
constructs and connects the DBI database handle for the current data source, calling dbi_connect to make a fresh DBI database handle if none exists yet. and if there's no registered data source for the current type and domain, fatal error, no exceptions.
if any post_connect_sql statement failed to execute, the database handle gets disconnected and then thrown away. bye bestie. ποΈ
now here's the tea π΅: if the database handle that dbi_connect returned was originally connected by some other Rose::DB-derived object (like, say, if a subclass's custom implementation of dbi_connect calls DBI's connect_cached method), then the post_connect_sql statements will not run, and neither will any custom DBI attributes get applied (e.g., Rose::DB::MySQL's mysql_enable_utf8 attribute). important!!
returns true if the database handle connected successfully and all the post_connect_sql statements (if there were any) ran successfully, false otherwise.
π connect_option NAME [, VALUE]
get or set a single connection option. like this:
$val = $db->connect_option('RaiseError'); # get
$db->connect_option(AutoCommit => 1); # set
connection options are name/value pairs passed in a hash reference as the fourth argument to the call to DBI->connect(). see the DBI documentation for what all the various options actually do. π
β¨ connect_options [HASHREF | PAIRS]
get or set the DBI connect options hash. if you pass a reference to a hash, it replaces the connect options hash. if you pass a series of name/value pairs, they get added to the connect options hash.
returns a reference to the connect options hash in scalar context, or a list of name/value pairs in list context. context matters, bestie.
π dbh [DBH]
get or set the DBI database handle connected to the current data source. if the database handle doesn't exist, or it was created in another process or thread, this method discards the old database handle (if there was one) and dbi_connect gets called to create a new one.
returns undef if the database handle couldn't be constructed and connected. and if there's no registered data source for the current type and domain, fatal error occurs.
β οΈ note: when you're setting this attribute, you must pass in a DBI database handle that has the same driver as the object. like, if the driver is "mysql" then the DBI database handle has to be connected to a MySQL database. passing in a mismatched database handle will cause a fatal error. don't do it. π
π¦ dbi_connect [ARGS]
this method calls DBI->connect(...), passing all ARGS and returning all values. it has no effect on the internal state of the object. use the connect method if you actually want to create and store a new database handle in the object.
override this method in your Rose::DB subclass if you want to use a different method (e.g. DBI->connect_cached()) to create database handles. main character customization energy. π
π disconnect
decrements the reference count for the database handle and disconnects it if the reference count hits zero and if the database handle was originally connected by this object. (which might not be the case if, say, a subclass's custom implementation of dbi_connect calls DBI's connect_cached method.) regardless of the reference count, it sets the dbh attribute to undef.
returns true if all pre_disconnect_sql statements (if any) ran successfully and the database handle disconnected successfully (or if it was simply set to undef), false otherwise.
the database handle will not be disconnected if any pre_disconnect_sql statement fails to execute, and pre_disconnect_sql does not run unless the handle is actually going to be disconnected. logic, we love her.
π do_transaction CODE [, ARGS]
runs whatever code you want inside a single transaction, rolling back if any of the code fails, committing if it succeeds. CODE should be a code reference. it'll be called with any arguments passed to do_transaction after the code reference. example:
# Transfer $100 from account id 5 to account id 9
$db->do_transaction(sub
{
my($amt, $id1, $id2) = @_;
my $dbh = $db->dbh or die $db->error;
# Transfer $amt from account id $id1 to account id $id2
$dbh->do("UPDATE acct SET bal = bal - $amt WHERE id = $id1");
$dbh->do("UPDATE acct SET bal = bal + $amt WHERE id = $id2");
},
100, 5, 9) or warn "Transfer failed: ", $db->error;
if the CODE block threw an exception, or the transaction couldn't be started and committed successfully, then undef is returned and the exception that got thrown is available in the error attribute. otherwise you get a true value back. π«Ά
π error [MSG]
get or set the error message associated with the last failure. if a method fails, check out this attribute to find out why it failed, as a text message. it's giving helpful.
π has_dbh
returns true if the object has a DBI database handle (dbh), false if it doesn't. simple as.
πΈ has_primary_key [ TABLE | PARAMS ]
returns true if the specified table has a primary key (as determined by the primary_key_column_names method), false otherwise.
the arguments are the same as those for the primary_key_column_names method: either a table name, or name/value pairs specifying "table", "catalog", and "schema". the "catalog" and "schema" parameters are optional and default to the return values of the catalog and schema methods, respectively. see the documentation for primary_key_column_names for more info. π
π in_transaction
return true if the dbh is currently in the middle of a transaction, false (but still defined!) if it's not. if there's no dbh, then undef is returned. three states, we contain multitudes.
π§ init_db_info
initializes the data source configuration info based on the current values of the type and domain attributes, by pulling data from the corresponding registry entry. if there's no registered data source for the current type and domain, fatal error, obviously. init_db_info gets called as part of the new and connect methods.
β insertid_param
returns the name of the DBI statement handle attribute that holds the auto-generated unique key created during the last insert operation. returns undef if the current data source doesn't support that attribute. your fave might just not do it, and that's fine.
π keyword_function_calls [BOOL]
get or set a boolean value that says whether or not any string that looks like a function call (matches /^\w+\(.*\)$/) will be treated as a "keyword" by the various format_* methods. defaults to the value returned by the default_keyword_function_calls class method. regex girlies rise β¨
last_insertid_from_sth STH
Hand this one a DBI statement handle, and it hands you back the value of the auto-generated unique key created during the last insert operation. π₯
But bestie, lowkey important: this value may be undefined if this feature isn't supported by the current data source. Not every database wants to give up the goods. π
list_tables
Returns the tables in the database β a plain old list in list context, or a reference to an array in scalar context. The current catalog and schema are honored, periodt. β¨
quote_column_name NAME
Returns the column name NAME, appropriately quoted so you can drop it into an SQL statement. And ngl, the tea here is that "appropriate" quoting may literally mean no quoting at all. π
release_dbh
Decrements the reference count for the DBI database handle β y'know, if it exists. If that handle doesn't exist, you get a 0 and we move on. π«Ά
If the reference count drops all the way down to zero, the database handle gets disconnected. And keep this in mind, because it's giving main character energy: the Rose::DB object itself will increment the reference count when the database handle is connected, and decrement it when disconnect is called. π
Returns true if the reference count is not 0, or if all pre_disconnect_sql statements (if any) were run successfully and the database handle was disconnected successfully. Returns false otherwise. π
The database handle will not be disconnected if anypre_disconnect_sqlstatement fails to execute. Andpre_disconnect_sqlis not run at all unless the handle is actually going to be disconnected.
Peep the "Database Handle Life-Cycle Management" section for more on the retain/release system.
retain_dbh
Returns the connected DBI database handle β after incrementing the reference count, obviously. π If the database handle doesn't exist, or isn't already connected, this method will do literally everything necessary to make that happen. Iconic behavior, no notes.
Returns undef if the database handle could not be constructed and connected. And if there's no registered data source for the current type and domain? Fatal error. Screaming, crying. π¨
Peep the "Database Handle Life-Cycle Management" section for more on the retain/release system.
rollback
Rolls back the current transaction by calling the rollback method on the DBI database handle. If the DBI database handle doesn't exist or isn't connected, you get 0 back. π
If the call to DBI's rollback method succeeds, or if auto-commit is enabled, you get 1. If it fails, you get undef.
π Data Source Configuration π
Okay so, not all databases will use all of these values. Values that aren't supported are simply ignored. They said "no thank you" and we respect it. π
autocommit [VALUE]
Get or set the value of the "AutoCommit" connect option and DBI handle attribute. If a VALUE is passed, it gets set in both the connect options hash and the current database handle, if any. πΈ Returns the value of the "AutoCommit" attribute of the database handle if it exists, or the connect option otherwise.
Do not mix this method with theconnect_optionsmethod in calls toregister_dbormodify_db. Why? Becauseconnect_optionswill overwrite all the connect options with its argument, and neitherregister_dbnormodify_dbguarantee the order that its parameters will be evaluated in. It's giving chaos, and not the cute kind. π
catalog [CATALOG]
Get or set the database catalog name. This setting is only relevant to databases that actually support the concept of catalogs. If yours doesn't, it's just over there, existing, unbothered. π¦
connect_options [HASHREF | PAIRS]
Get or set the options passed in a hash reference as the fourth argument to the call to DBI->connect(). Peep the DBI documentation for the full description of the various options.
- Pass a reference to a hash β it replaces the connect options hash.
- Pass a series of name/value pairs β they get added to the connect options hash. β¨
Returns a reference to the hash of options in scalar context, or a list of name/value pairs in list context.
When init_db_info is called for the first time on an object (either in isolation or as part of the connect process), the connect options are merged with the default_connect_options. The defaults are overridden in the case of a conflict. Example, bestie, take notes:
Rose::DB->register_db(
domain => 'development',
type => 'main',
driver => 'Pg',
database => 'dev_db',
host => 'localhost',
username => 'devuser',
password => 'mysecret',
connect_options =>
{
RaiseError => 0,
AutoCommit => 0,
}
);
# Rose::DB->default_connect_options are:
#
# AutoCommit => 1,
# ChopBlanks => 1,
# PrintError => 1,
# RaiseError => 1,
# Warn => 0,
# The object's connect options are merged with default options
# since new() will trigger the first call to init_db_info()
# for this object
$db = Rose::DB->new(domain => 'development', type => 'main');
# $db->connect_options are:
#
# AutoCommit => 0,
# ChopBlanks => 1,
# PrintError => 1,
# RaiseError => 0,
# Warn => 0,
$db->connect_options(TraceLevel => 2); # Add an option
# $db->connect_options are now:
#
# AutoCommit => 0,
# ChopBlanks => 1,
# PrintError => 1,
# RaiseError => 0,
# TraceLevel => 2,
# Warn => 0,
# The object's connect options are NOT re-merged with the default
# connect options since this will trigger the second call to
# init_db_info(), not the first
$db->connect or die $db->error;
# $db->connect_options are still:
#
# AutoCommit => 0,
# ChopBlanks => 1,
# PrintError => 1,
# RaiseError => 0,
# TraceLevel => 2,
# Warn => 0,
database [NAME]
Get or set the database name, used in the construction of the DSN that gets passed into the DBI connect call. Simple. Elegant. Slay. π
domain [DOMAIN]
Get or set the data source domain. Peep the "Data Source Abstraction" section for more tea on data source domains. π
driver [DRIVER]
Get or set the driver name. But heads up, bestie β the driver name can only be set during object construction (i.e., as an argument to new), because it's the thing that determines the object class. After the object is constructed, setting the driver to anything other than the same value it already has will cause a fatal error. π
Even in the call to new, setting the driver name explicitly is not recommended. Instead, specify the driver when calling register_db for each data source, and let the driver get set automatically based on the domain and type. Trust the process. π§
The driver names for the currently supported database types are:
pg
mysql
mariadb
informix
oracle
sqlite
Driver names should only use lowercase letters. Lowercase. Only. Periodt. π
dsn [DSN]
Get or set the DBI DSN (Data Source Name) passed to the call to DBI's connect method.
An attempt is made to parse the new DSN. Any parts successfully extracted get assigned to the corresponding Rose::DB attributes (e.g., host, port, database). If no value could be extracted for an attribute, it's set to undef. π«
If the DSN is never set explicitly, it's built automatically based on the relevant object attributes.
If the DSN is set explicitly, but any of host, port, database, schema, or catalog are also provided β either in an object constructor or when the data source is registered β the explicit DSN may be ignored, because a new DSN gets constructed based on those attributes instead. Surprise! π
handle_error [VALUE]
Get or set the value of the "HandleError" connect option and DBI handle attribute. If a VALUE is passed, it gets set in both the connect options hash and the current database handle, if any. πΈ Returns the value of the "HandleError" attribute of the database handle if it exists, or the connect option otherwise.
Same warning as before, bestie: do not mix this method with theconnect_optionsmethod in calls toregister_dbormodify_db, becauseconnect_optionswill overwrite all the connect options with its argument, and neitherregister_dbnormodify_dbguarantee the order that its parameters will be evaluated in. π
host [NAME]
Get or set the database server host name, used in the construction of the DSN which is passed in the DBI connect call. π¦
password [PASS]
Get or set the password that will be passed to the DBI connect call. Keep it secret, keep it safe. π€«
port [NUM]
Get or set the database server port number, used in the construction of the DSN which is passed in the DBI connect call. π
pre_disconnect_sql [STATEMENTS]
Get or set the SQL statements that get run immediately before disconnecting from the database. STATEMENTS should be a list or reference to an array of SQL statements. Returns a reference to the array of SQL statements in scalar context, or a list of SQL statements in list context. β¨
The SQL statements are run in the order that they're supplied in STATEMENTS. If any pre_disconnect_sql statement fails when executed, the subsequent statements are ignored. First fail and we're out, no cap. π
post_connect_sql [STATEMENTS]
Get or set the SQL statements that get run immediately after connecting to the database. STATEMENTS should be a list or reference to an array of SQL statements. Returns a reference to the array of SQL statements in scalar context, or a list of SQL statements in list context. π
The SQL statements are run in the order that they're supplied in STATEMENTS. If any post_connect_sql statement fails when executed, the subsequent statements are ignored. Same energy as above, fr fr. π
primary_key_column_names [ TABLE | PARAMS ]
Returns a list (in list context) or reference to an array (in scalar context) of the names of the columns that make up the primary key for the specified table. If the table has no primary key, you get an empty list (in list context) or a reference to an empty array (in scalar context). Nothing. Void. The emptiness. π³οΈ
The table may be specified in two ways:
- Pass one argument β it's taken as the name of the table.
- Otherwise β name/value pairs are expected.
Valid parameter names are:
catalogβ The name of the catalog that contains the table. This parameter is optional and defaults to the return value of thecatalogmethod."schema"β the name of the schema that's holding your table π this one's optional, and if you don't say anything it just defaults to whatever theschemamethod hands back."table"β the name of the table. this one is required, no skipping it bestie π
Case-sensitivity of names is determined by the underlying database. If your database is case-sensitive, then you must pass names to this method with the expected case. π so like, don't come crying to me when Users and users turn out to be two completely different tables. match the case, fr fr.
print_error [VALUE] π«Ά
Get or set the value of the "PrintError" connect option and DBI handle attribute. If a VALUE is passed, it will be set in both the connect options hash and the current database handle, if any. Returns the value of the "PrintError" attribute of the database handle if it exists, or the connect option otherwise.
β οΈ okay so do NOT mix this method with theconnect_optionsmethod in calls toregister_dbormodify_db. why? becauseconnect_optionswill straight up overwrite all the connect options with its argument, and neitherregister_dbnormodify_dbguarantee the order that its parameters will be evaluated. so the order is giving chaos and you will lose π
raise_error [VALUE] π₯
Get or set the value of the "RaiseError" connect option and DBI handle attribute. If a VALUE is passed, it will be set in both the connect options hash and the current database handle, if any. Returns the value of the "RaiseError" attribute of the database handle if it exists, or the connect option otherwise.
β οΈ same warning, same energy: don't mix this with theconnect_optionsmethod in calls toregister_dbormodify_db, becauseconnect_optionsoverwrites all the connect options with its argument. and neitherregister_dbnormodify_dbpromise you any particular evaluation order. so yeah. don't π
schema [SCHEMA] β¨
Get or set the database schema name. Heads up: this setting is only useful to databases that support the concept of schemas (so like, PostgreSQL, iykyk π).
server_time_zone [TZ] π
Get or set the time zone used by the database server software. TZ should be a time zone name that is understood by DateTime::TimeZone. The default value is "floating".
See the DateTime::TimeZone documentation for acceptable values of TZ π°οΈ
type [TYPE] π¦
Get or set the data source type. Peep the "Data Source Abstraction" section for more info on data source types.
username [NAME] π
Get or set the username that will be passed to the DBI connect call.
β¨ Value Parsing and Formatting β¨
okay this is the part where all the type conversion magic lives, and honestly it's lowkey the whole personality of this module, we're obsessed π
format_bitfield BITS [, SIZE] π§
Converts the Bit::Vector object BITS into the appropriate format for the "bitfield" data type of the current data source. If a SIZE argument is provided, the bit field will be padded with the appropriate number of zeros until it is SIZE bits long. If the data source does not have a native "bit" or "bitfield" data type, a character data type may be used to store the string of 1s and 0s returned by the default implementation.
format_boolean VALUE π
Converts VALUE into the appropriate format for the "boolean" data type of the current data source. VALUE is simply evaluated in Perl's scalar context to determine if it's true or false. classic Perl behaviour, no notes π
format_date DATETIME π
Converts the DateTime object DATETIME into the appropriate format for the "date" (month, day, year) data type of the current data source.
format_datetime DATETIME π
Converts the DateTime object DATETIME into the appropriate format for the "datetime" (month, day, year, hour, minute, second) data type of the current data source.
format_interval DURATION β³
Converts the DateTime::Duration object DURATION into the appropriate format for the interval (years, months, days, hours, minutes, seconds) data type of the current data source. If DURATION is undefined, a DateTime::Duration object, a valid interval keyword (according to validate_interval_keyword), or if it looks like a function call (matches /^\w+\(.*\)$/) and keyword_function_calls is true, then it is returned unmodified. like, untouched. we said what we said β¨
format_time TIMECLOCK π
Converts the Time::Clock object TIMECLOCK into the appropriate format for the time (hour, minute, second, fractional seconds) data type of the current data source. Fractional seconds are optional, and the useful precision may vary depending on the data source. so like, your mileage may vary on how many of those lil decimal digits survive π
format_timestamp DATETIME β
Converts the DateTime object DATETIME into the appropriate format for the timestamp (month, day, year, hour, minute, second, fractional seconds) data type of the current data source. Fractional seconds are optional, and the useful precision may vary depending on the data source.
format_timestamp_with_time_zone DATETIME π
Converts the DateTime object DATETIME into the appropriate format for the timestamp with time zone (month, day, year, hour, minute, second, fractional seconds, time zone) data type of the current data source. Fractional seconds are optional, and the useful precision may vary depending on the data source.
parse_bitfield BITS [, SIZE] π’
Parse BITS and return a corresponding Bit::Vector object. If SIZE is not passed, then it defaults to the number of bits in the parsed bit string.
If BITS is a string of "1"s and "0"s or matches /^B'[10]+'$/, then the "1"s and "0"s are parsed as a binary string.
If BITS is a string of numbers, at least one of which is in the range 2-9, it is assumed to be a decimal (base 10) number and is converted to a bitfield as such.
If BITS matches any of these regular expressions:
/^0x/
/^X'.*'$/
/^[0-9a-f]+$/
it is assumed to be a hexadecimal number and is converted to a bitfield as such.
Otherwise, undef is returned. bye π
parse_boolean STRING β
Parse STRING and return a boolean value of 1 or 0. STRING should be formatted according to the data source's native "boolean" data type. The default implementation accepts 't', 'true', 'y', 'yes', and '1' values for true, and 'f', 'false', 'n', 'no', and '0' values for false.
If STRING is a valid boolean keyword (according to validate_boolean_keyword) or if it looks like a function call (matches /^\w+\(.*\)$/) and keyword_function_calls is true, then it is returned unmodified. Returns undef if STRING could not be parsed as a valid "boolean" value.
parse_date STRING π
Parse STRING and return a DateTime object. STRING should be formatted according to the data source's native "date" (month, day, year) data type.
If STRING is a valid date keyword (according to validate_date_keyword) or if it looks like a function call (matches /^\w+\(.*\)$/) and keyword_function_calls is true, then it is returned unmodified. Returns undef if STRING could not be parsed as a valid "date" value.
parse_datetime STRING π
Parse STRING and return a DateTime object. STRING should be formatted according to the data source's native "datetime" (month, day, year, hour, minute, second) data type.
If STRING is a valid datetime keyword (according to validate_datetime_keyword) or if it looks like a function call (matches /^\w+\(.*\)$/) and keyword_function_calls is true, then it is returned unmodified. Returns undef if STRING could not be parsed as a valid "datetime" value.
parse_interval STRING [, MODE] β±οΈ
Parse STRING and return a DateTime::Duration object. STRING should be formatted according to the data source's native "interval" (years, months, days, hours, minutes, seconds) data type.
If STRING is a DateTime::Duration object, a valid interval keyword (according to validate_interval_keyword), or if it looks like a function call (matches /^\w+\(.*\)$/) and keyword_function_calls is true, then it is returned unmodified. Otherwise, undef is returned if STRING could not be parsed as a valid "interval" value.
This optional MODE argument determines how math is done on duration objects. If defined, the "end_of_month" setting for each DateTime::Duration object created by this column will have its mode set to MODE. Otherwise, the "end_of_month" parameter will not be passed to the DateTime::Duration constructor.
Valid modes are "wrap", "limit", and "preserve". See the documentation for DateTime::Duration for a full explanation π
parse_time STRING β°
Parse STRING and return a Time::Clock object. STRING should be formatted according to the data source's native "time" (hour, minute, second, fractional seconds) data type.
If STRING is a valid time keyword (according to validate_time_keyword) or if it looks like a function call (matches /^\w+\(.*\)$/) and keyword_function_calls is true, then it is returned unmodified. Returns undef if STRING could not be parsed as a valid "time" value.
parse_timestamp STRING π°οΈ
Parse STRING and return a DateTime object. STRING should be formatted according to the data source's native "timestamp" (month, day, year, hour, minute, second, fractional seconds) data type. Fractional seconds are optional, and the acceptable precision may vary depending on the data source.
If STRING is a valid timestamp keyword (according to validate_timestamp_keyword) or if it looks like a function call (matches /^\w+\(.*\)$/) and keyword_function_calls is true, then it is returned unmodified. Returns undef if STRING could not be parsed as a valid "timestamp" value.
parse_timestamp_with_time_zone STRING π
Parse STRING and return a DateTime object. STRING should be formatted according to the data source's native "timestamp with time zone" (month, day, year, hour, minute, second, fractional seconds, time zone) data type. Fractional seconds are optional, and the acceptable precision may vary depending on the data source.
If STRING is a valid timestamp keyword (according to validate_timestamp_keyword) or if it looks like a function call (matches /^\w+\(.*\)$/) and keyword_function_calls is true, then it is returned unmodified. Returns undef if STRING could not be parsed as a valid "timestamp with time zone" value.
validate_boolean_keyword STRING π§
Returns true if STRING is a valid keyword for the "boolean" data type of the current data source, false otherwise. The default implementation accepts the values "TRUE" and "FALSE". yes, in all caps, we don't make the rules π
validate_date_keyword STRING π§
Returns true if STRING is a valid keyword for the "date" (month, day, year) data type of the current data source, false otherwise. The default implementation always returns false. so like. it's giving "no". every time. π
β¨ validate_datetime_keyword STRING
Returns true if STRING is a valid keyword for the datetime (month, day, year, hour, minute, second) data type of the current data source, and false otherwise. Ngl the default implementation just hits you with false every single time. π
β¨ validate_interval_keyword STRING
Returns true if STRING is a valid keyword for the interval (years, months, days, hours, minutes, seconds) data type of the current data source, false otherwise. And yeah β the default implementation? Also always false. Periodt. π«Ά
β¨ validate_time_keyword STRING
Returns true if STRING is a valid keyword for the time (hour, minute, second, fractional seconds) data type of the current data source, false otherwise. Default implementation stays returning false, no cap. π
β¨ validate_timestamp_keyword STRING
Returns true if STRING is a valid keyword for the timestamp (month, day, year, hour, minute, second, fractional seconds) data type of the current data source, false otherwise. Yep, default implementation = always false, she's consistent bestie. π
π οΈ DEVELOPMENT POLICY
The Rose development policy applies to this module, and to all the Rose::* modules, fr fr. So please install Rose from CPAN and then run this:
perldoc Rose
β¦for more info. That's the whole assignment. πβ¨
π« SUPPORT
Got any Rose::DB questions or problems? Post them to the Rose::DB::Object mailing list, bestie. (And listen β if the volume ever gets high enough, the author will create a separate list just for Rose::DB, but it isn't an issue right now.) To subscribe to the list or peek the archives, go here:
<http://groups.google.com/group/rose-db-object>
Okay so the mailing list is the preferred support mechanism and all, but you can also email the author (see below π) or file bugs using the CPAN bug tracking system:
<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Rose-DB>
There's also a wiki and other resources linked from the Rose project home page:
Lowkey a whole ecosystem. Go explore it, you'll eat. π₯
π CONTRIBUTORS
Shoutout to the icons who helped build this, in order as listed:
- Kostas Chatzikokolakis
- Peter Karman
- Brian Duggan
- Lucian Dragus
- Ask BjΓΈrn Hansen
- Sergey Leschenko
- Ron Savage
- Ferry Hendrikx
Absolute legends, every single one. πβ¨
π 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 a wrap on Rose::DB(3pm), bestie!! This page ships with perl v5.40.1 and is dated 2026-07-31 β so go forth, connect to your databases, and slay. ππ¦πΈ
π¦ where this page comes from
- ubuntu stonking: librose-db-perl 0.788-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms