NAME
AmberDB - High-performance Berkeley DB (DB_File) flat-file database engine
SYNOPSIS
use AmberDB;
my $dbp = AmberDB->new(
cfg => { language => "tr" },
path => { dbase_dir => "./dbstore" }
);
my @record = ( 0, "John Doe", "New York", 1980, 'john@example.com' );
# Insert record
$dbp->insert_id("table_id", @record);
# Update record
$dbp->modify_id("table_id", @record_updated);
# Delete record
$dbp->delete_id("table_id", $record_id);
# Read record by ID
my @record = $dbp->read_id("table_id", $record_id);
# Read all records
my @records = $dbp->read_all("table_id");
# Read list of records by IDs
my @records = $dbp->read_list("table_id", \@id_list);
# Search for the string "New York" in field 2 using the match function.
my @records = $dbp->field_fetch("table_id", 2, "New York");
# Full-text string search
my @records = $dbp->search_table("table_id", "search string");
# Direct low-level table access
$dbp->table_write($file_path);
my $records = $dbp->recs_get($file_path, @rec_ids);
my $ok = $dbp->recs_put($file_path, @records);
$dbp->table_close($file_path);
# Transaction example (Checkout / Stock operation)
$dbp->transact_start();
my $order_id = $dbp->insert_id("order", 0, $user_id, $item_id, $qty);
my $res = $dbp->transact_end();
if ($res->{status} eq 'rollback') {
warn "Checkout transaction failed and rolled back!";
}
DESCRIPTION
AmberDB provides flat-file database storage, indexing, and transaction management capabilities using Perl's DB_File tie interface. It supports automatic primary key generation, indexing (search, field-matching, facets), ACID-like undo-journal transactions with automatic/manual rollbacks, soft deletion, language sorting, and localized record manipulation.
TABLE NAMING CONVENTIONS
AmberDB enforces a strict, deterministic lowercase snake_case table naming convention:
Format: All table identifiers must consist of lowercase alphanumeric characters in snake_case, structured as
<database>_<table_name>(e.g.catalog_product,member_address,orders_item).Database Prefix Resolution: The segment before the first underscore (
_) represents the logical database/schema group (mapped to<database>.dbase).Schema Files: A table
catalog_productautomatically resolves its schema fromcatalog_product.tableand its database group settings fromcatalog.dbase.Constraint: Uppercase or mixed-case table names (e.g.
Catalog_Product) are not supported and will fail database group extraction.
TRANSACTIONS
Transactions provide multi-table atomic updates backed by undo-log journals (.txn files). If a database error occurs (e.g. file lock failure, duplicate ID), or if custom business validation fails (e.g. insufficient stock), all base records and indexes across all affected tables are restored to their exact pre-transaction state.
Note / Limitation: Bulk operations (insert_list, modify_list, delete_list) perform direct batch writes for performance and do not write to the transaction undo journal. Therefore, bulk operations are not covered by transactions and cannot be rolled back with transact_rollback() or transact_end(). Always use single-record CRUD operations (insert_id, modify_id, delete_id) when transaction/rollback support is needed.
Checkout / Stock Deduction Example
$dbp->transact_start();
# 1. Check & update stock
my @product = $dbp->read_id("product", $product_id);
my $current_stock = $product[4];
if ($current_stock < $quantity) {
# Custom business logic rollback (e.g. stock insufficient)
$dbp->transact_rollback();
return { success => 0, error => "Out of stock" };
}
$product[4] -= $quantity;
$dbp->modify_id("product", $product_id, @product);
# 2. Insert order record
my $order_id = $dbp->insert_id("orders", 0, $user_id, $product_id, $quantity, time());
# 3. Finalize transaction (auto-rollbacks if base error occurred)
my $txn = $dbp->transact_end();
if ($txn->{status} eq 'commit') {
return { success => 1, order_id => $order_id };
} else {
return { success => 0, error => "The operation failed, the changes were reverted." };
}
METHODS
new(%options)
Instantiates a new AmberDB object.
insert_id($table_id, [$record_id], @record)
Inserts a new record into specified table. Supports transaction logging.
insert_list($table_id, @records)
Inserts multiple records in a single bulk operation. Bypasses transaction logging.
modify_id($table_id, $record_id, @record)
Updates existing record data. Supports transaction logging.
modify_list($table_id, @records)
Modifies multiple records in a single bulk operation. Bypasses transaction logging.
delete_id($table_id, $record_id)
Deletes specified record from table. Supports transaction logging.
delete_list($table_id, @records)
Deletes multiple records in a single bulk operation. Bypasses transaction logging.
read_id($table_id, $record_id)
Reads single record by primary key ID.
read_all($table_id, [$start], [$limit], [%options])
Reads active records from table. Supports pagination, binary index optimization (.inx, .srt), sorting, and keys_only:
# Default sort (newest ID first)
my @records = $dbp->read_all("catalog_product");
# Sort by block 2 (default: descending / highest first)
my @records = $dbp->read_all("catalog_product", sort => { blk => 2 });
my @records = $dbp->read_all("catalog_product", sort => 2);
# Sort by block 2 reversed (ascending / lowest first)
my @records = $dbp->read_all("catalog_product", sort => { blk => 2, reverse => 1 });
my @records = $dbp->read_all("catalog_product", sort => -2);
# Natural primary key reverse (oldest first: 1..N)
my @records = $dbp->read_all("catalog_product", sort => { reverse => 1 });
# Tiered query mode: 'A' (Active only), 'B' (Junk only), 'AB' (Active first, then Junk)
my @active_only = $dbp->read_all("catalog_product", jnktype => 'A', keys_only => 1);
my @all_tiered = $dbp->read_all("catalog_product", jnktype => 'AB', keys_only => 1);
# Paginated with sorting
my ($count, @records) = $dbp->read_all("catalog_product", 0, 20, sort => { blk => 2, reverse => 1 });
# Return only scalar record IDs (memory-efficient pipeline)
my ($count, @ids) = $dbp->read_all("catalog_product", 0, 50, keys_only => 1);
my @all_ids = $dbp->read_all("catalog_product", keys_only => 1);
read_list($table_id, \@id_list)
Reads multiple records matching provided ID list while preserving exact list ordering.
field_fetch($table_id, $block, $value, [$start], [$limit], [%options])
Fetches records matching one or more block values using the .fld match index (or sequential table scan fallback if unindexed). Supports multi-value queries, automatic deduplication, sorting, pagination, and keys_only:
# Single value match
my @records = $dbp->field_fetch("catalog_product", 1, "5");
# Multi-value matching (comma string, semicolon, or ARRAY ref)
my @records = $dbp->field_fetch("catalog_product", 1, ["5", "8"]);
my @records = $dbp->field_fetch("catalog_product", 1, "5, 8");
# Paginated with sorting
my ($count, @records) = $dbp->field_fetch(
"catalog_product", 1, "5",
start => 0,
limit => 20,
sort => { blk => 10, reverse => 1 }
);
# Return only record IDs
my ($count, @ids) = $dbp->field_fetch("catalog_product", 1, "5", 0, 20, keys_only => 1);
my @all_ids = $dbp->field_fetch("catalog_product", 1, "5", keys_only => 1);
search_table($table_id, $query, [$start], [$limit], [$mode], [%options])
Searches table for matching query terms using full-text .src index (or sequential table scan fallback if unindexed). Features advanced language normalization (apostrophe suffix stop-words, Turkish phonetic devoicing b/d/g -> p/t/k, circumflex vowels â/î/û), block filtering, tier mode selection (jnktype => 'A' | 'AB' | 'B' | 'BA'), sorting, pagination, and keys_only:
# Basic AND full-text search (Active only)
my @records = $dbp->search_table("catalog_product", "kablosuz kulaklık", jnktype => 'A');
# Filtered search with index-level sort and pagination across both tiers
my ($total, @search) = $dbp->search_table(
"catalog_product", "kulaklık",
start => 0,
limit => 20,
sort => -5,
filter => { field => 6, value => 12 },
jnktype => 'AB',
);
# Return only scalar record IDs
my ($total, @ids) = $dbp->search_table("catalog_product", "kulaklık", 0, 50, keys_only => 1);
my @all_ids = $dbp->search_table("catalog_product", "kulaklık", keys_only => 1);
field_filter($table_id, \%filter_options)
Performs multi-block filtered queries (AND / OR) with support for multi-value filters, tier mode selection (jnktype), sorting, and pagination:
my $res = $dbp->field_filter("catalog_product", {
type => "and",
filter => { 1 => "5", 6 => ["12", "14"] },
sort => { blk => 5, reverse => 1 },
jnktype => "AB",
start => 0,
limit => 20,
});
# Returns: { count => $total, ids => \@matching_ids }
table_attr($table_id, \%attributes)
Dynamically overrides or customizes table schema attributes in-memory at runtime without altering schema files on disk:
# Narrow down search scope dynamically (e.g. barcode + title for POS scanner)
$dbp->table_attr("catalog_product", { search_block => [ 4, 9 ] });
# Include soft-deleted records or customize indexing flags on the fly
$dbp->table_attr("catalog_product", { keep_deleted => 1, use_cache => 0 });
id_check($table_id, $record_id)
Sanitizes and validates record ID against table schema (id_type). Enforces deterministic 8-byte limit for ASCII IDs.
bin_encode(\@rids, [$id_type])
Encodes list of record IDs into 8-byte unified packed binary format (Q*> for numeric, a8* for ASCII).
bin_decode($binary_buffer, [$start], [$limit], [$dir], [$id_type])
Decodes 8-byte unified binary buffer with O(1) substr slicing and deterministic numeric/ASCII detection.
index_get($table_path, $key, [$type], [$start], [$limit], [$dir])
Reads an entry from an index file (.inx, .fld, .src, .fac, .srt). $type can be 'ids' (binary decode) or 'raw' (scalar).
index_put($table_path, $key, $value, [$type])
Writes an entry to an index file with automatic bin_encode for ARRAY references.
index_del($table_path, $key)
Deletes an entry from an index file.
table_read($file_path)
Opens a DB_File handle in read-only mode (O_RDONLY) and caches it in internal pool.
table_write($file_path)
Opens a DB_File handle in read-write mode (O_RDWR | O_CREAT) with exclusive file lock (flock LOCK_EX).
table_close($file_path)
Syncs, unlocks, and closes the specified DB_File handle, removing it from internal pool.
recs_get($file_path, @record_ids)
Reads multiple keys in a single pass over the open DB_File handle. Returns { key => raw_val }.
recs_put($file_path, @records)
Writes records in bulk to open DB_File handle. Each item must be in [$rid, @fields] or [$rid, $val] format.
recs_del($file_path, @record_ids)
Deletes provided record IDs from open DB_File handle.
recs_exist($file_path, @keys)
Checks presence of key(s) in DB_File table. Returns boolean for single key, or { key => 1/0 } for multiple keys.
recs_keys($file_path)
Extracts all keys from DB_File handle in sequential order using C-level seq.
recs_scan($file_path, [$mode_or_callback])
Scans open DB_File handle sequentially using C-level seq. Supports multiple modes: - \&callback: Invokes callback->($key, $val) for each pair. - 'keys': Returns list/arrayref of all keys. - 'value' / 'values': Returns list/arrayref of all raw values. - 'each' / 'pairs': Returns list/arrayref of [$key, $val] pairs. - 'count': Returns total number of records. - 'hash' (default): Returns key-value hash (or hashref).
transact_start()
Starts a new transaction for atomic multi-table operations.
transact_end()
Finalizes active transaction. Performs LIFO rollback if any base DB error occurred during execution.
transact_rollback()
Forces an immediate manual rollback of active transaction.
flock_open($table_id, [$mode], [$record_id])
Acquires a record-level (if $record_id specified) or table-level (if $record_id omitted) lock. $mode can be "write" (exclusive lock, default) or "read" (shared lock).
flock_close($table_id, [$record_id])
Releases a record-level or table-level lock previously acquired via flock_open().
AUTHOR
Maruf Cetin <marufcetin@gmail.com>
LICENSE AND COPYRIGHT
Copyright (C) 2005-2026 Maruf Cetin.
This library is free software; you can redistribute it and/or modify it under the terms of the Artistic License 2.0.