AmberDB

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

5.26.1  2026-09-28
        - [32-BIT PERL / CPAN TESTERS QUAD PACKING COMPATIBILITY]
          * Implemented transparent cross-platform 64-bit integer packing in AmberDB::Base::Encoder (_pack_ids, _unpack_ids, _pack_single_id).
          * Utilizes native 64-bit pack("(Q>)*") / unpack("(Q>)*") on 64-bit Perls with zero performance overhead.
          * Automatically falls back to dual 32-bit unsigned network integer pack("(NN)*") / unpack("(NN)*") on 32-bit Perls without quad support (use64bitint=undef, e.g. Raspberry Pi armv6l).
          * Guaranteed 100% byte-exact binary compatibility on physical .inx, .fld, .src index files across 32-bit and 64-bit architectures.
          * Completely resolved CPAN Testers "Invalid type 'Q' in pack" exceptions across 36 test suites.

        - [CLI THREE-MODE ARCHITECTURE & ZERO-FALLBACK ENFORCEMENT]
          * Re-architected amberdb CLI (bin/amberdb_cli.pl) into three distinct, predictable operational modes:
            1. 'amberdb setup': Provisions global workspace (~/.amberdb) with session/ and config/ directories. Fully eliminated dummy default/ database.
            2. 'amberdb connect <name>[@<path>]': Named session management with canonical absolute path resolution; rejects raw directory names without database alias.
            3. Direct CRUD ('amberdb CRUD'): Strictly targets local ./dbstore in current working directory without fallback to ~/.amberdb/default.
          * Read operations (tables, read, search, count, info) return empty/null cleanly without creating directory skeletons.
          * Write operations (insert) automatically provision ./dbstore and core.conf on-the-fly.
          * Updated user guides and documentation in README.md, wiki/TR-Guide-CLI.md, and wiki/Guide-CLI.md.

        - [SCHEMA USE_SIMPLE SANITIZATION & STRING KEY PRESERVATION]
          * Updated AmberDB::Base::Schema to strip unused 'blocks' definition for use_simple => 1 tables.
          * Wrapped explicit ID sorting in AmberDB::insert_list with unless ($is_simple) guard, eliminating numeric comparison warnings on string keys without regex overhead.

Changes  view on Meta::CPAN

          * Fixed macOS /Volumes permission error in AmberDB::Base::Ramdisk by verifying write permissions before activating RAM-disk mount points.
          * Added eval guard to ramdisk_setup with graceful fallback to local storage.

        - [WINDOWS CRLF & TRANSACTION JOURNAL HARDENING]
          * Enforced binmode on journal handles in AmberDB::Base::Transact to prevent Windows CRLF mangling of record separators and Base64 payloads.
          * Added journal content diagnostic dumps and exact field assertions in t/amberdb_transact.t.

        - [WINDOWS CI & FLOCK / CLI AT-SYNTAX COMPATIBILITY]
          * Replaced colon separator with '@' for custom directory connect syntax ('amberdb connect <dbname>@<path>'), completely eliminating ambiguity with Windows drive letters (C:\path).
          * Enforced strict directory path and legacy colon syntax rejection in bin/amberdb_cli.pl.
          * Added automatic background workspace provisioning in bin/amberdb_cli.pl: automatically runs global setup on first invocation if ~/.amberdb does not exist.
          * Fixed t/amberdb_transact.t journal reader to read directly via active transaction handle ($adb->{_txn}->{fh}), eliminating Windows mandatory flock(LOCK_EX) read collisions that resulted in uninitialized $journal_content on native Windows ...
          * Added comprehensive cross-platform connect '@' syntax, auto-setup, and Windows drive path rejection tests in t/amberdb_cli.t.

5.26.0  2026-09-23
        - [FAST INDEXED FIELD COUNTING (field_count)]
          * Implemented field_count($table, $block, $val) for fast O(1) indexed counting across inverted match (.fld) indexes without reading or deserializing full records.
          * Optimized for high-throughput facet counts, inventory status aggregation, and relational child counts.
          * Added comprehensive unit test suite in t/amberdb_field_count.t and documentation in wiki/Method-field_count.md and wiki/TR-Method-field_count.md.

        - [COLUMNAR FACETS & BIDIRECTIONAL DICTIONARY LOOKUP]

Changes  view on Meta::CPAN

          * Replaced direct hash access with fast accessor methods across dump, vacuum, and backup routines.

        - [DIRECTORY ARCHITECTURE & LOCK PATH STANDARDIZATION]
          * Standardized lock_dir and session_dir as single-key directories in AmberDB::Base::Ramdisk and AmberDB::Base.
          * Removed obsolete fallback keys (lock_rdir) and legacy naming aliases (conf_dir, cfg_dir).
          * In RAM-disk environments, lock_dir and session_dir are dynamically mounted under $ramdisk_dir/lock and $ramdisk_dir/session with 0755 permissions; when unmounted, they reside cleanly under $dbase_dir/lock and $dbase_dir/session.
          * Aligned database lock directory structures with inter-process state locking specifications.

        - [SCHEMA LOADING RESILIENCE]
          * Wrapped 'do $target_path' inside eval { do $target_path } in AmberDB::Base::Schema (table_info() and dbase_info()).
          * Prevents fatal process/worker termination when user .table or .dbase schema files contain syntax errors under global $SIG{__DIE__} handlers.

        - [SLUG INDEX ARCHITECTURE VERIFICATION (.slg)]
          * Verified flat unified .slg index access model where block numbers (formerly _0 / _1 file suffixes) reside in key prefixes:
            - Block 0: "0:$rid" -> URL slug value
            - Block 1: "1:$slug" -> Record ID value
          * Enforced direct .slg table access and recs_get key lookups without legacy .rwt fallbacks.

        - [GROUP-LEVEL SCHEMA INHERITANCE (.dbase -> .table)]
          * Database group schema files (.dbase) now cascade common operational flags to all member tables in the group.
          * Added %INHERITABLE_DBASE_KEYS whitelist in AmberDB::Base::Schema (use_ramdisk, keep_deleted, use_counter, log_owner, table_dir, use_section, etc.) preventing table-specific blocks and rules from leaking.

