Konstantin Stepanov


FusqlFS::Artifact - basic abstract class to represent database artifact in FusqlFS


    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);


    sub get_table_fields
        my $self = shift;
        my ($table) = @_;
        # fetches and returns field name => type hashref.


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.


Abstract interface methods


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.


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 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.


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.


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.


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.


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.


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


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, and sprintf() will be called to populate this string with values from @sprintf array.

The difference between expr and cexpr 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, while cdo 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


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".


Validates input data against a set of simple rules.

Input: $data, $rule, $overrule. Output: $validated_data|undef.

A rule can be:


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.


Ref of data value must be equal to this rule's value. If undef, data value must be simple scalar.


Every element in rule's array is a subrule, data value must match against all of the subrules.


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.


Helper validation function, creates "validate" rule to check if given value is a set with elements from given variants set.

Input: @variants. Output: $rule.


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".


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 with undefs to the right up to this number, so output always contain $max_chunks elements.


Joins chunks with configured split character as a glue.

Input: @chunks. Output: $string.

It is opposite of "asplit".


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).


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 using bind_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.


Static method. Extended sprintf version.

Input: $format, $binds. Output: $string.

The $format is the same as for sprintf, $binds is either an arrayref or a hashref. If it is an arrayref the result of the method is the same as of sprintf($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, where x is any sprintf compatible conversion and key 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.


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


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.


Returns configured split character.

Output: $fnsep.


Extend one hash with other hash inplace.

Input: $hashref, ... Output: $hashref


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") from FusqlFS::Backend::SomeEngine::Tables package, two packages will be imported and instantiated with new() method call (without arguments): FusqlFS::Backend::SomeEngine::Table::Indices and FusqlFS::Backend::SomeEngine::Table::Struct. Each instance will be put into $self->{subpackages} hash under indices and struct 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'