view release on metacpan or search on metacpan
pass 'hunter2'; # Do not store any real passwords in plaintext in code!!!!
};
Can be nested under db or server.
creds sub { return \%CREDS }
Allows you to provide a coderef that will return a hashref with all
the necessary database connection fields.
This is mainly useful if you credentials are in an encrypted YAML or
JSON file and you have a method to decrypt and read it returning it
as a hash.
db mydb => sub {
creds sub { ... };
};
Can be nested under db or server.
connect sub { ... }
db mydb => sub {
dsn "dbi:Pg:dbname=foo";
};
Can be nested under db or server.
server $NAME => sub { ... }
Used to define a server with multiple databases. This is a way to
avoid re-specifying credentials for each database you connect to.
You can use db('server_name.db_name') to fetch the database.
Basically this allows you to specify any database fields once in the
server, then define any number of databases that inherit them.
Example:
server pg => sub {
host 'pg.myapp.com';
pass 'hunter2'; # Do not store any real passwords in plaintext in code!!!!
};
Can be nested under `db` or `server`.
- `creds sub { return \%CREDS }`
Allows you to provide a coderef that will return a hashref with all the
necessary database connection fields.
This is mainly useful if you credentials are in an encrypted YAML or JSON file
and you have a method to decrypt and read it returning it as a hash.
db mydb => sub {
creds sub { ... };
};
Can be nested under `db` or `server`.
- `connect sub { ... }`
- `connect \&connect`
db mydb => sub {
dsn "dbi:Pg:dbname=foo";
};
Can be nested under `db` or `server`.
- `server $NAME => sub { ... }`
Used to define a server with multiple databases. This is a way to avoid
re-specifying credentials for each database you connect to.
You can use `db('server_name.db_name')` to fetch the database.
Basically this allows you to specify any database fields once in the server, then
define any number of databases that inherit them.
Example:
server pg => sub {
host 'pg.myapp.com';
lib/DBIx/QuickORM.pm view on Meta::CPAN
$params{+SCHEMAS} //= {};
$params{+SERVERS} //= {};
return bless(\%params, $class);
}
sub quick {
my $class = shift;
my %params = @_;
my $creds = delete $params{credentials};
my $connect = delete $params{connect};
my $types = delete $params{auto_types} // [];
my $dialect = delete $params{dialect};
my $autorow = delete $params{autorow}; # 0 = off (default), 1 = generated namespace, or a class-name prefix
my $row_manager = delete $params{row_manager} // 'DBIx::QuickORM::RowManager::Cached';
croak "Unknown parameter(s) to quick(): " . join(', ', sort keys %params) if keys %params;
croak "quick() requires exactly one of 'credentials' or 'connect'"
unless (($creds ? 1 : 0) + ($connect ? 1 : 0)) == 1;
croak "'credentials' must be a hashref" if $creds && ref($creds) ne 'HASH';
croak "'connect' must be a coderef" if $connect && ref($connect) ne 'CODE';
croak "'auto_types' must be an arrayref" if ref($types) ne 'ARRAY';
my ($dialect_class, $db_name) = $class->_quick_detect($dialect, $creds, $connect);
require DBIx::QuickORM::DB;
my %db_params = (dialect => $dialect_class, db_name => $db_name);
if ($creds) {
$db_params{dsn} = $creds->{dsn} if defined $creds->{dsn};
$db_params{user} = $creds->{user} if defined $creds->{user};
lib/DBIx/QuickORM.pm view on Meta::CPAN
if ($creds) {
$name_source = $creds->{dsn};
if (my $dbd = $creds->{dbd}) {
($driver = $dbd) =~ s/^DBD:://;
}
elsif (my $dsn = $creds->{dsn}) {
($driver) = $dsn =~ m/^dbi:([^:]+):/i
or croak "Could not parse a driver from the dsn '$dsn'";
}
elsif (!$explicit) {
croak "quick() credentials need a 'dsn' or 'dbd' to detect the dialect, or pass an explicit 'dialect'";
}
}
else {
my $dbh = $connect->() or croak "The 'connect' callback did not return a database handle";
$driver = $dbh->{Driver}->{Name};
$name_source = $dbh->{Name};
$dbh->disconnect;
}
my $dialect;
lib/DBIx/QuickORM.pm view on Meta::CPAN
pass 'hunter2'; # Do not store any real passwords in plaintext in code!!!!
};
Can be nested under C<db> or C<server>.
=item C<creds sub { return \%CREDS }>
Allows you to provide a coderef that will return a hashref with all the
necessary database connection fields.
This is mainly useful if you credentials are in an encrypted YAML or JSON file
and you have a method to decrypt and read it returning it as a hash.
db mydb => sub {
creds sub { ... };
};
Can be nested under C<db> or C<server>.
=item C<connect sub { ... }>
lib/DBIx/QuickORM.pm view on Meta::CPAN
db mydb => sub {
dsn "dbi:Pg:dbname=foo";
};
Can be nested under C<db> or C<server>.
=item C<< server $NAME => sub { ... } >>
Used to define a server with multiple databases. This is a way to avoid
re-specifying credentials for each database you connect to.
You can use C<< db('server_name.db_name') >> to fetch the database.
Basically this allows you to specify any database fields once in the server, then
define any number of databases that inherit them.
Example:
server pg => sub {
host 'pg.myapp.com';
lib/DBIx/QuickORM/DB.pm view on Meta::CPAN
my $self = shift;
return $self->{+DSN} if $self->{+DSN};
return $self->{+DSN} = $self->{+DIALECT}->dsn($self);
}
=pod
=item $dbh = $db->new_dbh
Returns a new DBI handle, using the C<connect> callback when present or
C<< DBI->connect >> with the resolved DSN and credentials otherwise.
=back
=cut
sub new_dbh {
my $self = shift;
my (%params) = @_;
my $attrs = $self->attributes;
lib/DBIx/QuickORM/Manual/Connections.pm view on Meta::CPAN
Alternatively, supply a C<connect> coderef that returns a fresh C<DBI> handle.
When present it is used instead of the DSN-based path, giving you full control
over how the handle is opened (custom drivers, connection pools, extra setup,
and so on):
connect => sub { DBI->connect($dsn, $user, $pass, \%attrs) },
Each new handle - whether for the first connection, a reconnect, or a forked
child - is produced the same way: via your callback if you provided one,
otherwise via C<< DBI->connect >> with the resolved DSN and credentials. See
L<DBIx::QuickORM::DB> for the full set of configuration attributes.
=head1 SEE ALSO
=over 4
=item L<DBIx::QuickORM::Connection>
The connection object itself: transactions, handles, async/aside/forked
queries, and the state operations backing the row cache.
lib/DBIx/QuickORM/Manual/Features.pm view on Meta::CPAN
Connect to a database and work with its rows as objects with no DSL, using
C<< DBIx::QuickORM->quick(...) >>. See L<DBIx::QuickORM::Manual::QuickStart>.
=item Connection lifecycle
A memoized connection per ORM, in-place reconnect, and fork safety. See
L<DBIx::QuickORM::Manual::Connections>.
=item Credentials or connect callback
Configure a connection from a DSN/credentials or your own connect callback.
See L<DBIx::QuickORM::Manual::Connections> and L<DBIx::QuickORM/db>.
=back
=head1 DEFINING AN ORM (THE DSL)
=over 4
=item Schemas, tables, columns
lib/DBIx/QuickORM/Manual/QuickStart.pm view on Meta::CPAN
The idea: point C<quick()> at a database, and DBIx::QuickORM introspects all
the table and column metadata directly from the live database. You get back a
ready-to-use connection and start treating rows as objects immediately.
When you want more control (defining your own schema, custom row classes,
joins, and so on) follow the links at the end of this page. For the bigger
picture and the full set of guides, see L<DBIx::QuickORM::Manual>.
=head1 CONNECT
Use the C<quick()> class method. Provide exactly one of C<credentials> or
C<connect>. The SQL dialect is detected automatically from the DSN (or the
C<dbd>), so you usually do not need to think about it.
use DBIx::QuickORM;
my $con = DBIx::QuickORM->quick(
credentials => {
dsn => $dsn, # e.g. "dbi:Pg:dbname=myapp;host=..."
user => $user,
pass => $pass,
},
# Type classes (under DBIx::QuickORM::Type unless fully qualified)
# used to auto inflate/deflate matching columns.
auto_types => ['JSON', 'UUID'],
);
If you would rather hand DBIx::QuickORM a callback that produces a fresh DBI
handle, use C<connect> instead of C<credentials>:
my $con = DBIx::QuickORM->quick(
connect => sub { DBI->connect($dsn, $user, $pass) },
);
C<$con> is a L<DBIx::QuickORM::Connection>. It self-heals: it can reconnect in
place and retry work, preserving its row cache. That is the only object you
need to keep around.
=head2 OPTIONS
lib/DBIx/QuickORM/Manual/Recipes.pm view on Meta::CPAN
=head1 DESCRIPTION
This is a hub of focused, task-oriented recipes for L<DBIx::QuickORM>. Each
recipe below solves a specific problem; for broader topics see the guides
linked under L</SEE ALSO>.
=head2 DEFINE DB LATER
In some cases you may want to define your orm/schema before you have your
database credentials. Then you want to add the database later in an app/script
bootstrap process.
Schema:
package My::Schema;
use DBIx::QuickORM;
orm MyORM => sub {
autofill;
};
lib/DBIx/QuickORM/Manual/Recipes.pm view on Meta::CPAN
use My::Schema;
# This will do the db bootstrap
use My::Bootstrap;
# Connect to the database with the ORM
my $con = qorm('MyORM');
=head2 SCHEMA WITH NO DATABASE, ADD A CONNECT CALLBACK LATER
Like L</"DEFINE DB LATER">, but instead of credentials you attach your own
C<connect> callback (any sub that returns a fresh L<DBI> handle) right before
you need the connection. This is handy when the connection comes from
something you build yourself - a pool, a tunnel, an already-open handle, and
so on.
Define the schema with no database at all:
package My::Schema;
use DBIx::QuickORM;
t/AI/caching.t view on Meta::CPAN
$dbh->do('CREATE TABLE logs (message TEXT NOT NULL)');
$dbh->do('INSERT INTO logs (message) VALUES (?)', undef, 'hello');
$dbh->do('INSERT INTO logs (message) VALUES (?)', undef, 'world');
$dbh->disconnect;
return $dsn;
}
sub connect_orm {
my $dsn = shift // fresh_db();
return DBIx::QuickORM->quick(credentials => {dsn => $dsn});
}
subtest default_manager_is_cached => sub {
my $con = connect_orm();
isa_ok($con->manager, ['DBIx::QuickORM::RowManager::Cached'], "default manager is Cached");
ok($con->manager->does_cache, "does_cache is true for the default manager");
ok($con->state_does_cache, "connection reports caching is on");
};
subtest identity_same_object => sub {
t/AI/connection.t view on Meta::CPAN
my $file = "$dir/connection.sqlite";
my $dsn = "dbi:SQLite:dbname=$file";
{
my $dbh = DBI->connect($dsn, '', '', {RaiseError => 1, PrintError => 0});
$dbh->do('CREATE TABLE users (user_id INTEGER PRIMARY KEY, name TEXT NOT NULL)');
$dbh->do('INSERT INTO users (user_id, name) VALUES (1, ?)', undef, 'bob');
$dbh->disconnect;
}
sub connect_orm { DBIx::QuickORM->quick(credentials => {dsn => $dsn}, @_) }
subtest connection_is_memoized_singleton => sub {
my $con = connect_orm();
my $orm = $con->orm;
ref_is($orm->connection, $con, "quick() returns the ORM's memoized connection");
ref_is($orm->connection, $orm->connection, "connection() returns the same object every call");
my $fresh = $orm->connect;
ref_is_not($fresh, $con, "connect() builds a brand new, independent connection");
t/AI/datetime.t view on Meta::CPAN
# ---- DateTime type over a real SQLite db ----
my $dir = tempdir(CLEANUP => 1);
my $dsn = "dbi:SQLite:dbname=$dir/dt.sqlite";
{
my $dbh = DBI->connect($dsn, '', '', {RaiseError => 1, PrintError => 0});
$dbh->do('CREATE TABLE events (id INTEGER PRIMARY KEY, created DATETIME)');
$dbh->do("INSERT INTO events (created) VALUES ('2020-01-02 03:04:05')");
$dbh->disconnect;
}
my $con = DBIx::QuickORM->quick(credentials => {dsn => $dsn}, auto_types => ['DateTime']);
subtest lazy_inflate => sub {
my ($row) = $con->handle('events')->all;
my $v = $row->field('created');
ok(masked($v), "datetime column inflated to a mask");
ok($v->isa('DBIx::QuickORM::Type::DateTime'), "isa the type (no build needed)");
ok(!$v->qorm_mask_inflated, "isa(type) did not build the DateTime");
is("$v", '2020-01-02 03:04:05', "stringifies to the database string");
t/AI/handle_builder.t view on Meta::CPAN
{
my $dbh = DBI->connect($dsn, '', '', {RaiseError => 1, PrintError => 0});
$dbh->do('CREATE TABLE people (id INTEGER PRIMARY KEY, surname TEXT, first_name TEXT, bio TEXT)');
$dbh->do(
"INSERT INTO people (surname, first_name, bio) VALUES "
. "('smith', 'al', 'x'), ('jones', 'bob', 'y'), ('smith', 'cy', 'z')"
);
$dbh->disconnect;
}
my $con = DBIx::QuickORM->quick(credentials => {dsn => $dsn});
my $base = $con->handle('people');
isa_ok($base, ['DBIx::QuickORM::Handle'], "got a handle for the people table");
subtest immutability => sub {
my $smiths = $base->where({surname => 'smith'});
my $jones = $base->where({surname => 'jones'});
isnt(refaddr($smiths), refaddr($base), "where() returns a new handle, not the original");
isnt(refaddr($jones), refaddr($base), "a second where() returns yet another new handle");
t/AI/literal_source.t view on Meta::CPAN
my $dir = tempdir(CLEANUP => 1);
my $dsn = "dbi:SQLite:dbname=$dir/literal.sqlite";
{
my $dbh = DBI->connect($dsn, '', '', {RaiseError => 1, PrintError => 0});
$dbh->do('CREATE TABLE people (id INTEGER PRIMARY KEY, surname TEXT)');
$dbh->do("INSERT INTO people (surname) VALUES ('smith'), ('jones')");
$dbh->disconnect;
}
my $con = DBIx::QuickORM->quick(credentials => {dsn => $dsn});
# $con->source(\$sql) builds a LiteralSource.
my $sql = "people";
my $src = $con->source(\$sql);
isa_ok($src, ['DBIx::QuickORM::LiteralSource'], "con->source(\\\$sql) builds a LiteralSource");
# The SQL builder splices the moniker in after FROM, so a literal source
# works as a FROM fragment (e.g. a table name). It is NOT a full
# standalone SELECT statement.
my @rows = $con->handle($src)->data_only->all;
t/AI/quick.t view on Meta::CPAN
my $dsn = "dbi:SQLite:dbname=$file";
# Seed a database the quick interface will introspect.
{
my $dbh = DBI->connect($dsn, '', '', {RaiseError => 1, PrintError => 0});
$dbh->do('CREATE TABLE users (user_id INTEGER PRIMARY KEY, name TEXT NOT NULL, meta_json TEXT)');
$dbh->do('INSERT INTO users (name, meta_json) VALUES (?, ?)', undef, 'bob', '{"age":42}');
$dbh->disconnect;
}
subtest credentials_with_dsn => sub {
my $con = DBIx::QuickORM->quick(credentials => {dsn => $dsn}, auto_types => ['JSON']);
isa_ok($con, ['DBIx::QuickORM::Connection'], "quick() returns a live Connection");
isa_ok($con->orm, ['DBIx::QuickORM::ORM'], "the ORM is reachable via \$con->orm");
isa_ok($con->dialect, ['DBIx::QuickORM::Dialect::SQLite'], "dialect detected from the dsn scheme");
my @rows = $con->handle('users')->all;
is(scalar(@rows), 1, "introspected the table and fetched the seeded row");
my $row = $rows[0];
is($row->field('name'), 'bob', "plain column value");
t/AI/quick.t view on Meta::CPAN
auto_types => ['JSON'],
);
isa_ok($con->dialect, ['DBIx::QuickORM::Dialect::SQLite'], "dialect detected by probing the connect handle");
my ($row) = $con->handle('users')->all;
ok($row, "fetched a row through a connect-callback quick connection");
is($row->field('name'), 'bob', "column value via connect-callback path");
};
subtest explicit_dialect => sub {
my $con = DBIx::QuickORM->quick(credentials => {dsn => $dsn}, dialect => 'SQLite');
isa_ok($con->dialect, ['DBIx::QuickORM::Dialect::SQLite'], "explicit dialect honored");
};
subtest row_manager => sub {
my $def = DBIx::QuickORM->quick(credentials => {dsn => $dsn});
isa_ok($def->manager, ['DBIx::QuickORM::RowManager::Cached'], "default row manager is Cached");
my $plain = DBIx::QuickORM->quick(credentials => {dsn => $dsn}, row_manager => 'DBIx::QuickORM::RowManager');
isa_ok($plain->manager, ['DBIx::QuickORM::RowManager'], "row_manager override honored");
ok(!$plain->manager->does_cache, "the plain RowManager does not cache");
like(
dies { DBIx::QuickORM->quick(credentials => {dsn => $dsn}, row_manager => 'No::Such::Manager::XYZ') },
qr/Could not load row_manager/,
"bad row_manager class is reported",
);
};
subtest autorow => sub {
# Off by default: rows are the generic class.
my $off = DBIx::QuickORM->quick(credentials => {dsn => $dsn});
my ($u) = $off->handle('users')->all;
is(ref($u), 'DBIx::QuickORM::Row', "autorow off by default -> generic Row");
# autorow => 1 generates a unique namespace.
my $gen = DBIx::QuickORM->quick(credentials => {dsn => $dsn}, autorow => 1);
my ($g) = $gen->handle('users')->all;
like(ref($g), qr/^DBIx::QuickORM::Row::Auto\d+::Users$/, "autorow => 1 generates a row class");
isa_ok($g, ['DBIx::QuickORM::Row'], "generated row class isa Row");
is($g->name, 'bob', "generated row class has a named field accessor");
# autorow => prefix uses that namespace.
my $pfx = DBIx::QuickORM->quick(credentials => {dsn => $dsn}, autorow => 'My::QS::Row');
my ($p) = $pfx->handle('users')->all;
is(ref($p), 'My::QS::Row::Users', "autorow => prefix uses the given namespace");
is($p->name, 'bob', "prefixed row class has a named field accessor");
# Two generated namespaces do not collide.
my $gen2 = DBIx::QuickORM->quick(credentials => {dsn => $dsn}, autorow => 1);
my ($g2) = $gen2->handle('users')->all;
isnt(ref($g2), ref($g), "each autorow => 1 connection gets its own namespace");
};
subtest validation => sub {
like(
dies { DBIx::QuickORM->quick() },
qr/exactly one of 'credentials' or 'connect'/,
"must provide credentials or connect",
);
like(
dies { DBIx::QuickORM->quick(credentials => {dsn => $dsn}, connect => sub { }) },
qr/exactly one of 'credentials' or 'connect'/,
"cannot provide both",
);
like(
dies { DBIx::QuickORM->quick(credentials => {user => 'x'}) },
qr/dsn.*dbd|detect the dialect/,
"credentials need a dsn/dbd or an explicit dialect",
);
like(
dies { DBIx::QuickORM->quick(credentials => {dsn => $dsn}, bogus => 1) },
qr/Unknown parameter/,
"rejects unknown parameters",
);
};
done_testing;
t/AI/row_state.t view on Meta::CPAN
# Read a column straight from the database, bypassing the ORM and any
# row cache, so we can verify what was actually persisted.
sub db_value {
my ($col, $pk) = @_;
my $dbh = DBI->connect($dsn, '', '', {RaiseError => 1, PrintError => 0});
my ($val) = $dbh->selectrow_array("SELECT $col FROM users WHERE user_id = ?", undef, $pk);
$dbh->disconnect;
return $val;
}
my $con = DBIx::QuickORM->quick(credentials => {dsn => $dsn}, auto_types => ['JSON']);
isa_ok($con, ['DBIx::QuickORM::Connection'], "got a live Connection");
my $bob = $con->handle('users')->where({name => 'bob'})->one;
my $bob_pk = $bob->field('user_id');
ok(defined($bob_pk), "fetched bob and have a primary key");
subtest field_get_set_and_pending => sub {
ok($bob->is_stored, "freshly fetched row is stored");
ok($bob->in_storage, "freshly fetched row is in_storage");
ok($bob->is_valid, "freshly fetched row is valid");
t/AI/transaction_extra.t view on Meta::CPAN
my $dir = tempdir(CLEANUP => 1);
my $file = "$dir/txn.sqlite";
my $dsn = "dbi:SQLite:dbname=$file";
{
my $dbh = DBI->connect($dsn, '', '', {RaiseError => 1, PrintError => 0});
$dbh->do('CREATE TABLE items (item_id INTEGER PRIMARY KEY, name TEXT NOT NULL)');
$dbh->disconnect;
}
my $con = DBIx::QuickORM->quick(credentials => {dsn => $dsn});
# Independent connection used to confirm what is actually committed to disk.
# The ORM connection's own dbh would see uncommitted in-transaction writes, so
# we read through a separate handle to verify true persistence.
my $probe = DBI->connect($dsn, '', '', {RaiseError => 1, PrintError => 0});
sub disk_names {
my $rows = $probe->selectcol_arrayref('SELECT name FROM items ORDER BY name');
return [@$rows];
}
t/AI/type_json.t view on Meta::CPAN
my $file = "$dir/json.sqlite";
my $dsn = "dbi:SQLite:dbname=$file";
{
my $dbh = DBI->connect($dsn, '', '', {RaiseError => 1, PrintError => 0});
$dbh->do('CREATE TABLE docs (doc_id INTEGER PRIMARY KEY, label TEXT, payload_json TEXT)');
$dbh->do('INSERT INTO docs (label, payload_json) VALUES (?, ?)', undef, 'seed', '{"age":42,"tags":["x","y"]}');
$dbh->disconnect;
}
my $con = DBIx::QuickORM->quick(credentials => {dsn => $dsn}, auto_types => ['JSON']);
my ($seed) = $con->handle('docs')->all;
is(
$seed->field('payload_json'),
{age => 42, tags => ['x', 'y']},
"auto-typed *json* column inflated the seeded row to a structure",
);
my $struct = {nums => [3, 2, 1], nested => {a => 1}};
my $new = $con->handle('docs')->insert({label => 'fresh', payload_json => $struct});
is($new->field('payload_json'), $struct, "JSON round-tripped on insert");
# Re-fetch from a fresh connection so we read what was actually stored.
my $con2 = DBIx::QuickORM->quick(credentials => {dsn => $dsn}, auto_types => ['JSON']);
my ($fetched) = $con2->handle('docs')->where({label => 'fresh'})->all;
is($fetched->field('payload_json'), $struct, "stored JSON read back from a new connection");
# The raw stored value is a JSON string, not Perl-serialized.
my $dbh = DBI->connect($dsn, '', '', {RaiseError => 1, PrintError => 0});
my ($raw) = $dbh->selectrow_array('SELECT payload_json FROM docs WHERE label = ?', undef, 'fresh');
$dbh->disconnect;
like($raw, qr/^\{.*\}$/, "stored value is a JSON document string");
is(Cpanel::JSON::XS::decode_json($raw), $struct, "raw stored JSON decodes back to the struct");
};
t/AI/type_uuid.t view on Meta::CPAN
{
my $dbh = DBI->connect($dsn, '', '', {RaiseError => 1, PrintError => 0});
# "user_uuid" exercises substring name matching; SQLite gives it TEXT
# affinity, so deflation uses the string form.
$dbh->do('CREATE TABLE accounts (account_id INTEGER PRIMARY KEY, label TEXT, user_uuid TEXT)');
$dbh->do('INSERT INTO accounts (label, user_uuid) VALUES (?, ?)', undef, 'seed', $SAMPLE);
$dbh->disconnect;
}
my $con = DBIx::QuickORM->quick(credentials => {dsn => $dsn}, auto_types => ['UUID']);
my ($seed) = $con->handle('accounts')->all;
is($seed->field('user_uuid'), $SAMPLE, "substring-named *uuid* column auto-typed and inflated");
my $fresh = $C->new;
my $new = $con->handle('accounts')->insert({label => 'fresh', user_uuid => $fresh});
is($new->field('user_uuid'), $fresh, "UUID round-tripped on insert");
# Read back from a fresh connection.
my $con2 = DBIx::QuickORM->quick(credentials => {dsn => $dsn}, auto_types => ['UUID']);
my ($fetched) = $con2->handle('accounts')->where({label => 'fresh'})->all;
is($fetched->field('user_uuid'), $fresh, "stored UUID read back from a new connection");
my $dbh = DBI->connect($dsn, '', '', {RaiseError => 1, PrintError => 0});
my ($raw) = $dbh->selectrow_array('SELECT user_uuid FROM accounts WHERE label = ?', undef, 'fresh');
$dbh->disconnect;
is($raw, $fresh, "raw stored value is the hyphenated UUID string for a TEXT column");
};
done_testing;
t/interface.t view on Meta::CPAN
{
name => 'from_creds',
user => 'username',
pass => 'password',
socket => 'socketname',
dialect => 'DBIx::QuickORM::Dialect::PostgreSQL',
created => T(),
compiled => T(),
},
"Got credentials from subroutine",
);
schema deeptest => sub {
row_class "ClassA";
table foo => sub {
row_class "ClassB";
db_name 'foo1';
column a => 'MyType';
column b => \'VARCHAR(123)', 'string';
column c => sub {