Changes  view on Meta::CPAN

            - AmberDB::Base::Facet (Faceted search and category aggregation)
            - AmberDB::Base::Junk (Multi-tiered soft-delete and junk rule processing)
            - AmberDB::Base::Transact (WAL transaction engine and atomic journaling)
          * Excluded entire lib/AmberDB/Base/ directory and AmberDB::Base namespace from CPAN indexing in Makefile.PL (no_index), keeping MetaCPAN documentation clean and focused on public standalone interfaces.
          * Consolidated public submodule architecture in AmberDB POD to focus exclusively on standalone components (AmberDB::Date, AmberDB::Locale, AmberDB::Tools).
          * Integrated ISO 4217 Currency Dictionary documentation into AmberDB::Locale and removed standalone POD from internal AmberDB::Locale::Currency to prevent separate CPAN indexing.
          * Removed unused legacy String utility module; consolidated trim_space utility into AmberDB::Base.

        - [TRANSPARENT PHYSICAL RAM-DISK ACCELERATION & CROSS-PLATFORM ORCHESTRATION]
          * Cross-Platform Support (Linux, macOS, Windows): Standardized bin/ramdisk_* suite (ramdisk_amberdb.pl, ramdisk_windows.bat/ps1, ramdisk_macos.sh, ramdisk_linux.sh) with native support for Linux tmpfs, macOS APFS RAM-Disk (hdiutil), and Win...
          * Global & Per-Table Acceleration: Supports global use_ramdisk => 1|2 in AmberDB->new with per-table overrides (use_ramdisk => 0|1|2|3) and lazy preloading on first table access.
          * Volatile Pure RAM-Disk Mode (Tier 3 & ramdisk_ttl): Supports memory-only unindexed tables (use_ramdisk => 3, use_simple => 1) with configurable sliding time-to-live expiration (ramdisk_ttl, default 300s).
          * Custom Storage Subfolder Organization (table_dir): Allows routing table and index files to dedicated subfolders (e.g. table_dir => 'orders') or directly to the database root (table_dir => '').
          * Standardized Path & Environment Options (dbase_dir): Engine root storage path formalized with full runtime reflection and set_datadir migration.
          * Standardized RAM-Disk Parameters: Replaced legacy cache_size and cache_dir with ramdisk_size and ramdisk_dir across constructor, config, and diagnostic reporting.
          * Native File Extension Architecture: RAM-disk stores all database and index files with their native extensions (.db, .inx, .fld, .src, .fac, .unq, .slg), retiring proprietary .cache file formats.
          * Unified ramdisk_setup([$tableid]): Consolidated environment validation, mount diagnostics, and deterministic table preloading into a single method ($adb->ramdisk_setup), superseding legacy cache_setup and cache_preload.
          * Dedicated L1 Process Cache API: Replaced legacy cache_* routines with clean, dedicated get_cache and set_cache methods for in-memory L1 storage.
          * Hardened Mount Detection: Validates symlinks/junctions (-l) and direct RAM paths with zero-subprocess /proc/mounts verification, auto-registered to $adb->config('ramdisk_mounted').
          * Dual-Write & Transaction Safety: Real-time dual-write across index and data files with atomic Berkeley DB preloading and WAL rollback protection.
          * Decoupled Engine Architecture: Separated AmberDB::Base::Ramdisk (physical file storage) from AmberDB::Base::Cache (in-memory L1 cache and staging buffers).

Changes  view on Meta::CPAN

          * All 47 test files (440 assertions) passing with 100% success rate.

5.23.2  2026-09-03
        - [LOCALE ENGINE & MULTILINGUAL ARCHITECTURE] 10th Language - Global Base (gb) and Default Locale:
          * Introduced Global Base (gb) as the 10th supported language and new universal default/fallback locale (replacing en).
          * Implemented comprehensive multilingual Latin character preservation in alphabet_chars across European, Turkish, Nordic, French, German, Spanish, and Slavic-Latin alphabets.
          * Added cross-lingual, accent-tolerant search regex mapping (regex_map) matching accented and unaccented variations (e.g. cafe matches café, munchen matches münchen, seker matches şeker).
          * Implemented canonical accent folding in accent_map for high-recall inverted search indexing (.src).
          * Added lossless Unicode ligature conversion in ascii_map (ß->ss, æ->ae, œ->oe, ı->i, ø->o, ł->l, đ->d, ð->d, þ->th, ə->e) for clean URL slug and ASCII ID generation.
          * Configured international English numbering, date formatting, and ISO standard decimal/group separators.
          * Added language aliases: 'gb', 'global', 'gl', 'universal', 'uni', 'gb_base'.
          * Added dedicated test coverage in t/amberdb-locale_09_gb.t.
        - [TRANSACTION ARCHITECTURE & API REFINEMENT] Pure File-Path Error Model and Operational Rollback:
          * Refactored transact_error($file_path, $message) to exclusively accept physical file paths; eliminated artificial "transaction" and "system" string contexts.
          * Simplified table identification via single exact regex /([^\/\\:]+)\.$db_ext$/: directly extracts table ID and inspects schema no_transact attribute; non-db extensions (.inx, .src, .fld, .fac, .slg, .aut, .del, .txn) never trigger rollbac...
          * Added immediate early return in transact_error if $file_path is undefined or empty.
          * Established strict API role separation: application code directly invokes transact_rollback() for business logic cancellations (insufficient stock, credit limits, validation aborts) and unexpected eval exceptions; transact_error is reserv...
          * Unified legacy is_index and is_no_transact flags into single no_rollback attribute.
          * Restructured insert_id to strictly validate mandatory $tableid at entry prior to resolving table paths, with proper ref guard for $rid.

5.23.1  2026-09-02

Changes  view on Meta::CPAN

          * Implemented hash_diff($hash1, $hash2) in AmberDB::Array with safe shallow copying, ensuring input hash structures are never mutated.
          * Removed legacy internal _hash_diff from AmberDB::Tools and switched to $adb->hash_diff directly.
          * Added unit test coverage for hash_diff in t/amberdb_array.t.

