Declarative SQLite table builder and schema manager with integration support for recordsQL.
Project description
tablesQLite + recordsQL Integration Example
This project demonstrates how to use tablesQLite for defining table schemas and recordsQL for generating flexible, expressive SQL queries — including INSERT, UPDATE, SELECT, and more — with a focus on type-safe, validated column operations.
💡
tablesQLitefocuses on table-level (DDL) logic.
💡recordsQLhandles record-level (DML) operations like insertions, updates, selects, etc.
✅ This separation encourages clear modular design.
📦 Installation
pip install tablesqlite recordsql expressql
📋 Features
- Define tables with rich column constraints (types, nulls, defaults, foreign keys, uniqueness, checks).
- Generate full
CREATE TABLESQL strings. - Parse a SQL schema back into a
SQLTableInfoobject. - Insert and manipulate rows using
recordsQL-based query builders. - Optional integration: dynamically patch record query methods into your
SQLTableInfo.
🧪 Quick Example
Step 1: Define a table
from tablesqlite import SQLColumnInfo, SQLTableInfo
from expressQL import parse_condition, cols, col
col_names = ("id", "name", "age", "email", "balance", "is_active", "created_at", "updated_at", "cc_number")
datatypes = ("INTEGER", "TEXT", "INTEGER", "TEXT", "REAL", "BOOLEAN", "DATETIME", "DATETIME", "INTEGER")
not_nulls = (True, False, True, False, False, True, True, True, True)
default_values = (None, None, None, None, 0.0, False, "CURRENT_TIMESTAMP", "CURRENT_TIMESTAMP", None)
primary_keys = (True, False, False, False, False, False, False, False, False)
uniques = (True, False, False, True, False, False, False, False, True)
foreign_keys = (None, None, None, None, None, None, None, None, {"table": "credit_cards", "column": "cc_number"})
id, balance, age = cols("id", "balance", "age")
checks = (
parse_condition("id > 0"), None, parse_condition("age >= 18"), None,
parse_condition("balance >= 0"), None, None, None, None)
columns = [
SQLColumnInfo(name, dtype, not_null=nn, default_value=defv,
primary_key=pk, unique=uq, foreign_key=fk, check=chk)
for name, dtype, nn, defv, pk, uq, fk, chk in zip(
col_names, datatypes, not_nulls, default_values,
primary_keys, uniques, foreign_keys, checks)
]
table_info = SQLTableInfo(
name="users",
columns=columns,
foreign_keys=[
{"columns": ["cc_number"], "ref_table": "credit_cards", "ref_columns": ["cc_number"]}
]
)
query, _ = table_info.create_query()
print(query)
"""
>>> query1= CREATE TABLE "users" ("id" INTEGER UNIQUE PRIMARY KEY CHECK (id > 0),
"name" TEXT, "age" INTEGER NOT NULL CHECK (age >= 18),
"email" TEXT UNIQUE, "balance" REAL DEFAULT 0.0 CHECK (balance >= 0),
"is_active" BOOLEAN NOT NULL DEFAULT False,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, "cc_number" INTEGER UNIQUE NOT NULL, FOREIGN KEY ("cc_number") REFERENCES credit_cards("cc_number"));
"""
Step 2: Validate Table Equality
table_info_ = SQLTableInfo.from_sql_schema(query)
assert query == table_info_.create_query()[0]
assert table_info.to_dict() == table_info_.to_dict()
Step 3: Enable Record Queries
from recordsQL.integrations.tablesqlite import add_query_methods
add_query_methods() # Dynamically injects insert/update/select/delete into SQLTableInfo
Step 4: Create an Insert Query
from expressQL import cols
from datetime import datetime, timedelta
data = {
"id": 1,
"name": "John Doe",
"age": 30,
"email": "johndoe@gmail.com"
}
timestamp = (datetime.now() - timedelta(days=5)).isoformat()
extra = [("balance", 100.0), ("is_active", True), ("created_at", timestamp), ("updated_at", timestamp)]
insert_q = table_info.insert_query(data, *extra, returning=cols("id", "name", "age", "email"))
print("Insert Query:", *insert_query.placeholder_pair())
"""
Insert Query: INSERT INTO "users" (id, name, age, email, balance, is_active, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?) RETURNING id, name, age, email
[1, 'John Doe', 30, 'johndoe@gmail.com', 100.0, 1, '2025-05-23T22:18:14.115497', '2025-05-23T22:18:14.115497']
"""
⚠️ Column Validation Examples
try:
i_query = table_info.insert_query({"non_column": 0}, returning = cols("id", "name", "age", "email"), if_column_exists=True)
except ValueError as e:
print(f"Caught expected ValueError: {e}")
print("Caught expected ValueError for non-existing column in insert query.")
try:
i_query = table_info.insert_query({"non_column": 0},
returning = cols("id", "name", "age", "email"), if_column_exists=True,
resolve_by="ignore")
except ValueError as e:
print(f"Caught expected ValueError: {e}")
print("Caught expected error for no valid columns in insert query.")
"""
Caught expected ValueError: If 'if_column_exists' is True, all provided columns must exist in the table.
Caught expected ValueError for non-existing column in insert query.
Caught expected ValueError: No valid columns provided for insertion.
Caught expected error for no valid columns in insert query.
"""
✅ Ignoring Invalid Columns Gracefully
i_query = table_info.insert_query({"non_column": 0, "name": "Jane Doe"},
returning = cols("id", "name", "age", "email"), if_column_exists=True,
resolve_by="ignore")
print("Insert Query with ignored non-existing column:")
print(*i_query.placeholder_pair())
"""
INSERT INTO "users" (name) VALUES (?) RETURNING id, name, age, email
['Jane Doe']
"""
🧩 Design Philosophy
tablesQLite= Table definitions, constraints, schema parsing (DDL).recordsQL= Insert, select, update, delete, joins, withs, expressions (DML).- You can extend
SQLTableInfowith dynamic query builders viaadd_query_methods()fromrecordsQL.
🔧 Advanced
Want to create your own patch or only expose selected methods?
from recordsQL.integrations.tablesqlite import insert_query_for
query = insert_query_for(table_info, name="Test", age=25)
📚 Dependencies
expressQL: SQL expression builder.recordsQL: Record-level query generation.tablesQLite: Table schema abstraction (you’re here!).
📜 License
MIT License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tablesqlite-0.1.1.tar.gz.
File metadata
- Download URL: tablesqlite-0.1.1.tar.gz
- Upload date:
- Size: 22.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0ef306e59af9fef12853f53cee094d11589445acb3e615b01920d35cf4a24d43
|
|
| MD5 |
211aa4e257063adc60e6215f86c961ac
|
|
| BLAKE2b-256 |
10862085aaa359a7b75c6a4779c40b73610935564a9832b8d121c0ebf3c9f540
|
File details
Details for the file tablesqlite-0.1.1-py3-none-any.whl.
File metadata
- Download URL: tablesqlite-0.1.1-py3-none-any.whl
- Upload date:
- Size: 24.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e419602e9936919529cecc0170d4b87a8006a8c1b6cc00982de1d231ede7be2a
|
|
| MD5 |
7b7c10aa48385bc62cf976de078824c5
|
|
| BLAKE2b-256 |
1faa29fd8484a110ee90e207a0320d1a911f4f588b9230870058d7b0a39f0721
|