Skip to main content

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.

💡 tablesQLite focuses on table-level (DDL) logic.
💡 recordsQL handles 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 TABLE SQL strings.
  • Parse a SQL schema back into a SQLTableInfo object.
  • 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 SQLTableInfo with dynamic query builders via add_query_methods() from recordsQL.

🔧 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


📜 License

MIT License


Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tablesqlite-0.1.1.tar.gz (22.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tablesqlite-0.1.1-py3-none-any.whl (24.8 kB view details)

Uploaded Python 3

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

Hashes for tablesqlite-0.1.1.tar.gz
Algorithm Hash digest
SHA256 0ef306e59af9fef12853f53cee094d11589445acb3e615b01920d35cf4a24d43
MD5 211aa4e257063adc60e6215f86c961ac
BLAKE2b-256 10862085aaa359a7b75c6a4779c40b73610935564a9832b8d121c0ebf3c9f540

See more details on using hashes here.

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

Hashes for tablesqlite-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 e419602e9936919529cecc0170d4b87a8006a8c1b6cc00982de1d231ede7be2a
MD5 7b7c10aa48385bc62cf976de078824c5
BLAKE2b-256 1faa29fd8484a110ee90e207a0320d1a911f4f588b9230870058d7b0a39f0721

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page