5.22.2  2026-09-01
        - [CROSS-PLATFORM & CI] Universal GitHub Actions CI Matrix:
          * Configured multi-platform CI matrix testing on Linux (ubuntu-latest), macOS (macos-latest), and Windows (windows-latest) across Perl 5.16 through 5.40.
          * Configured official Strawberry Perl distribution in CI for native Berkeley DB / DB_File binary compatibility and prevented Git Bash PATH collisions.
        - [STORAGE & TRANSACTIONS] Safe Directory Scanner and Windows File Sharing:
          * Introduced dir_files($dir, [$pattern], [%opts]) helper method in AmberDB::Base for cross-platform, safe file discovery supporting wildcards (*.db, txn_*.txn) and compiled regular expressions (qr/../).
          * Refactored AmberDB::Transact and AmberDB::Tools (dir_tables, all_tables, del_table) to use dir_files, completely removing fragile glob usage.
          * Fixed Windows NTFS file sharing collision in transact_recover: journal lines are now read directly from open locked handles, preventing secondary open permission denied errors.
        - [TESTS & STABILITY] Test Concurrency and Monotonic Sequence:
          * Hardened t/amberdb_transact.t orphan recovery subtest to use strictly monotonic table_autoid record IDs (65) and authentic transaction lifecycle simulation.
          * Guaranteed complete handle and lock cleanup with $adb->close_all() in crash recovery test scenarios.

5.22.1  2026-09-01
        - [DOCS] Documentation and Synopsis Fixes:
          * Fixed synopsis and API example signatures across documentation and POD.
          * Updated README.md installation instructions with streamlined CPAN/cpanm cross-platform support.
          * Fixed character encoding and wide-character warnings in test suite schemas.

bin/amberdb_cli.pl  view on Meta::CPAN

# ============================================================================
# SESSION REGISTRY (~/.amberdb/session/)
# Stores session files per active session under ~/.amberdb/session/sess_$token
# ============================================================================

my $user_home = $ENV{USERPROFILE} // $ENV{HOME} // '.';
$user_home =~ s{\\}{/}g;
our $AMBERDB_HOME = "$user_home/.amberdb";
our $CLI_SESS_DIR = "$AMBERDB_HOME/session";

sub setup_global_workspace {
    eval {
        make_path($AMBERDB_HOME) unless -d $AMBERDB_HOME;
        make_path($CLI_SESS_DIR) unless -d $CLI_SESS_DIR;
        my $cfg_dir = "$AMBERDB_HOME/config";
        make_path($cfg_dir) unless -d $cfg_dir;
    };
}

# Auto-provision global workspace in background on first run if missing
if ( !-d $AMBERDB_HOME ) {
    setup_global_workspace();
}

