NAME
FusqlFS::Artifact - basic abstract class to represent database artifact in FusqlFS
SYNOPSIS
package FusqlFS::Backend::PgSQL::Tables;
use parent 'FusqlFS::Artifact';
sub init
{
my $self = shift;
# initialize Tables specific resources
}
sub get
{
my $self = shift;
my ($table, $name) = @_;
return $self->one_row("SELECT * FROM %s WHERE id = ?", [$table], $name);
}
sub list
{
my $self = shift;
my ($table) = @_;
return $self->all_col("SELECT id FROM %s %s", [$table, $self->limit]);
}
sub store
{
my $self = shift;
my ($table, $data) = @_;
my $row = $self->validate($data, {
id => qr/^\d+$/,
-func => '',
}) or return;
my $func = $row->{func}? $row->{func}.'(?)': '?';
my $sth = $self->build("UPDATE $table SET ", sub{
my ($k, $v) = @_;
return " WHERE " unless $k;
return " $k = $func ", $row->{$k}, $v;
}, %{$self->get_table_fields($table)},
'' => '',
id => SQL_INTEGER);
$sth->execute();
}
sub get_table_fields
{
my $self = shift;
my ($table) = @_;
# fetches and returns field name => type hashref.
}
DESCRIPTION
This abstract class declares interface between database artifacts (like tables, data rows, functions, roles etc.) and Fuse hooks in FusqlFS.
The point of this class is to abstract database layer interaction from file system structure operations, so it provides some basic operations under database artifacts like "get", "list", "create", "drop", etc.
For example FusqlFS::Backend::PgSQL::Tables subclass defines it's get method to return table's description and list method to list all available tables, so this subclass is represented as directory with tables in file system.
For more examples see childrens of this class.
METHODS
Abstract interface methods
- new
-
Base constructor, shouldn't be overridden in most cases. Use "init" method to initialize object instance.
Override it only if you really know what you do and you have no other way to achieve you goal.
Input: $class Output: $artifact_instance.
- init
-
Abstract method called on object instance (
$self
) by constructor "new" immediately after instance is created and blessed in order to initialize it.All parameters given to constructor are passed to this method intact, value returned by this method is ignored.
Override this method instead of "new" in order to initialize your class.
- get
-
Get item from this artifact.
Input: @names. Output: $hashref|$arrayref|$scalarref|$coderef|$scalar|undef.
Hashrefs and arrayref are represented as directories in filesystem with keys (or indices in case of arrayref) as filenames and values as their content (maybe hashrefs or arrayrefs as well).
Scalarrefs are represented as symlinks, their content being the path to referenced object in filesystem.
Coderefs provide "pseudopipes" interface: at first request referenced sub is called without parameters for initialization and file content will be whatever the sub returns. On any write to the "pseudopipe" the sub is called with written data as first argument and the content of the file will be any text the sub returns back. Dynamic DB queries in FusqlFS::Backend::PgSQL::Queries class are implemented with this interface.
Scalars are represented with plain files.
If this sub returns undef the file with given name is considered non-existant, and user will get
NOENT
error. - list
-
Get list of items, represented by class.
Input: @names. Output: $arrayref|undef.
If this method returns arrayref of scalars, then the class is represented with directory containing elements with names from this array, otherwise (the method returns undef) the type of filesystem object is determined solely on "get" method call results.
- rename
-
Renames given database artifact.
Input: @names, $newname. Output: $success.
This method must rename database object defined with @names to new $newname and return any "true" value on success or undef on failure.
- drop
-
Removes given database artifact.
Input: @names. Output: $success.
This method must drop given database object defined with @names and return any "true" value on success or undef on failure.
- create
-
Creates brand new database artifact.
Input: @names. Output: $success.
This method must create new database object by given @name and return any "true" value on success or undef on failure. If given object can't be created without additional "content" data (e.g. table's index) it should create some kind of stub in memory/cache/anywhere and this stub must be visible via "get" and "list" methods giving the user a chance to fill it with some real data, so successive "store" call can create the object.
- store
-
Stores any changes to object in database.
Input: @names, $data. Output: $success.
This method must accept the same $data structure as provided by "get" method, possibly modified by user, and store it into database, maybe creating actual database object in process (see "create" for details). The method must return any "true" value on success or undef on failure.
DBI interface methods
- dbh
-
Returns underlayed DBI handler.
Output: $dbh.
- expr, cexpr
-
Prepare expression with $dbh->prepare() or $dbh->prepare_cached().
Input: $sql, @sprintf. Output: $sth.
If
@sprintf
is not empty,$sql
must be a scalar string with printf-compatible placeholders, andsprintf()
will be called to populate this string with values from@sprintf
array.The difference between
expr
andcexpr
is the first calls "prepare" in DBI and the second calls "prepare_cached" in DBI. - do, cdo
-
Prepare and execute expression just like "do" in DBI.
Input: $sth, @binds or $sql, $sprintf, @binds. Output: $result.
Both of them can take either SQL statement as a scalar string or prepared DBI statement in place of first argument.
If the first argument is a scalar string, the second argument can be either an arrayref or a hashref, and if it is, the string must be printf-compatible format string and "hprintf()" will be used to populate SQL statement with values from second argument just like with expr.
do
just calls "do" in DBI and returns success value returned with it, whilecdo
calls "prepare_cached" in DBI and returns this prepared statement in case it was successfully executed, undef otherwise. - one_row, one_col, all_col, all_row
-
Executes given statement and returns well formatted result.
Input: $sth, @binds or $sql, $sprintf, @binds. Output: $result.
Basicly these methods accept the same arguments (and process them the same way) as do, but return results in format better suited for immediate usage.
one_row
returns the first row as hashref with field names as keys and field values as values.all_col
returns arrayref composed from first field values from all result rows.all_row
returns arrayref composed from hashrefs, where each hashref represents data row with field names as keys and field values as values.one_col
returns single scalar - the value of first field of first record fetched by query.
Data manipulation methods
- load
-
Parses input data in configured string format (e.g. YAML, JSON or XML) and returns perl structure (hashref or arrayref).
Input: $string_data. Output: $parsed_data.
Uses configured parser to deserialize plain string and produce perl structure (usually a hashref). In case of parsing failure returns undef.
If
$string_data
is not a plain string, this method returns this value intact, so you can call this method on input data any number of times just to make sure they are correct perl structure, not a serialized data.It is opposite of "dump".
- validate
-
Validates input data against a set of simple rules.
Input: $data, $rule, $overrule. Output: $validated_data|undef.
A rule can be:
- Hashref
-
The input data must be a hashref, every field in from rule's hash must also exist in data hash, rule's hash values are subrules to be matched against data's hash values. Hash keys with minus as first char are optional.
If input data is a scalar, it will be parsed with standard loader using "load" method, and validation will fail if
load()
call is. - Scalar
-
Ref of data value must be equal to this rule's value. If undef, data value must be simple scalar.
- Arrayref
-
Every element in rule's array is a subrule, data value must match against all of the subrules.
- Coderef
-
A subroutine referenced by the rule's value is called with data value as the first argument, it should return processed data if data is correct or undef if data is incorrect.
- Anything else
-
Data's value must magically match rule's value (with
~~
operator).
Optional third argument (
$overrule
) must be a coderef. It will be called with $_ locally set to parsed data and must return boolean value. If this value is false, then all data is discarded and validation fails, otherwise everything is ok. - set_of
-
Helper validation function, creates "validate" rule to check if given value is a set with elements from given variants set.
Input: @variants. Output: $rule.
- dump
-
Convert perl structure into string of configured format (e.g. YAML, JSON or XML).
Input: $data. Output: $string.
Uses configured dumper to serialize perl structure into plain scalar string.
It is opposite of "load".
- asplit
-
Splits string using configured split character.
Input: $string, $max_chunks=undef. Output: @chunks.
It is opposite of "ajoin". Second optional argument is an integer, and is identical to one of
split
, i.e. sets max number of chunks to split input$string
into, but it also defines minimum number of chunks as well, so if$string
contains less than given$max_chunks
chunks, the result will be padded withundef
s to the right up to this number, so output always contain$max_chunks
elements. - ajoin
-
Joins chunks with configured split character as a glue.
Input: @chunks. Output: $string.
It is opposite of "asplit".
- concat
-
Produces SQL statement to join given data chunks with configured split character as a glue.
Input: @chunks. Output: $sql_clause.
It is opposite of "asplit" (in some sense).
- build
-
Builds SQL statement step by step from given configuration data chunks, prepares and binds it afterwards.
Input: $sql, $filter, %iter. Output: $sth.
$filter
must be a coderef,$sql
is a initial SQL statement value to build upon and%iter
is a series of key-value pairs (normally meant to be field value => build config pairs, but it is not carved in stone).For every key-value pair in
%iter
$filter->($key, $value)
is called in list context. It must return the next chunk of SQL which will be added to resulting SQL statement and an optional bind value to be associated with this SQL chunk. This bind value must be either a single bind value or a bind value and a configaration parameter for "bind_param" in DBI (i.e. third argument). If$filter
returns empty list (or undef, which is the same for list context) the iteration is silently skipped and the next pair from%iter
is taken.When
%iter
is depleted, constructed SQL statement is prepared, all gathered bind values are bound to it usingbind_param()
and the resulting statement handler is returned.So you can use this method to construct complex SQL statements using table driven SQL statements construction, producing finely tuned binds with correctly typed bind values.
- hprintf
-
Static method. Extended sprintf version.
Input: $format, $binds. Output: $string.
The
$format
is the same as forsprintf
,$binds
is either an arrayref or a hashref. If it is an arrayref the result of the method is the same as ofsprintf($format, @$binds)
. If it is a hashref the result is a little different.For hashref
$binds
all placeholders in$format
must be in the form of%(key)$x
, wherex
is anysprintf
compatible conversion andkey
is the key in the%$binds
, so that instead of positional placeholders substitution, placeholders in$format
are substituted with correspondent%$binds
' values.E.g. if you call
hprintf("%(msg)s: %(count)d\n", { msg => 'The counter is', count => 10 })
you will get the string"The counter is: 10\n"
as the result. This is really useful if you need to keep formatting strings loosely linked with real data inserted into them, e.g. in case of l10n with something like gettext. - adiff
-
Get difference between to arrays.
Input: $oldarray, $newarray. Output: $newitems, $olditems.
Gets two arrayrefs and returns two arrayrefs with items existing in $arrayref2 only (
$newitems
) and in $arrayref1 only ($olditems
).
Configuration methods
- limit
-
Returns configured
LIMIT ...
clause or empty string if it's not configured.Output: $limit_clause.
This method can be used to compose
SELECT ...
statements according to configured limit option. - fnsep
-
Returns configured split character.
Output: $fnsep.
- extend
-
Extend one hash with other hash inplace.
Input: $hashref, ... Output: $hashref
- autopackages
-
Automagically plug all designated packages and plug them in as subpackages.
It takes a list of names, each of them will be put to lower case and used as subpackages hash key (so it will be subdirectory name in mounted filesystem). Package name for each of the name will be formed with current package name put to singular form appended with the name with first letter put to upper case. All absent packages (which couldn't be imported without errors) will be ignored.
Each such subpackage will be instantiated with
new()
method call without arguments.Singular form of current package name is produced by removing last "s" from package name, which can be quite naive for some cases.
For example if you run
$self->autopackages("indices", "struct")
fromFusqlFS::Backend::SomeEngine::Tables
package, two packages will be imported and instantiated withnew()
method call (without arguments):FusqlFS::Backend::SomeEngine::Table::Indices
andFusqlFS::Backend::SomeEngine::Table::Struct
. Each instance will be put into$self->{subpackages}
hash underindices
andstruct
keys correspondingly.The method returns subpackages hashref in scalar context and linearized version of subpackages hash in list context.
See also: FusqlFS::Backend::Base for information about subpackages hash, FusqlFS::Entry for more information about file path resolution algorithm.
Input: $name, ... Output: $hashref
5 POD Errors
The following errors were encountered while parsing the POD:
- Around line 249:
L<> starts or ends with whitespace
- Around line 267:
L<> starts or ends with whitespace
- Around line 637:
'=item' outside of any '=over'
- Around line 639:
L<> starts or ends with whitespace
- Around line 701:
You forgot a '=back' before '=head2'