Database Persistence Layer for TCL
Contact: neophytos (at) gmail (dot) com
https://github.com/jerily/tpersist%|%tpersist git repo%|%
This module was generated with help from AI.
****Releases****
* 2026-10-31 https://github.com/jerily/tpersist/releases/tag/v0.1.0%|%tpersist-v0.1.0%|% (Initial release of tpersist, a Tcl SQL toolkit inspired by SQLAlchemy Core.)
----
****Examples****
***Examples***
Here are some examples with optional [TclOO] API:
====== package require tpersist::oo
namespace import ::tpersist::db_*
set database [::tpersist::oo::Database new -database :memory:]
try {
$database create_table [db_define_table users {
id {type integer primary_key 1 auto_increment 1}
name {type text}
age {type integer}
}]
set insert [$database insert users]
$database transaction {
foreach {name age} {Alice 30 Bob 17 Carol 42} {
$insert values [dict create name $name age $age]
$insert execute
}
}
# set everyone [$database select users -columns {name age}]
set everyone [$database select users -expr {name, age}]
set adults [$everyone fork]
# $adults where [db_ge [db_col age] [db_value 18 -type integer]]
$adults where -expr {age >= 18}
# $adults order_by [db_desc [db_col age]]
$adults order_by -expr {age DESC}
$adults limit 10
puts "Adults: [$adults all]"
puts "Everyone: [$everyone all]"
# Interoperate with procedural code using the same statement dictionary.
puts "SQL: [dict get [db_compile [$adults statement]] sql]"
puts "Params: [dict get [db_compile [$adults statement]] params]"} finally {
# Also destroys its queries and disconnects the TDBC connection.
$database destroy}
# Adults: {name Carol age 42} {name Alice age 30}
# Everyone: {name Alice age 30} {name Bob age 17} {name Carol age 42}
# SQL: SELECT "name", "age" FROM "users" WHERE ("age" >= :p1) ORDER BY "age" DESC LIMIT :p2
# Params: p1 18 p2 10
======
****Transactions****
======
package require tpersist::oo
namespace import ::tpersist::db_*
set database [::tpersist::oo::Database new -database :memory:]
try {
$database create_table [db_define_table accounts {name {type text primary_key 1} balance {type integer not_null 1}}]
set insert [$database insert accounts]
$database transaction {
$insert values {name Alice balance 100}
$insert execute
$insert values {name Bob balance 20}
$insert execute
}
$database transaction {
set alice [$database update accounts]
# $alice where [db_eq [db_col name] [db_value Alice]]
$alice where -expr {name = 'Alice'}
set bob [$database update accounts]
# $bob where [db_eq [db_col name] [db_value Bob]]
$bob where -expr {name = 'Bob'}
$alice values {balance 90}
$alice execute
$bob values {balance 30}
$bob execute
# This nested scope has its own savepoint. Its failure does not undo
# the successful transfer in the surrounding transaction.
if {[catch {$database transaction {
# Rollback affects database rows, not mutable query objects.
set adjustment [$alice fork]
$adjustment values {balance 0}
$adjustment execute
error "Rejected optional adjustment"
}} message]} { puts $message }
}
set accounts [$database select accounts]
# $accounts order_by name
$accounts order_by -expr {name}
puts "After transfer: [$accounts all]"
$database commit
# Explicit savepoints use the procedural API with a borrowed connection.
set connection [$database connection]
$database begin
db_savepoint $connection experiment
set remove [$database delete accounts]
$remove execute
db_rollback_to $connection experiment
db_release $connection experiment
$database commit
puts "After undo: [$accounts all]"
} finally {
# Also destroys its queries and disconnects the TDBC connection.
$database destroy
}
======