sub resolve_abs_path {
    my ($path) = @_;
    return '' unless defined $path && length $path;
    $path =~ s{\\}{/}g;
    my $abs = eval { abs_path($path) };
    if ( defined $abs && length $abs ) {
        $abs =~ s{\\}{/}g;
        return $abs;

bin/amberdb_cli.pl  view on Meta::CPAN

  amberdb delete users 10

2. İsimlendirilmiş Oturum (Session Management):
  amberdb connect <database>                  # ~/.amberdb/<database> havuzuna bağlanır
  amberdb connect <database>\@<path>           # Özel bir klasöre bağlanır (örn: mydb\@./dbstore)
  amberdb 1245 tables                         # 1245 nolu oturumun tablolarını listeler
  amberdb 1245 read products 10               # 1245 nolu oturumda okuma yapar
  amberdb 1245 disconnect                     # Oturumu sonlandırır

3. Altyapı ve Kurulum:
  amberdb setup                               # ~/.amberdb global çalışma alanını kurar
  amberdb setup [dir]                         # Özel bir dizinde veritabanı iskeleti kurar
  amberdb setup ramdisk [start|stop|status]   # RAM-disk sürücü yönetimi

Bakım ve Yönetim Eylemleri:
  amberdb update storage [--check] [--force]  # Dizin & ABR v5 veri biçimi migrasyonu
  amberdb update version [--check]            # MetaCPAN çekirdek sürüm kontrolü / güncelleme
  amberdb reindex products                    # İndeksleri sıfırdan oluştur
  amberdb check products                      # Fiziksel dosya bütünlük kontrolü
  amberdb vacuum products                     # BDB disk boşluklarını temizle
  amberdb migrate products                    # Şema güncellemesi

bin/amberdb_cli.pl  view on Meta::CPAN

  amberdb delete users 10

2. Named Session (Session Management):
  amberdb connect <database>                  # Connect to ~/.amberdb/<database> pool
  amberdb connect <database>\@<path>           # Connect to custom folder (e.g. mydb\@./dbstore)
  amberdb 1245 tables                         # List tables for session 1245
  amberdb 1245 read products 10               # Read record in session 1245
  amberdb 1245 disconnect                     # Terminate active session

3. Infrastructure & Setup:
  amberdb setup                               # Provision ~/.amberdb global workspace
  amberdb setup [dir]                         # Initialize database skeleton in custom directory
  amberdb setup ramdisk [start|stop|status]   # RAM-disk drive management

Maintenance & Administrative Actions:
  amberdb update storage [--check] [--force]  # Directory & ABR v5 format migration
  amberdb update version [--check]            # MetaCPAN core version check / update
  amberdb reindex products                    # Rebuild all derived indexes
  amberdb check products                      # Physical file integrity check
  amberdb vacuum products                     # Compact and reclaim BDB storage space
  amberdb migrate products                    # Schema migration

bin/amberdb_cli.pl  view on Meta::CPAN

    delete_session($token);
    if ( defined $opt_format && $opt_format eq 'json' ) {
        print encode_json( { status => 'disconnected', token => $token } ), "\n";
    }
    else {
        print "[AMBERDB] Disconnected session '$token' successfully.\n";
    }
    exit 0;
}

# If in session and global configs/paths changed without action, update session and exit
if ( $session && ( $has_cfg_updates || $has_path_updates ) && !defined $opt_action ) {
    $session->{path} = $adb->path();
    $session->{cfg}  = $adb->config();
    $session->{updated_at} = time();
    save_session( $active_token, $session );

    if ( defined $opt_format && $opt_format eq 'json' ) {
        print encode_json( { status => 'updated', token => $active_token, path => $adb->path(), cfg => $adb->config() } ), "\n";
    }
    else {

bin/amberdb_cli.pl  view on Meta::CPAN

                print "[RAM-DISK] Linux /dev/shm initialized.\n";
                exit 0;
            }
            elsif ( $subcmd eq 'stop' ) {
                print "[RAM-DISK] Stopped.\n";
                exit 0;
            }
        }
    }

    # If no argument is passed: setup global environment (~/.amberdb)
    if ( !defined $first_arg || !length $first_arg ) {
        setup_global_workspace();

        if ( defined $opt_format && $opt_format eq 'json' ) {
            output_result( {
                status       => 'ok',
                action       => 'setup',
                mode         => 'global',
                amberdb_home => $AMBERDB_HOME,
                session_dir  => $CLI_SESS_DIR,
            }, $opt_format );
            exit 0;
        }

        print "=================================================================\n";
        print " AmberDB Global Environment Setup & Initialization               \n";
        print "=================================================================\n";
        print "AmberDB Home     : $AMBERDB_HOME (~/.amberdb)\n";
        print "Session Registry : $CLI_SESS_DIR/\n";
        print "Platform         : $^O\n";
        print "-----------------------------------------------------------------\n";
        print "[SUCCESS] AmberDB global workspace initialized successfully!\n\n";
        print "Kullanım Biçimleri:\n";
        print "  1. Yerel Proje   : Proje klasörünüzde doğrudan çalıştırın (./dbstore kullanılır)\n";
        print "     amberdb insert users 0 data='{\"name\":\"Ahmet\"}'\n";
        print "     amberdb tables\n\n";
        print "  2. Merkezi Havuz : Belirtilen ada oturum açarak ~/.amberdb/<ad> kullanılır\n";
        print "     amberdb connect eticaretim\n";
        print "     amberdb 1245 tables\n\n";
        print "  3. Özel Klasör   : 'ad\@yol' formatı ile oturum açılır\n";
        print "     amberdb connect eticaretim\@./dbstore\n";
        print "=================================================================\n";

docs/EN.AmberDB-Locale_User-Guide.md  view on Meta::CPAN

# 3) Positional string API
my $lang = AmberDB::Locale->new("fr");

# 4) No args → defaults to "gb" (Global Base)
my $lang = AmberDB::Locale->new();
```

### Internal behaviors

- **Caching:** A second `new()` call for the same language returns the existing instance (singleton-like).
- **Alias support:** Labels like `"global"`, `"gl"`, `"turkish"`, `"tr_tr"`, `"tr-tr"` are automatically mapped to canonical codes.
- **Fallback:** If an unknown language is requested, a `cluck` warning is emitted and it falls back to `gb`.
- **Collator:** Attempts to load `Unicode::Collate::Locale`; if it fails, falls back to base `Unicode::Collate`, and if that's also unavailable, uses a custom `sort_map` Schwartzian transform.

### AmberDB integration

```perl
# Language is automatically pulled from cfg
my $db = AmberDB->new(cfg => { language => "tr" });
$db->uc("ığdır");   # works via inheritance: IĞDIR
```

docs/EN.AmberDB_User-Guide.md  view on Meta::CPAN

#### 1. Global Configuration (Default for All Tables)
You can enable index or full-table acceleration across the entire database in one step:

```perl
# Apply Tier 1 (Hybrid Index) to all tables upon initialization
my $adb = AmberDB->new(
    cfg  => { use_ramdisk => 1 },
    path => { dbase_dir   => "/var/data/amberdb" }
);

# Dynamically change global tier at runtime
$adb->config(use_ramdisk => 2); # Switch all tables to Tier 2 (Full Mirror)
```

#### 2. Per-Table Flexible Configuration and Overrides
Each table can be independently assigned its own acceleration tier in its `.table` schema file or at runtime via `table_attr()`:

```perl
# Put high-traffic categories table into Full RAM-Disk Mirroring
$adb->table_attr("catalog_category", use_ramdisk => 2);

docs/TR.AmberDB-Locale_Kullanim_Rehberi.md  view on Meta::CPAN

# 3) Pozisyonel string API
my $lang = AmberDB::Locale->new("fr");

# 4) Argümansız → varsayılan "gb" (Global Base)
my $lang = AmberDB::Locale->new();
```

### Dahili davranışlar

- **Önbellekleme:** Aynı dil için ikinci `new()` çağrısı mevcut nesneyi döndürür (singleton benzeri).
- **Alias desteÄŸi:** `"global"`, `"gl"`, `"turkish"`, `"tr_tr"`, `"tr-tr"` gibi etiketler otomatik olarak eÅŸlenir.
- **Fallback:** Bilinmeyen bir dil istenirse `cluck` ile uyarı verilir ve `gb`'ye düşülür.
- **Collator:** `Unicode::Collate::Locale` yüklenmeye çalışılır; başarısız olursa `Unicode::Collate` tabanına, o da yoksa özel `sort_map` Schwartzian transform'una düşülür.

### AmberDB entegrasyonu

```perl
# cfg üzerinden dil otomatik çekilir
my $db = AmberDB->new(cfg => { language => "tr" });
$db->uc("ığdır");   # kalıtım yoluyla çalışır
```

docs/TR.AmberDB_Veritabani_Sistemi.md  view on Meta::CPAN

#### 1. Global Yapılandırma (Tüm Tablolar İçin Varsayılan)
Tüm veritabanı genelinde indeks veya tam tablo hızlandırmasını tek seferde etkinleştirebilirsiniz:

```perl
# Kurulum anında tüm tablolara Seviye 1 (Hibrit İndeks) uygulama
my $adb = AmberDB->new(
    cfg => { use_ramdisk => 1 },
    path => { dbase_dir => "/var/data/amberdb" }
);

# Çalışma anında global seviyeyi değiştirme
$adb->config(use_ramdisk => 2); # Tüm tabloları Seviye 2 (Tam Ayna) yap
```

#### 2. Tablo Bazında Esnek Yapılandırma ve İstisnalar
Her tablo için `.table` şema dosyasından veya çalışma anında `table_attr()` ile bağımsız hızlandırma seviyesi belirlenebilir:

```perl
# Yüksek trafikli kategoriler tablosunu Tam RAM Aynasına al
$adb->table_attr("catalog_category", use_ramdisk => 2);

# Seyrek erişilen bir tabloyu global RAM-disk kapsamı dışına çıkar (diskte tut)
$adb->table_attr("audit_archive", use_ramdisk => 0);
```

#### 3. Standart CRUD Çağrılarıyla Doğrudan Kullanım
Geliştirici yalnızca standart AmberDB metotlarını kullanır. Motor, arka planda RAM-disk kopyalamasını, bellekten okumayı ve diske çift yazmayı şeffaf olarak yürütür:

```perl
# Okuma: use_ramdisk tanımlıysa sorgular doğrudan RAM üzerinden mikrosaniyede döner
my @urun = $adb->read_id("catalog_product", 101);
my ($adet, @sonuclar) = $adb->search_table("catalog_product", "kablosuz kulaklik");

lib/AmberDB.pm  view on Meta::CPAN

    }

    for my $child_table ( keys %children ) {
        $self->table_truncate($child_table);
    }
    return scalar keys %children;
}


