NAME
    XAO::DO::FS::Hash - Core data class for XAO::FS

SYNOPSIS
     my $data=XAO::Objects->new(objname => 'FS::Hash');

     $data->put(aaa => 123);

     my $aaa=$data->get('aaa');

DESCRIPTION
    This is a core data class for XAO Foundation Server (see XAO::FS). All
    data classes are based on FS::Hash and for that matter FS::Hash can be
    considered pure virtual class which you would never want to use
    directly.

    A data object can contain arbitrary number of named single-value
    parameters and arbitrary number of list objects. Whenever you need more
    than one count of something you will have to create a list object to
    store those things. For example if you only have one shipping address
    per customer - you can store it as a couple of properties in Customer
    object, but if you want a customer to have an address book - create list
    object named Addresses and store addresses inside of it.

    Any data object at any given time can be in either attached state
    (stored in some List and connected to the database) or in detached state
    (when it is not connected to the database layer all manipulations on
    object's properties only change memory).

    Detached data object can be at any time re-attached to a container or
    stored under different ID. That allows a developer to have increased
    performance when required by detaching an object and then using
    in-memory copy.

    When an object is attached all data manipulations are done directly on
    database and never cached. Reasonable measures should be taken by
    developer to ensure that it is safe to re-attach an object to the
    database because the content of the object would replace current
    database content. Object server does not try to map any changes that you
    make to the database back to the detached object. Once detached the
    object is on its own.

    Here is the entire API that is available in all objects based on the
    FS::Hash class. It is not recommended to override or extend any of these
    methods unless stated otherwise in method description. Methods are
    listed in alphabetical order.

    add_placeholder (%)
        Modifies database scheme by adding new possible parameter name into
        the object. After you call this method you can call put() and get()
        on the name you have added.

        The operation can take some time especially if you have a lot of
        objects of that type in the database because it have to modify
        database tables and add new field.

        Arguments are (alphabetically):

        class
            Only makes sense for 'list' type - sets the name of class for
            the objects that would be contained in the list. That class have
            to exist and be available for object loader at the time of the
            call.

        charset
            For fields of 'text' type this can be one of 'binary', 'latin1',
            or 'utf8'. For compatibility with older version that did not
            have a dedicated 'blob' data type the default charset is
            'binary'.

            Fields of 'latin1' or 'utf8' charset have no guaranteed
            behaviour on characters not defined for these charsets. Such
            characters can be skipped or converted to '?' for instance.

            'Binary' charset fields will accept any data just like 'blob'
            data type, but the sorting order and word matching in search may
            differ from older versions. As another side effect, searches on
            'binary' charset fields are case sensitive.

            NOTE: The 'utf8' charset only supports the Basic Multilingual
            Plane characters (0x0000-0xffff). These characters in UTF-8
            encoding are guaranteed to take up from 1 to 3 bytes.
            Supplemental Unicode planes are not supported.

        connector
            Optional name of the key that would refer objects in the list to
            the object they are contained in. Default is 'parent_unique_id',
            you can change it to something more meaningfull so that it would
            make sense for somebody looking at the plain SQL tables.

        default
            Sets default values that would be returned from get() when no
            content is available. Valid only for data types. Defaults to 0
            or minvalue if zero is not in the range for 'real' and 'integer'
            types and empty string for 'text'.

            Maximum length of the default text is limited to 30 characters
            regardless of the 'maxlength'.

        index
            Optional parameter that when set to non-zero value suggests that
            you are going to use this field in searches a lot. This works
            especially good on `real' and `integer' fields when you later
            search on them using ranges or equivalence.

            Note, that indexing text fields works mostly on 'eq', 'ne', and
            'sw' search operators, not 'cs', 'ws', or 'wq'.

            Regardless of your use of indexes searches are guaranteed to
            produce equal results. Indexing can only improve performance (or
            decrease it when used incorrectly).

        key Name of the key that would identify objects in the list.
            Required if you add a 'list' placeholder.

            When possible it is recommended to name the key as the class
            name or some derivative from it with '_id' suffix. If you add
            Orders list placeholder it is recommended to call the key
            'order_id'.

        key_charset
            Charset to be used for the list key. Default is 'binary' which
            should be sufficient for the majority of applications.

        key_format
            Only for 'list' placeholders. Specifies format of the
            auto-generated keys for a single argument put() method on Lists
            (XAO::DO::FS::List).

            Key format consists of normal alpha-numeric characters and may
            include several special sequences:

            <$RANDOM$>
                Random 8-character sequence as generated by
                XAO::Utils::generate_key() function. It never evaluates to
                'false' in perl sense, always starts from a letter and has
                some other constraints - see XAO::Utils for details.

            <$AUTOINC$>
                This is an auto-incrementing unsigned at least 32-bit
                integer value. It is not guaranteed to be continuously
                incrementing, but new value is always greater than any
                previously assigned and greater than zero. There is no
                definition of what would happen if all integer values are
                used up.

                Can optionally have number of digits specified -
                <$AUTOINC/10$> to generate 10 digits integers. Default is to
                use minimum possible number of digits.

            <$GMTIME$>
                Seconds GMT since Epoch.

            <$DATE$>
                Current date and time in YYYYMMDDHHMMSS format.

            One of <$AUTOINC$> or <$RANDOM$> must present in the key format
            as otherwise it is impossible to guarantee key uniqueness.

            The default key format is '<$RANDOM$>'.

            Examples:

             V<$AUTOINC$>        - V1, V2, V3, ..., V12345
             <$DATE$>_<$RANDOM$> - 200210282218_QWERT123
             NUM<$AUTOINC/12$>   - NUM000000000001, ..., NUM000000012345

        key_length
            Maximum allowed key length, default is 30 (the same as maximum
            field name length in Hashes for consistency reasons).

        maxlength
            Maximum length for 'text' type in bytes (so for 'utf8' charset
            you may store less characters than the maxlength depending on
            the data). If later on you will try to store longer text string
            into that field an error will be thrown.

            Default is 100, but using default length is deprecated -- it may
            become illegal in future versions.

        maxvalue
            Optional maximum possible value for `integer' and `real'
            properties, inclusive. Default is 2147483647 for integer
            property if minvalue is negative and 4294967295 if minvalue is
            zero or positive. Larger values will force the database field to
            be a 64-bit integer.

            For the MySQL driver, the storage and performance might improve
            when you use the smallest possible range for your values. The
            database data type will be the smallest that fits the range
            (tinyint, smallint, etc).

            The value of 'maxvalue' can only be an integer, even for 'real'
            properties.

        minvalue
            Optional minimum possible value for `integer' and `real'
            properties, inclusive. Default is -2147483648 for integer
            properties.

            For the MySQL driver, if you use a positive value or zero for
            integer properties, the database type will use an 'unsigned'
            qualifier.

        scale
            Only makes sense for 'real' type. When set the field is stored
            as a fixed precision decimal with guaranteed math properties (as
            opposed to plain 'real' values where there may not be a way to
            store exactly 3.0 for example).

        name
            Placeholder name -- this is the name you would then use in put()
            and get() to access that property.

            It is recommended to name single-value properties in
            all-lowercase with underscores to separate words (like
            "middle_name") and name lists in capitalized words (like
            "Addresses"). Names have to start from letter and can consist of
            only letters, digits and underscore symbol.

        table
            Optional table name for 'list' type placeholder. If not defined
            it would be created from class name (something like
            'osCustomer_Address' for 'Customer::Address' class).

        type
            Placeholder type, one of 'text', 'blob', 'integer', 'unsigned',
            'real' or 'list'.

        unique
            If set to non-zero value then this property will have to be
            filled with values that are unique troughout the entire class.
            Placeholder with that modifier can only be added when there are
            no objects of that class in the database.

        An example of adding new single-value property placeholder:

         $customer->add_placeholder(name      => 'middle_name',
                                    type      => 'text',
                                    maxlength => 10);

         $customer->put(middlename => 'Jr.');

        An example of adding new list of properties placeholder:

         $customer->add_placeholder(name  => 'Addresses',
                                    class => 'Customer::Address',
                                    key   => 'address_id');

         my $adlist=$customer->get('Addresses');

         $adlist->put('addr001' => $address);

        NOTE: A placeholder added to an object in fact adds it to all
        objects of the same class regardless of their status - attached or
        detached.

    build_structure (%)
        Convenience method that checks object structure and adds specified
        placeholders if they do not currently exist.

        If any existing field has a different description than supplied
        build_structure() method will adjust the database structure when
        possible, or throw an error if an automatic adjustment is not
        supported.

        Upon return, the object will have at least the given fields. It can
        have some extra fields that were on the object before, but given
        fields guaranteed to exist and have the same descriptions as
        provided. The list of extra fields is returned.

        Example:

         $customer->build_structure(
             Orders => {
                 type => 'list',
                 class => 'Data::Order',
                 key => 'order_id',
                 structure => {
                     total => {
                         type => 'integer',
                         minvalue => 0,
                     },
                 },
             },
             first_name => {
                 type => 'text',
                 maxlength => 100
             },
             last_name => {
                 type => 'text',
                 maxlength => 100
             });

    sync_structure (%)
        Build the given structure (similarly to build_structure()) and drop
        all fields that are not mentioned in the given structure definition.

        DANGER: This routine can irreversibly delete table fields and whole
        tables.

    collection_key ()
        Returns the same ID of the object that would be used be a collection
        object holding this object. See XAO::DO::FS::Collection and
        collection() method on the glue object.

        Will return undef on detached objects.

    container_key ()
        If current object is not on top level returns key that refers to the
        current object in the container object that contains current object.

        Will return undef if current object was created with "new" and had
        never been stored anywhere.

    container_object ()
        If current object is not on top level returns container object that
        contains current object. For Global object will return `undef'.

        Will throw an error if current object was created with get_new()
        method or something similar.

        Example:

         my $orders_list=$order->container_object();

    defined ($)
        Obsolete since version 1.03 when the concept of existing, but
        undefined value was eliminated for simplicity. Values are always
        defined -- therefore this method will either return true or throw an
        error if the name is not correct.

    delete ($)
        Deletes content of the given property. If you use get() on the
        deleted property you will get empty List for `list' properties or
        `undef' for value properties.

        NOTE: If the name you gave refers to a contained object then
        destroy() method would be called on that object. List object would
        then unlink all its contained object and if that was the only place
        they were linked into then these object would be destroyed too. Be
        careful with delete() method.

        Delete() method would not alter database structure. It can leave
        some tables empty, but it would not change relations scheme.

    describe ($)
        Returns a hash reference that contains description of the given
        field. The format is exactly like you would pass to
        add_placeholder() method.

        Can be used to check limitations and field types. Will return
        `undef' on non-existing fields.

        Example:

         my $description=$customer->describe('first_name');
         print "Type: $description->{'type'}\n";
         print "Maximum length: $description->{'maxlength'}\n";

    destroy ()
        Deletes everything inside the current object -- an alias for the
        following code:

         foreach my $key ($customer->keys) {
             $customer->delete($key);
         }

    detach ()
        Detaches current object from its container and from database.
        Detaching an object leads to detaching every object it contains to
        the deepest possible level.

        Once an object is detached it "remembers" a place where it was
        attached and can be re-attached later.

        No changes in the database data would be propagated to the detached
        object and no changes in the detached object would ever change the
        database. An exception is add_placeholder() and drop_placeholder()
        methods that operate on all objects of the same type regardless of
        their status -- detached or attached.

        NOT IMPLEMENTED YET. Almost all supporting infrastructure is in
        place, but currently the only way to get a detached object is to
        call get_new() on List object.

        It is safe to call detach() though. You should do that in places
        where you think this is appropriate. Like that:

         # Printing all properties. Detach() will load all the values into
         # memory and allow speedy prints. The code will work in exactly the
         # same way with or without detach() but once detach() is implemented
         # there would be speed up.
         #
         my $obj=$customers->get($customer_id);
         $obj->detach();
         foreach my $key ($obj->keys) {
             my $value=$obj->get($key);
             if(ref($value)) {
                 print "obj{$key}=List (" . $value->uri . ")\n";
             }
             else {
                 print "obj{$key}='$value'\n";
             }
         }

    drop_placeholder ($)
        Deletes placeholder and all values stored in the field being deleted
        in all Hash objects. Be careful!

        It might take considerable amount of time to finish if you have
        large database.

        Example:

         $customer->drop_placeholder('Orders');

        There is currently no way to rename a placeholder. You can create
        new one, copy data from the old one to the new one and then drop old
        one.

        If you drop a list placeholder it will effectively chop off entire
        branch that starts at that placeholder and drop all related tables
        in the SQL database.

    exists ($)
        Checks if there is a placeholder for the given key. Here is an
        example:

         if(! $customer->exists('middle_name')) {
             print "No placeholder for 'middle_name' exists in the database\n";
         }

        Not the same as defined() which just checks if given property has
        value or not. Property can have placeholder and still be undefined.

    fetch ($)
        Takes URI style path and returns an object or property referenced by
        that path. If path starts with slash (/) then it goes from the top,
        otherwise - from the current object. Counting objects from top would
        always give you connected object or undef.

        Examples:

         my $zip001=$customer->fetch('Addresses/addr001/zipcode');

         my $customers=$address->fetch('/Customers');

        Currently is only implemented on Glue, relative URI are not
        supported.

    fill (%)
        Takes a hash or another object of the same type and merges all the
        data from it into the current object.

        NOT IMPLEMENTED.

    get ($)
        Retrieves data field or a list reference from the object.

        Example:

         my $addresses_list=$customer->get('Addresses');

         my $first_name=$customer->get('first_name');

        As a convenience (and an optimisation, because database driver would
        be able to optimise that into just one query into database in most
        cases) you can pass more than one property name into the get()
        method. In that case it will return you an array of values in the
        same order that you passed property names.

         my ($name,$phone,$fax)=$customer->get('name','phone','fax');

    glue ()
        Returns the Glue object which was used to retrieve the current
        object from.

    is_attached ()
        Boolean method that returns true if the current object is attached
        or false otherwise.

    keys ()
        Returns list of field names and list names stored in that object.
        Excludes connectors and unique_id.

        Example:

         foreach my $key ($object->keys) {
            my $value=$object->get($key);
            print "object.$key=$value\n";
         }

    new (%)
        Creates new instance of a Hash object. Would not work if called
        directly, XAO::Objects' new() method should always be used instead.

        Example:

         my $obj=XAO::Objects->new(objname => 'Data::Customer',
                                   glue => $glue);

        One required argument is 'glue', it must contain a reference to
        XAO::DO::FS::Glue object.

        As a convenience it is recommended to call get_new() method on the
        list object to get new empty detached objects of the class that list
        can store. If you do so first you will not forget to pass `glue' as
        get_new() will do that for you and second if later on the name of
        the class will change you will not have to worry about that.

        Example:

         my $customer=$customers_list->get_new();

    objname ()
        Returns class name of the object.

    objtype ()
        For all objects based on Hash returns 'Hash' string.

    put (%)
        Stores new value into the Hash object. Values can currently only be
        strings and numbers, you cannot store a list.

        On attached objects your changes go directly into the database. On
        detached objects changes accumulate in memory and only get stored
        into the database when you put() that object into an attached list.

        Example:

         $customer->put(full_name => 'John Silver');

        Name must correspond to a previously defined placeholder otherwise
        an error will be thrown.

        Value must meet constrains set for the placeholder, otherwise error
        will be thrown and no changes will be made.

        More than one name/value pair can be given on the same line. For
        example, all three code snippets below will have the same effect,
        but first will be slower:

         # One by one, the slowest way.
         #
         $obj->put(first_name => 'John');
         $obj->put(last_name => 'Silver');
         $obj->put(age => '50');

         # Hash-like array, will translate to one SQL update statement.
         #
         $obj->put(first_name => 'John', last_name => 'Silver', age => 50);

         # Hash reference
         #
         my %data=(
            first_name  => 'John',
            last_name   => 'Silver',
            age         => 50,
         );
         $obj->put(\%data);

    reattach ()
        The same as to call put() method on upper level container. Works
        only for detached objects and does nothing if the object is already
        attached.

        Note: entire content of an object currently stored in the database
        would be replaced with current object recursively. Be careful!

        All attached objects that refer to the same piece of data would
        immediately start returning updated values on calls to get() method.

        Not implemented yet. Call put() on the list instead to attach the
        object.

    upper_class (;$)
        Returns class name for the hash that contained the list that
        contained current hash object.

    values ()
        Returns a list of all property values for the current object
        including its contained Lists if any.

        Note: the order of values is the same as the order of keys returned
        by keys() method. At least until you modify the object directly on
        indirectly. It is not recommended to use values() method for the
        reason of pure predictability.

    uri ($)
        Returns complete URI to either the object itself (if no argument is
        given) or to a property with the given name.

        That URI can then be used to retrieve a property or object using
        $odb->fetch($uri). Be aware, that fetch() is a relatively slow
        method and should not be abused.

        Example:

         my $uri=$customer->uri;
         print "URI of that customer is: $uri\n";

AUTHORS
    Copyright (c) 2005 Andrew Maltsev

    Copyright (c) 2001-2004 Andrew Maltsev, XAO Inc.

    <am@ejelta.com> -- http://ejelta.com/xao/

SEE ALSO
    Further reading: XAO::OS, XAO::DO::FS::List (aka FS::List),
    XAO::DO::FS::Glue (aka FS::Glue).

