AmberDB

 view release on metacpan or  search on metacpan

lib/AmberDB.pm  view on Meta::CPAN


=head2 insert_links($table_id, @records)

Writes alias link bindings into the table's C<.lnk> routing index. Used specifically when duplicate records are deleted and consolidated/merged into a canonical record (requires C<use_alias =E<gt> 1> in table schema):

    # Map deleted duplicate ID 452 to canonical active ID 586
    $adb->delete_id("catalog_product", 452);
    $adb->insert_links("catalog_product", [ 452, 586 ]);

    # Multiple mappings in a single call
    $adb->insert_links("catalog_product", [ 452, 586 ], [ 453, 586 ]);

    # read_id queries for 452 will automatically/transparently fetch canonical record 586:
    my @rec = $adb->read_id("catalog_product", 452);

=head2 update_id($table_id, $record_id, @record)

Updates existing record data (alias: C<modify_id>). It automatically updates the search, match, slug, and facet indexes if they are defined in the table schema. It supports transact operations.

    $adb->update_id("catalog_product", 101, "Widget Pro v2", "Electronics", 1300);

=head2 modify_id($table_id, $record_id, @record)

Legacy alias for C<update_id>.

    $adb->modify_id("catalog_product", 101, "Widget Pro v2", "Electronics", 1300);

=head2 update_list($table_id, @records)

Modifies multiple records in a single bulk operation (alias: C<modify_list>). Aside from Transact, it processes records, search, match, slug, and facet indexes all at once with high performance.

    $adb->update_list("catalog_product",
        [ 101, "Item 1 Updated", "Category A", 150 ],
        [ 102, "Item 2 Updated", "Category B", 250 ],
    );

=head2 modify_list($table_id, @records)

Legacy alias for C<update_list>.

=head2 delete_id($table_id, $record_id)

Deletes specified record from table. Supports transaction logging.

    $adb->delete_id("catalog_product", 101);

=head2 delete_list($table_id, @records)

Deletes multiple records in a single bulk operation. Aside from Transact, it processes records, search, match, slug, and facet indexes all at once with high performance.

    $adb->delete_list("catalog_product", 101, 102, 103);

=head2 read_id($table_id, [$record_id], [\%options])

Reads a single record by primary key ID (or dynamic positional type) in $O(1)$ time.

Options:

=over 4