# Sanitizes and validates a record ID according to table mode.
# If simple mode (global simple or table use_simple): allows safe arbitrary keys (max 255 bytes, no control chars).
# If standard mode: strictly enforces positive integer numeric ID.
# my $clean_id = $adb->id_check($tableid, $rid);
# ------------------------------------------------
sub id_check {
    my ( $self, $tableid, $rid ) = @_;

    return unless defined $rid && $rid ne '';
    return if ref $rid;

    my $table_info = $tableid ? $self->table_info($tableid) : {};

lib/AmberDB.pm  view on Meta::CPAN

                    $self->index_del( [ $mirror_path, $tableid, 1 ], \@keys_to_del );
                }
            }
        }
    }

    return $del_count;
}

# Writes add|edit|del operation to daily CSV backup audit stream (backup/YYYY/YYYY-MM-DD.csv).
# Exits silently if no_backup is set (globally or in table schema).
# my $ok = $adb->recs_back("add|edit|del", $tableid, @records);
# ------------------------------------------------
sub recs_back {

    my ( $self, $action, $tableid, @records ) = @_;

    ( $action and $tableid and scalar @records ) or return;

    # Global config check: disables backup for all tables
    return 1 if $self->config('no_backup');

lib/AmberDB.pm  view on Meta::CPAN

=item * B<Tier 4 (Asynchronous Write-Behind, C<use_ramdisk =E<gt> 4>):> Primary records and indexes are updated immediately in RAM-disk for maximum throughput. Write operations append dirty sync events to C<journal/sync_ramdisk>, and a background dae...

=back

=head2 Transparent Management (C<use_ramdisk>)

AmberDB manages the RAM-disk layer entirely in the background. Developers do not need to call any low-level RAM-disk functions or manually orchestrate memory synchronization. Everything is controlled declaratively via the C<use_ramdisk> option:

=over 4

=item * B<Global Configuration:> Set globally at instantiation (C<AmberDB-E<gt>new(cfg =E<gt> { use_ramdisk =E<gt> 1 })>) or at runtime via C<$adb-E<gt>config(use_ramdisk =E<gt> 2)>.

=item * B<Per-Table Customization:> Set independently for each table in its C<.table> schema or via C<$adb-E<gt>table_attr($table, use_ramdisk =E<gt> $tier)>.

=item * B<Standard CRUD Workflow:> Continue using standard AmberDB methods (C<read_id>, C<search_table>, C<insert_id>, C<modify_id>). The engine automatically reads from memory at microsecond speeds and dual-writes to permanent storage.

=item * B<Windows & Linux Administration:> On Windows, use C<bin\setup_windows.bat> to mount or unmount the ImDisk RAM-disk. On Linux, C</dev/shm> is utilized automatically:

  - Mount RAM-disk (Windows): bin\setup_windows.bat start 512M R:
  - Status check (Windows):   bin\setup_windows.bat status
  - Background Sync Daemon:   perl bin/amberdb_daemon.pl start

lib/AmberDB/Base.pm  view on Meta::CPAN

    my %pairs = ( @args == 1 && ref( $args[0] ) eq 'HASH' ) ? %{ $args[0] } : @args;

    for my $key ( keys %pairs ) {
        $self->{_path}->{$key} = $pairs{$key};
    }
    $self->_invalidate_table_paths();

    return $self;
}

