The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Class::PObject::Driver::file - Default PObject driver

SYNOPSIS

  pobject Person => {
    columns   => ['id', 'name', 'email']
    datasource=> 'data'
  };

DESCRIPTION

Class::PObject::Driver::file is a default driver used by Class::PObject. Class::PObject::Driver::file is a direct subclass of Class::PObject::Driver. Refer to its manual for more details.

The only required class property is columns. If driver is missing, Class::PObject will default to file automatically. If datasource is missing, the driver will default to your system's temporary directory, which is /tmp on most *nix systems, and C:\TEMP on Windows.

This data source is a folder in your operating system, inside which objects will be stored. Pobject will create a folder for each object type inside the datasource folder, and will store all the objects of the same type in their own folders.

SUPPORTED FEATURES

Class::PObject::Driver::file overrides following methods of Class::PObject::Driver

  • save()

  • load()

  • remove()

In addition to standard methods, it also defines following methods of its own. These methods are just private/utility methods that are not invoked by PObjects directly. But knowledge of these methods may prove useful if you want to subclass this driver to cater it to your needs.

  • load_by_id($self, $pobject_name, \%properties, $id) is called from within load() method when an object is to be loaded by id. This happens if the pobject invokes load() method with a single digit:

        $article = Article->load(443)

    This is the most efficient way of loading objects using file driver.

    Although the effect of saying

        $article = Article->load({id=>443})

    is the same as the previous example, the latter will bypass optimizer, thus will not invoke load_by_id() method.

  • generate_id($self, $pobject_name, \%properties) is called whenever a new object is to be stored and new, unique ID is to be generated.

  • _dir($self, $pobject_name, \%propertries) is called to get the path to a directory where objects of this type are to be stored. If the directory hierarchy doesn't exist, it will create necessary directories automatically, assuming it has necessary permissions.

  • _filename($self, $pobject_name, \%properties) is called to get a path to a file this particular object should be stored into. _filename() will call _dir() method to get the object directory, and builds a filename inside this directory.

  • freeze($self, \%data) and thaw($self, $string) are used to serialize and de-serialize the data to make it suitable for storing into disk. By default freeze() and thaw() use Data::Dumper. If you want to use some other method, you can subclass Class::PObject::Driver::file and define your own freeze() and thaw() methods:

        # Inside Class/PObject/Driver/my_file.pm
        package Class::PObject::Driver::my_file;
        use base ('Class::PObject::Driver::file');
        require Storable;
    
        sub freeze {
            my ($self, $data) = @_;
            return Storable::freeze($data)
        }
    
        sub thaw {
            my ($self, $string) = @_;
            return Storable::thaw($string)
        }
    
        1;
    
        # Inside Article.pm, for example:
        package Article;
        pobject {
            columns => ['id', 'title', 'author', 'content'],
            driver  => 'my_file'
        };

OBJECT STORAGE

Each object is stored as a separate file. File name pattern for each object file is defined in $Class::PObject::Driver::file::f global variable, is is obj%05.cpo by default, where %05 will be replaced with the id of the object, zeroes padded if necessary.

Note: extension '.cpo' stands for Class::PObject.

SERIALIZATION

Objects are serialized using standard Data::Dumper

ID GENERATION

file driver keeps its own record counter for generating auto-incrementing values for subsequent records more efficiently. Record counter is stored inside the object directory (_dir() method returns the path to this folder) in a file called "counter.cpo".

WARNING

Removing counter.cpo from the directory will force PObject to reset object ids. This may be a problem if there already are objects in the directory, and they may be overridden by new ids. I realize this is a scary limitation, which will be eventually addressed.

In the meanwhile, just don't make habit of removing counter.cpo!

EFFICIENCY

Since the driver doesn't keep an index of any kind, the most efficient way of loading the data is by its id. A relatively simple load(undef, {limit=n})> syntax is also relatively fast.

  my $p       = Person->load(451);
  my @people  = Person->load();
  my @group   = Person->load(undef, {limit=>100});

as load() becomes complex, the performance gets degrading:

  my @people = Person->load({name=>"Sherzod"}, {sort=>'age', direction=>'desc', limit=>10, offset=>4});

To perform the above search, the driver walks through all the objects available in the datasource, pushes all the objects matching 'name="sherzod"' to the data-set, then, just before returning the data set, performs sort, limit and offset calculations.

As you imagine, as the number of objects in the datasource increases, this operation will become more costly.

SEE ALSO

Class::PObject, Class::PObject::Driver::mysql, Class::PObject::Driver::file

AUTHOR

Sherzod Ruzmetov <sherzodr@cpan.org>