=item * C<type>: Positional selector (C<'last'>, C<'first'>, C<'rand'>). When specified, a dummy ID (e.g. C<0>) can be passed to preserve standard 3-argument positional signature consistency: C<< $adb->read_id("products", 0, { type => "last" }) >> (o...

=item * C<sort>: Optional sort block (numeric index, schema block name like C<"price">, C<"price desc">, or hashref C<< { block => "price", dir => "asc" } >>). Used in combination with C<< type => 'first' >> or C<'last'> to retrieve the first or last...

=item * C<range>: Optional numerical/chronological range filter hashref C<< { block => 4, min => 1000, max => 2000 } >> to constrain candidate records before positional selection.

=item * C<inflate>: Boolean (C<1> or string C<"inflate">) to inflate record fields into a named HASH reference based on table schema blocks.

=item * C<counter> / C<use_counter>: Explicit boolean (C<1> or C<0>) or string C<"counter"> to force or disable incrementing the read counter (C<.cnt>).

=item * C<no_counter>: Explicit boolean (C<1>) or string C<"no_counter"> to suppress incrementing the read counter.

=item * C<deleted> / C<force>: Boolean (C<1>) or string C<"deleted"> / C<"force"> to read from soft-deleted archive (C<.del>) if missing from active table.

=item * C<links> / C<alias>: Boolean (C<1>) or string C<"links"> / C<"alias"> to resolve a deleted/merged record ID from alias link index (C<.lnk>) to its canonical record.

=back

    # Standard array return: ($id, @fields)
    my @record = $adb->read_id("catalog_product", 101);

    # Inflate record into named HASH ref
    my $record_hash = $adb->read_id("catalog_product", 101, { inflate => 1 });
    # or shorthand string:
    my $record_hash = $adb->read_id("catalog_product", 101, "inflate");

    # Positional reads using type (consistent 3-arg with dummy ID 0 or 2-arg):
    my @last_rec  = $adb->read_id("catalog_product", 0, { type => "last" });
    my @first_rec = $adb->read_id("catalog_product", 0, { type => "first" });
    my @rand_rec  = $adb->read_id("catalog_product", 0, { type => "rand" });
    # with inflate:
    my $last_hash = $adb->read_id("catalog_product", 0, { type => "last", inflate => 1 });

    # Positional reads with sort by a specific block (first or last):
    my @cheapest = $adb->read_id("catalog_product", 0, { type => "first", sort => "price" });
    my @priciest = $adb->read_id("catalog_product", 0, { type => "last", sort => "price" });

    # Shorthand string options:
    my @rec_nc = $adb->read_id("catalog_product", 101, "no_counter");
    my @rec_dl = $adb->read_id("catalog_product", 101, "deleted");
    # Alias lookup (e.g. duplicate record 452 was deleted and merged/linked to 586):
    my @rec_lk = $adb->read_id("catalog_product", 452, "alias");

=head2 read_lastid($table_id, [\%options])

Convenience alias for:

    $adb->read_id($table_id, 0, { type => "last", %opts });

Supports passing a sort block directly, e.g.:

    $adb->read_lastid("catalog_product", "price");
    # or
    $adb->read_lastid("catalog_product", { sort => "price" });

=head2 read_firstid($table_id, [\%options])

Convenience alias for:

    $adb->read_id($table_id, 0, { type => "first", %opts });

Supports passing a sort block directly, e.g.:

    $adb->read_firstid("catalog_product", "price");
    # or

lib/AmberDB.pm  view on Meta::CPAN

    # Tiered query mode: 'A' (Active only), 'B' (Junk only), 'AB' (Active first, then Junk)
    my @active_only = $adb->read_all("catalog_product", { jnktype => 'A' });
    my ($total_count, @all_tiered) = $adb->read_all("catalog_product", { offset => 0, limit => 20, jnktype => 'AB' });

    # Return only scalar record IDs (memory-efficient pipeline)
    my ($count, @ids) = $adb->read_all("catalog_product", { offset => 0, limit => 50, keys_only => 1 });

    # Numerical / chronological range filtering (min defaults to 0 if omitted; max unbounded if omitted):
    my @in_range  = $adb->read_all("catalog_product", { range => { block => 4, min => 1000, max => 2000 } });
    my @min_only  = $adb->read_all("catalog_product", { range => { block => 'price', min => 1800 } });
    my @max_only  = $adb->read_all("catalog_product", { range => { block => 'price', max => 500 } });

=head2 read_list($table_id, \@id_list)

Reads multiple records matching provided ID list while preserving exact list ordering.

    # Read the entire active order list.
    my @records = $adb->read_all("order_active");

    # Extract customer IDs from block 1 using the map.
    my %customer_ids = map { $_->[1] => 1 } @records;

    # You've found the customer ID keys, now read them using read_list.
    my @customers = $adb->read_list("customers", [ keys %customer_ids ]);

=head2 field_fetch($table_id, $block, $value, [\%options])

Fetches records matching one or more block values using the C<.fld> match index (or sequential table scan fallback if unindexed). Supports multi-value queries, automatic deduplication, sorting, pagination, and C<keys_only>.

B<IMPORTANT (Return Signature Convention):>
When C<$limit> is passed and C<E<gt> 0> (paginated), C<field_fetch> returns C<($total_count, @records)> where the first scalar is the total matching count integer. When C<$limit> is omitted or C<0> (unpaginated), it returns C<@records> directly. Unpa...

    # 1. Unpaginated (returns array of record arrayrefs directly)
    my @records    = $adb->field_fetch("products", 1, "5");
    my @sorted_asc = $adb->field_fetch("products", 1, "5", { sort => -10 });

    # 2. Paginated (first element is total matching count integer)
    my ($total_count, @records) = $adb->field_fetch(
        "products", 1, "5",
        { offset => 0, limit => 20, sort => -10 }
    );

    # Multi-value matching (comma string, semicolon, or ARRAY ref)
    my @records = $adb->field_fetch("products", 1, ["5", "8"]);
    my @records = $adb->field_fetch("products", 1, "5, 8");

    # Return only record IDs: keys_only flag
    my @all_ids             = $adb->field_fetch("products", 1, "5", { keys_only => 1 });
    my ($total_count, @ids) = $adb->field_fetch("products", 1, "5", { offset => 0, limit => 20, keys_only => 1 });

    # Tiered Junk query mode
    my @active = $adb->field_fetch("products", 1, "5", { jnktype => 'A' }); # Only Active records

    # Numerical / chronological range filtering on an auxiliary block:
    my @range_prods = $adb->field_fetch("products", 2, "Smartphones", { range => { block => "price", min => 1000, max => 1500 } });

C<field_fetch> uses the C<match_block> definition in the schema and accesses inverted match index files (C<.fld>), providing $O(1)$ average-time lookup per indexed key (total retrieval cost scales with the number of requested values and matching reco...

=head2 search_table($table_id, $query, [\%options])

It performs searches matching query terms using the full-text C<.src> index (or a sorted table scan backup method if unindexed). C<search_table> uses the C<AmberDB::Locale> module. It features advanced language normalization according to the selected...

B<IMPORTANT (Return Signature Convention):>
When C<$limit> is passed and C<E<gt> 0> (paginated), C<search_table> returns C<($total_count, @records)> where the first scalar is the total matching count integer. When C<$limit> is omitted or C<0> (unpaginated), it returns C<@records> directly. Unp...

    # 1. Unpaginated (returns array of record arrayrefs directly)
    my @records        = $adb->search_table("catalog_product", "wireless headphones");
    my @sorted_records = $adb->search_table("catalog_product", "headphones", { sort => -5 });

    # 2. Paginated (first element is total matching count integer)
    my ($total_count, @search) = $adb->search_table("catalog_product", "headphones", { offset => 0, limit => 20 });
    my ($total_count, @search) = $adb->search_table(
        "catalog_product", "headphones",
        {
            offset  => 0,
            limit   => 20,
            sort    => -5,
            type    => "and",
            filter  => { field => 6, value => 12 },
            range   => { block => "price", min => 100, max => 500 },
            jnktype => 'AB',
        }
    );

    # Return only scalar record IDs
    my @all_ids             = $adb->search_table("catalog_product", "headphones", { keys_only => 1 });
    my ($total_count, @ids) = $adb->search_table("catalog_product", "headphones", { offset => 0, limit => 50, keys_only => 1 });

=head2 field_filter($table_id, \%filter_options)

Performs multi-block filtered queries (AND / OR) with support for multi-value filters, tier mode selection (C<jnktype>), numerical/chronological range filtering (C<range>), sorting, and pagination:

    my $res = $adb->field_filter("catalog_product", {
        type    => "and",
        filter  => { 1 => "5", 6 => ["12", "14"] },
        range   => { block => "price", min => 1000, max => 2500 },
        sort    => { blk => 5, reverse => 1 },
        jnktype => "AB",
        offset  => 0,
        limit   => 20,
    });
    # Returns: { count => $total, ids => \@matching_ids }

=head2 exist_id($table_id, $record_id)

Checks if a single record exists in the specified table. Returns 1 if present, 0 otherwise:

    my $exists = $adb->exist_id("catalog_product", 101);

=head2 exist_list($table_id, @record_ids)

Queries the presence of multiple record IDs in a single pass. Returns a hash reference C<{ id =E<gt> 1/0 }>:

    my $map = $adb->exist_list("catalog_product", 101, 102, 103);

=head2 exist_table($table_id, [$ext])

Checks whether the physical database table or index file exists on disk. C<$ext> defaults to C<$self-E<gt>{db_ext}> (C<'db'>):

    my $has_table = $adb->exist_table("catalog_product");
    my $has_index = $adb->exist_table("catalog_product", "inx");

=head2 table_count($table_id)

Returns the total number of records in the specified table. Reads from the primary C<.inx> index if enabled, or scans the main table:

    my $total_records = $adb->table_count("catalog_product");

=head2 table_keys($table_id)

Returns an array of all record IDs present in the table (retrieved from memory cache, C<.inx> index, or sequential table scan):

    my @all_ids = $adb->table_keys("catalog_product");

=head2 table_lastid($table_id)

Returns the highest / auto-increment primary key ID currently allocated in the table:

    my $last_id = $adb->table_lastid("catalog_product");

=head2 table_info($table_id)

Loads and returns the table schema definition (hash reference). Automatically ensures metadata fields:
- C<table>: table identifier (e.g. C<"catalog_product">)
- C<dbase>: database prefix (e.g. C<"catalog">)

    my $tb_info = $adb->table_info("catalog_product");

    print $tb_info->{table}; # "catalog_product"
    print $tb_info->{dbase}; # "catalog"



( run in 0.584 second using v1.01-cache-2.11-cpan-e623d60df62 )