# Invalidate cached table paths if global path-affecting configurations change
# ------------------------------------------------
sub _invalidate_table_paths {
    my ($self) = @_;

    if ( $self->{_table} && ref( $self->{_table} ) eq 'HASH' ) {
        for my $tbl ( keys %{ $self->{_table} } ) {
            delete $self->{_table}->{$tbl}->{_path}
              if ref( $self->{_table}->{$tbl} ) eq 'HASH';
        }
    }

lib/AmberDB/Base/Schema.pm  view on Meta::CPAN

    # ------------------------------------------------------------------------
    $self->_apply_dbase_inheritance( $table, $schema );

    # ------------------------------------------------------------------------
    # Pipeline Step 1: Global Configuration Inheritance
    # ------------------------------------------------------------------------
    if ( defined $schema->{use_ramdisk} ) {
        $schema->{use_ramdisk} = $self->_normalize_ramdisk_tier( $schema->{use_ramdisk} );
    }
    elsif ( !defined $schema->{use_cache} ) {
        my $global_ram = $self->config('use_ramdisk');
        $global_ram = $self->_normalize_ramdisk_tier($global_ram);
        $global_ram = 0 if $global_ram == 3;
        $schema->{use_ramdisk} = $global_ram;
    }

    # ------------------------------------------------------------------------
    # Pipeline Step 1b: Volatile RAM-Disk Tier 3 Stripping
    # If use_ramdisk == 3, table is pure volatile key-value store on RAM-disk.
    # Strip all indexing, columnar, facet, and relational definitions.
    # ------------------------------------------------------------------------
    if ( ( $schema->{use_ramdisk} // 0 ) == 3 ) {
        delete @{$schema}{
            qw(

lib/AmberDB/Locale.pm  view on Meta::CPAN

        'es_es'       => 'es',
        'russian'     => 'ru',
        'ru_ru'       => 'ru',
        'arabic'      => 'ar',
        'ar_sa'       => 'ar',
        'azerbaijani' => 'az',
        'az_az'       => 'az',
        'japanese'    => 'ja',
        'ja_jp'       => 'ja',
        'ja-jp'       => 'ja',
        'global'      => 'gb',
        'gb'          => 'gb',
        'gl'          => 'gb',
        'universal'   => 'gb',
        'uni'         => 'gb',
        'gb_base'     => 'gb',
    );

    $lang = lc( $lang // '' );
    $lang =~ s/[^\w-]//g;
    my $norm_lang = $LANG_ALIAS{$lang} || ( split /[_-]/, $lang )[0] || 'gb';

lib/AmberDB/Locale.pm  view on Meta::CPAN

    return 0 unless defined $cond && length $cond;

    my $n = abs( $count // 0 );

    # Whitelist strictly only digits, 'n', whitespace, arithmetic and logical operators
    return 0 unless $cond =~ /^[n0-9+\-*\/%&|!=<>()\s]+$/;

    # Replace 'n' variable token with actual numeric value
    ( my $expr = $cond ) =~ s/\bn\b/$n/g;

    # Safely evaluate numeric expression isolated from global DIE handlers
    my $res = eval {
        local $SIG{__DIE__} = sub {};
        eval $expr; ## no critic
    };
    return $res ? 1 : 0;
}

# -------------------------------------------------------
# Evaluate CLDR plural rule and select template.
#

lib/AmberDB/Locale.pm  view on Meta::CPAN


  # 2. Hashref API
  my $lang = AmberDB::Locale->new({ language => 'de' });

  # 3. Positional string API
  my $lang = AmberDB::Locale->new('fr');

  # 4. Default (falls back to Global Base 'gb')
  my $lang = AmberDB::Locale->new();

Supported language codes include C<"gb"> (Global Base - default), C<"tr">, C<"en">, C<"de">, C<"fr">, C<"es">, C<"ru">, C<"az">, C<"ar">, C<"ja"> and common aliases (such as C<"global">, C<"turkish">, C<"tr_tr">, C<"english">, C<"german">, etc.).
If an unsupported language is specified, a warning is issued and the instance falls back to C<"gb">.

=head1 METHODS

=head2 Case Conversions & Comparison

=head3 uc($string)

Converts C<$string> to uppercase according to locale-specific casing rules.

lib/AmberDB/Tools/Update.pm  view on Meta::CPAN

sub replace_tablename {

    my ( $self, $find, $replace ) = @_;
    my $adb = $self->{_adb} or return;

    my @tables;
    my $dbase_dir = $adb->path('dbase_dir') || ".";
    my $year_dir  = $adb->path('year_dir') || "";

    if ( $adb->config('simple') ) {
        @tables = glob "$dbase_dir/$find.*";
        push @tables, ( glob "$dbase_dir/${find}_*" );
    }
    else {
        @tables = glob "$dbase_dir/table/$find.*";
        push @tables, ( glob "$dbase_dir/table/${find}_*" );
        if ( $adb->config('use_section') ) {
            my @sections = glob "$dbase_dir/section_*";
            foreach my $sec_file (@sections) {
                push @tables, ( glob "$sec_file/$find.*" );
                push @tables, ( glob "$sec_file/${find}_*" );
            }
        }

        if ( $adb->config('use_year') && $year_dir ) {
            @tables = glob "$dbase_dir/$year_dir/$find.*";
            push @tables, ( glob "$dbase_dir/$year_dir/${find}_*" );
            if ( $adb->config('use_section') ) {
                my @sections = glob "$dbase_dir/$year_dir/section_*";
                foreach my $sec_file (@sections) {
                    push @tables, ( glob "$sec_file/${find}.*" );
                    push @tables, ( glob "$sec_file/${find}_*" );
                }
            }
        }
    }

    foreach my $old_file (@tables) {
        my $new_file = "$old_file";
        $new_file =~ s/\/$find([\.\_])/$replace$1/;
        rename( $old_file, $new_file );
    }

t/amberdb-locale_09_gb.t  view on Meta::CPAN

    plan tests => 7;

    # Default constructor without arguments must return 'gb'
    my $def = AmberDB::Locale->new();
    is( $def->language, 'gb', 'Default constructor resolves to gb' );

    # Explicit 'gb'
    my $gb = AmberDB::Locale->new( language => 'gb' );
    is( $gb->language, 'gb', 'Explicit language => gb resolves to gb' );

    # Alias 'global'
    my $global = AmberDB::Locale->new( language => 'global' );
    is( $global->language, 'gb', 'Alias language => global resolves to gb' );

    # Alias 'gl'
    my $gl = AmberDB::Locale->new( language => 'gl' );
    is( $gl->language, 'gb', 'Alias language => gl resolves to gb' );

    # Alias 'universal'
    my $uni = AmberDB::Locale->new( language => 'universal' );
    is( $uni->language, 'gb', 'Alias language => universal resolves to gb' );

    # Positional string

t/amberdb-locale_09_gb.t  view on Meta::CPAN

    plan tests => 8;

    my $tmpdir = tempdir( CLEANUP => 1 );
    my $adb = AmberDB->new(
        path => { dbase_dir => $tmpdir },
    );

    is( $adb->language, 'gb', 'AmberDB instance initializes with gb language by default' );
    is( $adb->config('language'), 'gb', 'AmberDB config("language") defaults to gb' );

    my $tbl = 'global_catalog';
    $adb->table_attr( $tbl, {
        record_index => 1,
        search_block => [ 2, 3 ], # Title, Desc
    });

    # Insert items in multiple languages
    $adb->insert_id( $tbl, 1, 'SKU-1', 'French Café Roastery', 'Artisan espresso blend' );
    $adb->insert_id( $tbl, 2, 'SKU-2', 'München Weissbier Glass', 'Traditionelles Glas aus Bayern' );
    $adb->insert_id( $tbl, 3, 'SKU-3', 'Türk Lokumu Şekerleme', 'Geleneksel antep fıstıklı tatlı' );

t/amberdb_cli.t  view on Meta::CPAN

    # Read session file content
    open my $fh, '<', $sess_file;
    local $/;
    my $sess_json = <$fh>;
    close $fh;
    my $sess_data = decode_json($sess_json);
    is($sess_data->{cfg}->{language}, 'tr', "Config language 'tr' saved in session");
};

# ---------------------------------------------------------------------------
subtest '3. Dash tolerance & global config update' => sub {
    plan tests => 4;

    # Connect to get token
    my $out_conn = `"$perl_bin" -Ilib "$cli_path" connect path-dbase_dir="$test_dbdir" format=json`;
    my $conn = eval { decode_json($out_conn) };
    my $token = $conn ? $conn->{token} : '';

    # Update with --cfg-no_write=1 (double dash)
    my $upd1 = `"$perl_bin" -Ilib "$cli_path" --token=$token --cfg-no_write=1 format=json 2>&1`;
    my $data1 = eval { decode_json($upd1) };

t/amberdb_ramdisk_tiers.t  view on Meta::CPAN

    is( $adb->config('use_ramdisk'), 1, "config('index') normalizes to 1" );

    $adb->config( use_ramdisk => 'none' );
    is( $adb->config('use_ramdisk'), 0, "config('none') normalizes to 0" );

    $adb->config( use_ramdisk => 'async' );
    is( $adb->config('use_ramdisk'), 4, "config('async') normalizes to 4" );

    # Global Tier 3 fallback to 0
    $adb->config( use_ramdisk => 'temp' );
    is( $adb->config('use_ramdisk'), 0, "config('temp') falls back to 0 globally" );

    $adb->config( use_ramdisk => 'volatile' );
    is( $adb->config('use_ramdisk'), 0, "config('volatile') falls back to 0 globally" );

    # 3. Table attribute string normalization
    $adb->table_attr( 'tbl_none',  use_ramdisk => 'none' );
    $adb->table_attr( 'tbl_index', use_ramdisk => 'index' );
    $adb->table_attr( 'tbl_dual',  use_ramdisk => 'dual' );
    $adb->table_attr( 'tbl_temp',  use_ramdisk => 'temp' );
    $adb->table_attr( 'tbl_async', use_ramdisk => 'async' );

    is( $adb->table_attr( 'tbl_none',  'use_ramdisk' ), 0, "table_attr('none') normalizes to 0" );
    is( $adb->table_attr( 'tbl_index', 'use_ramdisk' ), 1, "table_attr('index') normalizes to 1" );

t/amberdb_simple_mode.t  view on Meta::CPAN


        my @read = $adb->read_id( 'sessions', $id );
        is( $read[0], $id, "read_id returned exact ID: $id" );
        is( $read[1], 'Active', "read_id field 1 matches for $id" );

        my $exists = $adb->exist_id( 'sessions', $id );
        is( $exists, 1, "exist_id confirms key exists: $id" );
    }

    # Verify that ONLY sessions.db was created, NO index files (.inx, .fld, .src, .srt, .fac, .slg)
    my @created_files = glob("$db_dir/*");
    my @index_files   = grep { /\.(inx|fld|src|srt|fac|slg)$/ } @created_files;
    is_deeply( \@index_files, [], 'No index files (.inx, .fld, .src, .srt, .fac, .slg) generated' );
};

# ============================================================
# 2. CRUD Operations with Arbitrary IDs
# ============================================================
subtest '2. CRUD Lifecycle & Bulk Operations in Simple Mode' => sub {
    my $db_dir = "$tmp_dir/simple_db2";
    mkdir($db_dir);

t/amberdb_table_use_simple.t  view on Meta::CPAN

    ok( $del_res, 'delete_id succeeded' );

    my @after_del = $adb->read_id( 'sessions', $del_key );
    ok( !@after_del, 'Deleted record not returned by read_id' );

    # Check that .del archive file exists and contains the deleted record
    my $del_file = "$db_dir/table/sessions.del";
    ok( -e $del_file, 'sessions.del archive created by keep_deleted' );

    # Check that NO index files exist for sessions
    my @all_files = glob("$db_dir/table/*");
    my @index_files = grep { /sessions\.(inx|fld|src|srt|fac|slg)$/ } @all_files;
    is_deeply( \@index_files, [], 'No index files (.inx, .fld, .src, .srt, .fac, .slg) created for sessions' );
};

# ============================================================
# 4. Foreign Key (RDBM) & field_fetch Protection
# ============================================================
subtest '4. Foreign Key (RDBM) Guarding & field_fetch Unindexed Scan' => sub {
    plan tests => 5;

xt/amberdb_ramdisk.t  view on Meta::CPAN

        my $init_db = AmberDB->new(
            database => 'catalog',
            path     => { dbase_dir => $g_tmp }
        );

        $init_db->insert_id( 'catalog_books', 1, 'Book One' );
        $init_db->insert_id( 'catalog_authors', 10, 'Author Ten' );
        $init_db->insert_id( 'catalog_excluded', 99, 'Excluded Data' );
    }

    # 2. Open with global cfg => { use_ramdisk => 1 }
    my $adb_g1 = AmberDB->new(
        database => 'catalog',
        cfg  => { use_ramdisk => 1 },
        path => { dbase_dir => $g_tmp, ramdisk_dir => $g_ram }
    );

    # Access catalog_books via table_path
    my $b_path = $adb_g1->table_path('catalog_books');
    my $b_ram  = $adb_g1->ramdisk_path('catalog_books');

    ok( -e "$b_ram.inx", 'Global use_ramdisk => 1 preloads .inx to RAM-disk on table_path' );
    ok( !-e "$b_ram.db", 'Global use_ramdisk => 1 does NOT copy .db (data remains on disk)' );
    is( ($adb_g1->read_id('catalog_books', 1))[1], 'Book One', 'read_id works seamlessly' );

    # Access catalog_authors via table_info
    my $a_info = $adb_g1->table_info('catalog_authors');
    my $a_ram  = $adb_g1->ramdisk_path('catalog_authors');
    is( $a_info->{use_ramdisk}, 1, 'Table inherits global use_ramdisk => 1' );
    ok( -e "$a_ram.inx", 'Preloads .inx on table_info call' );

    # Check excluded table with explicit use_ramdisk => 0
    my $e_info = $adb_g1->table_info('catalog_excluded');
    my $e_ram  = $adb_g1->ramdisk_path('catalog_excluded');
    is( $e_info->{use_ramdisk}, 0, 'Table preserves explicit use_ramdisk => 0 override' );
    ok( !-e "$e_ram.inx", 'Excluded table is NOT copied to RAM-disk' );

    # 3. Open with global cfg => { use_ramdisk => 2 } (Full Table Acceleration)
    my $adb_g2 = AmberDB->new(
        database => 'catalog',
        cfg  => { use_ramdisk => 2 },
        path => { dbase_dir => $g_tmp, ramdisk_dir => $g_ram }
    );

    my $b2_path = $adb_g2->table_path('catalog_books');
    ok( -e "$b_ram.db", 'Global use_ramdisk => 2 preloads .db to RAM-disk on table_path' );
    ok( -e "$b_ram.inx", 'Global use_ramdisk => 2 keeps .inx on RAM-disk' );
    is( ($adb_g2->read_id('catalog_books', 1))[1], 'Book One', 'read_id reads from RAM-disk in mode 2' );

    # Insert new record under global mode 2
    $adb_g2->insert_id( 'catalog_books', 2, 'Book Two' );
    is( ($adb_g2->read_id('catalog_books', 2))[1], 'Book Two', 'Newly inserted record readable' );
    ok( -e "$b_ram.db", 'RAM-disk .db persists with new record' );
    ok( -e "$b_path.db", 'Permanent disk .db dual-written synchronously' );
};

subtest 'Unmounted RAM-disk strips use_ramdisk from table_info and table_attr' => sub {
    plan tests => 6;

    my $u_tmp = tempdir( CLEANUP => 1 );

xt/amberdb_ramdisk.t  view on Meta::CPAN

    # 1. From schema file
    my $file_info = $adb_unmounted->table_info('books_rd');
    ok( !exists $file_info->{use_ramdisk}, 'use_ramdisk stripped from schema file when RAM-disk is unmounted' );

    # 2. From table_attr
    $adb_unmounted->table_attr( 'dynamic_tbl', use_ramdisk => 1 );
    my $attr_info = $adb_unmounted->table_info('dynamic_tbl');
    ok( !exists $attr_info->{use_ramdisk}, 'use_ramdisk stripped from table_info after table_attr when unmounted' );
    is( $adb_unmounted->table_attr( 'dynamic_tbl', 'use_ramdisk' ), undef, 'table_attr getter returns undef when unmounted' );

    # 3. From global config inheritance
    my $glob_info = $adb_unmounted->table_info('unconfigured_tbl');
    ok( !exists $glob_info->{use_ramdisk}, 'Global use_ramdisk is NOT inherited when unmounted' );

    # 4. Now simulate mounted RAM-disk
    local $ENV{AMBERDB_TEST_RAMDISK} = 1;
    my $adb_mounted = AmberDB->new(
        database => 'unmount_test',
        cfg      => { use_ramdisk => 1 },
        path     => { dbase_dir => $u_tmp, ramdisk_dir => $u_ram }
    );

    my $m_file_info = $adb_mounted->table_info('books_rd');

xt/amberdb_ramdisk.t  view on Meta::CPAN

};

subtest 'use_ramdisk => 3 (Volatile RAM-Disk Tier 3 & TTL)' => sub {
    my $tmp = File::Temp->newdir( CLEANUP => 1 );
    my $t3_mount = File::Temp->newdir( CLEANUP => 1 );
    my $t3_ram = File::Spec->catdir( $t3_mount, 'amberdb_session_db' );
    make_path($t3_ram);
    local $ENV{AMBERDB_TEST_RAMDISK} = 1;

    # 1. Global use_ramdisk => 3 rejection/fallback to 0
    my $adb_global = AmberDB->new(
        database => 'session_db',
        cfg      => { use_ramdisk => 3 },
        path     => { dbase_dir => $tmp, ramdisk_dir => $t3_ram }
    );
    is( $adb_global->config('use_ramdisk'), 0, 'Global use_ramdisk => 3 in constructor falls back to 0' );

    $adb_global->config( use_ramdisk => 3 );
    is( $adb_global->config('use_ramdisk'), 0, 'Global config(use_ramdisk => 3) falls back to 0' );

    my $inh_info = $adb_global->table_info('unspec_table');
    is( $inh_info->{use_ramdisk}, 0, 'Unspecified table inherits 0, not 3' );

    # 2. Per-table use_ramdisk => 3 configuration and schema stripping
    my $adb = AmberDB->new(
        database => 'session_db',
        path     => { dbase_dir => $tmp, ramdisk_dir => $t3_ram }
    );
    my $ramdisk_dir = $adb->ramdisk_dir();

    $adb->table_attr( 'session_store',



( run in 2.037 seconds using v1.01-cache-2.11-cpan-4716db65a44 )