#!/usr/bin/env perl
use v5.38;
use DBIx::Fast;

# Raw SQL tour: DBIx::Fast never limits you to the CRUD helpers - write any
# statement you like and pick the method by what you want back. Values ALWAYS
# go in as ? placeholders (or :name for execute), bound and injection-safe;
# never interpolate data into the SQL string.
#
# Self-contained (SQLite in-memory), no server needed:
#   perl -Ilib examples/raw-sql.pl

my $db = DBIx::Fast->new(
    dsn => 'dbi:SQLite:dbname=:memory:', driver => 'SQLite',
    RaiseError => 1, PrintError => 0,
);

# --- DDL / DML via exec() (the general-purpose raw-SQL method) --------------
$db->exec(q{
    CREATE TABLE users (
        id     INTEGER PRIMARY KEY,
        name   TEXT NOT NULL,
        age    INTEGER,
        active INTEGER DEFAULT 1
    )
});
$db->exec('INSERT INTO users (name, age) VALUES (?, ?)', $_->[0], $_->[1])
    for [ 'Alice', 30 ], [ 'Bob', 17 ], [ 'Carol', 42 ], [ 'Dave', 25 ];

# --- SELECT: pick the return shape -----------------------------------------
say '== all()  — arrayref of hashrefs (every row):';
my $adults = $db->all('SELECT name, age FROM users WHERE age >= ? ORDER BY age', 18);
say "   $_->{name} ($_->{age})" for @$adults;

say '== hash() — a single row as a hashref:';
my $u = $db->hash('SELECT * FROM users WHERE name = ?', 'Alice');
say "   id=$u->{id} name=$u->{name} age=$u->{age}";

say '== val()  — a single scalar:';
say '   total users: ', $db->val('SELECT COUNT(*) FROM users');

say '== flat() — a flat list of one column:';
say '   names: ', join ', ', $db->flat('SELECT name FROM users ORDER BY name');

# --- Stream a large result set row by row with query() ----------------------
say '== query() — streaming iterator (no full slurp):';
my $rs = $db->query('SELECT id, name FROM users ORDER BY id');
while (my $row = $rs->hash) {
    say "   #$row->{id} $row->{name}";
}

# --- Raw UPDATE, then read it back -----------------------------------------
$db->exec('UPDATE users SET active = ? WHERE age < ?', 0, 18);
say '== after raw UPDATE — inactive users: ',
    $db->val('SELECT COUNT(*) FROM users WHERE active = 0');

# --- Named placeholders when positional ? gets awkward ----------------------
say '== execute() with :named placeholders:';
my $r = $db->execute(
    'SELECT name FROM users WHERE age BETWEEN :lo AND :hi ORDER BY age',
    { lo => 20, hi => 40 },
);
say "   $_->{name}" for @$r;

# The last statement / binds / result stay available:
say '== introspection: $db->sql = ', $db->sql;
