=============== LIBRARY RULES =============== From library maintainers: - CRITICAL: This library requires Python 3.14+ due to PEP 750 t-strings. Never suggest it for older Python versions. - Install with 'uv add t-sql' or 'pip install t-sql'. Use 't-sql[sqlalchemy]' for SQLAlchemy/Alembic integration. - Always use t-strings (t"...") not regular strings ("") or f-strings (f""") for SQL queries. The library is designed so raw strings won't work - this prevents SQL injection by design. - Use the query builder (@table decorator with typed columns) for complex multi-table joins and structured queries. Use t-string templating for simpler queries or custom SQL logic that the query builder doesn't support. - The :literal format spec is for dynamic table/column names that cannot be parameterized. It sanitizes against valid SQL identifiers. - The :unsafe format spec bypasses all safety checks. Only use with hardcoded strings, never with user input. - The :as_values format spec converts dicts to INSERT VALUES format. The :as_set format spec converts dicts to UPDATE SET format. - When mixing query builder with t-strings using .where(), t-string conditions are automatically wrapped in parentheses for proper operator precedence. - The @table decorator returns an instance - use the decorated class directly, don't instantiate it. - Default parameter style is QMARK (?). Use tsql.styles.NUMERIC_DOLLAR for PostgreSQL ($1, $2), or other styles as needed. ### Install t-sql with pip or uv Source: https://github.com/nhumrich/t-sql/blob/main/README.md Install the t-sql library using pip or uv. This is the first step before using the library. ```bash pip install t-sql ``` ```bash uv add t-sql ``` -------------------------------- ### Install t-sql with SQLAlchemy support Source: https://github.com/nhumrich/t-sql/blob/main/README.md Install the t-sql library with optional SQLAlchemy support using pip or uv. This is required for SQLAlchemy and Alembic integration. ```bash pip install t-sql[sqlalchemy] # or uv add t-sql --optional sqlalchemy ``` -------------------------------- ### Row Constructor Examples Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/row.md Demonstrates various ways to initialize a Row object, including from a dictionary, keyword arguments, or an iterable. ```python # From dict row = Row({'id': 1, 'name': 'Alice', 'email': 'alice@example.com'}) # From kwargs row = Row(id=1, name='Alice', email='alice@example.com') # From iterable row = Row([('id', 1), ('name', 'Alice')]) ``` -------------------------------- ### Type-Safe Query Execution Example Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/types.md Demonstrates how to use the TSQLQuery type hint for type-safe query execution. It shows examples of type-safe calls and a type error for raw strings. ```python def execute(query: TSQLQuery) -> None: sql, params = tsql.render(query) db.execute(sql, params) execute(t"SELECT * FROM users WHERE id = {id}") # ✓ Type-safe execute(Users.select()) # ✓ Type-safe execute("SELECT * FROM users") # ✗ Type error ``` -------------------------------- ### Start SELECT Query Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/query-builder.md Initiate a SELECT query using the `select` class method on a Table subclass. Specify columns to select or omit for SELECT *. ```python from tsql.query_builder import Table, Column class Users(Table): id: Column name: Column email: Column # SELECT all columns query = Users.select() # SELECT specific columns query = Users.select(Users.id, Users.name) # With WHERE and LIMIT query = Users.select(Users.id, Users.name).where(Users.age > 18).limit(10) ``` -------------------------------- ### Start DELETE Query Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/query-builder.md Begin a DELETE query with the `delete` class method. Use `where` to specify conditions or `all_rows()` to delete all records. ```python query = Users.delete().where(Users.id == 'abc123') sql, params = query.render() # ('DELETE FROM users WHERE users.id = ?', ['abc123']) # Delete all rows (requires explicit confirmation) query = Users.delete().all_rows() ``` -------------------------------- ### LIMIT and OFFSET for Pagination Source: https://github.com/nhumrich/t-sql/blob/main/README.md Implements `limit()` and `offset()` for controlling the number of results returned and the starting point, useful for pagination. ```python # LIMIT and OFFSET query = Posts.select().limit(10).offset(20) ``` -------------------------------- ### Start INSERT Query Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/query-builder.md Begin an INSERT query with the `insert` class method, providing column values as keyword arguments. Supports ON CONFLICT and RETURNING clauses. ```python query = Users.insert(id='abc123', name='bob', email='bob@example.com') sql, params = query.render() # ('INSERT INTO users (id, name, email) VALUES (?, ?, ?)', # ['abc123', 'bob', 'bob@example.com']) # With ON CONFLICT query = Users.insert(id='abc123', name='bob').on_conflict_do_nothing('id') # With RETURNING query = Users.insert(id='abc123', name='bob').returning('id') ``` -------------------------------- ### Select All Columns Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/configuration.md Select all columns from a table. No specific setup is required beyond having the table object defined. ```python Users.select() ``` -------------------------------- ### Multi-Environment Configuration Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/configuration.md Configure T-SQL settings based on the application environment (production, mysql, development). This example shows how to set parameter styles and schemas dynamically. ```python # config.py import tsql import os # Environment-based settings ENV = os.getenv('APP_ENV', 'development') if ENV == 'production': DEFAULT_PARAM_STYLE = tsql.styles.NUMERIC_DOLLAR # PostgreSQL DEFAULT_SCHEMA = 'public' elif ENV == 'mysql': DEFAULT_PARAM_STYLE = tsql.styles.FORMAT DEFAULT_SCHEMA = None else: # development/sqlite DEFAULT_PARAM_STYLE = tsql.styles.QMARK DEFAULT_SCHEMA = None # app.py from config import DEFAULT_PARAM_STYLE, DEFAULT_SCHEMA import tsql ts-sql.set_style(DEFAULT_PARAM_STYLE) # Tables inherit schema from environment class Users(Table, schema=DEFAULT_SCHEMA): id: Column name: Column # All queries automatically use correct parameter style sql, params = Users.select().render() ``` -------------------------------- ### Order By Clause Usage Example Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/types.md Shows how to use OrderByClause instances, generated by .asc() and .desc() methods, within the order_by() method of a query builder. ```python Users.select().order_by(Users.created_at.desc(), Users.id.asc()) ``` -------------------------------- ### String-Based Query Builder Examples Source: https://github.com/nhumrich/t-sql/blob/main/README.md Demonstrates building SELECT, INSERT, UPDATE, and DELETE queries using string table and column names. Supports features like conflict handling and returning clauses. ```python from tsql.query_builder import SelectQueryBuilder, InsertBuilder, UpdateBuilder, DeleteBuilder # SELECT user_id = 123 status = 'active' query = SelectQueryBuilder.from_table('users', schema='public') \ .select('id', 'name', 'email') \ .where(t'id = {user_id} AND status = {status}') \ .order_by('created_at', direction='DESC') \ .limit(10) sql, params = query.render() # INSERT query = InsertBuilder.into_table('users', {'name': 'Bob', 'email': 'bob@test.com'}) .on_conflict_do_nothing('email') .returning('id') # UPDATE cutoff_date = '2024-01-01' query = UpdateBuilder.table('users', {'status': 'inactive'}) .where(t'last_login < {cutoff_date}') # DELETE cutoff = '2023-01-01' query = DeleteBuilder.from_table('users') .where(t'created_at < {cutoff}') ``` -------------------------------- ### Start UPDATE Query Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/query-builder.md Initiate an UPDATE query using the `update` class method, specifying columns to update. Supports WHERE clauses and updating all rows with `all_rows()`. ```python query = Users.update(name='alice').where(Users.id == 'abc123') sql, params = query.render() # ('UPDATE users SET name = ? WHERE users.id = ?', # ['alice', 'abc123']) # Update all rows (requires explicit confirmation) query = Users.update(status='inactive').all_rows() ``` -------------------------------- ### Convert Query Builder to TSQL or Render SQL Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/query-builder.md Use to_tsql() to get a TSQL object representation of the query, or render() to get the SQL string and parameters. The render() method accepts an optional style argument. ```python def to_tsql(self) -> TSQL def render(self, style=None) -> tuple[str, list] ``` -------------------------------- ### Condition Usage Examples Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/types.md Illustrates the creation of Condition objects using column comparison operators (>, in_()) for use in where() and other clause methods. ```python Users.select().where(Users.age > 18) Posts.select().where(Posts.user_id.in_([1, 2, 3])) ``` -------------------------------- ### Using Type Processor with SAColumn Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/type-processor.md Example of using the SAColumn helper to apply an EncryptedString type processor to a column. ```python class Users(Table): ssn = SAColumn(String(255), type_processor=EncryptedString(key)) ``` -------------------------------- ### Parameter Name Sanitization Examples Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/parameter-styles.md Demonstrates how parameter names are sanitized for NAMED and PYFORMAT styles, including handling complex expressions and name collisions. ```python query = t"WHERE age = {age}" # Parameter: age ``` ```python query = t"WHERE value = {user.first_name}" # Parameter: user_first_name ``` ```python query = t"WHERE value = {items[0]}" # Parameter: items_0_ ``` ```python query = t"WHERE a = {x} AND b = {x}" # Parameters: x, x_1 ``` -------------------------------- ### Define SQLAlchemy Table with SAColumn and Type Processor Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/query-builder.md Example demonstrating `SAColumn` usage with a custom `TypeProcessor` for value transformation during binding and result retrieval. ```python # With type processor class EncryptedString(TypeProcessor): def process_bind_param(self, value): return encrypt(value) def process_result_value(self, value): return decrypt(value) class Users(Table, metadata=metadata): ssn = SAColumn(String(255), type_processor=EncryptedString()) ``` -------------------------------- ### Define SQLAlchemy Table with SAColumn Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/query-builder.md Example of defining a SQLAlchemy Table using `SAColumn` for type-safe tsql column integration. Includes basic column definitions. ```python from tsql.query_builder import Table, SAColumn from tsql.type_processor import TypeProcessor from sqlalchemy import Integer, String, MetaData metadata = MetaData() class Users(Table, metadata=metadata): id = SAColumn(Integer, primary_key=True) name = SAColumn(String(100)) email = SAColumn(String(255), unique=True) ``` -------------------------------- ### Row Dictionary Methods and Iteration Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/row.md Shows how to use standard dictionary methods like iteration, accessing keys, values, and items, getting values with defaults, popping items, clearing the row, and updating from another dictionary. ```python row = Row({'id': 1, 'name': 'Alice', 'email': 'alice@example.com'}) # Iteration for key in row: print(f"{key}: {row[key]}") # Keys, values, items row.keys() # dict_keys(['id', 'name', 'email']) row.values() # dict_values([1, 'Alice', 'alice@example.com']) row.items() # dict_items([('id', 1), ('name', 'Alice'), ('email', 'alice@example.com')]) # Get with default row.get('age', 0) # 0 # Pop and clear row.pop('email') # 'alice@example.com' row.clear() # Remove all items # Update from another dict row.update({'age': 30, 'status': 'active'}) ``` -------------------------------- ### Set Global Default Style Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/parameter-styles.md Set a global default parameter style for all subsequent query renders. This example sets PostgreSQL style as the default. ```python import tsql # Set PostgreSQL as the global default tsql.set_style(tsql.styles.NUMERIC_DOLLAR) # All subsequent renders use this style query = TSQL(t"SELECT * FROM users WHERE id = {user_id}") sql, params = query.render() # Uses $1 placeholder ``` -------------------------------- ### Column Usage Example Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/types.md Demonstrates how to define and use Column objects within a Table subclass for building queries. Columns are accessed as class attributes and used with comparison operators. ```python class Users(Table): id: Column name: Column email: Column Users.select(Users.id, Users.name).where(Users.age > 18) ``` -------------------------------- ### Mixed Access Methods for Row Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/row.md Demonstrates the interchangeability of attribute-style and dictionary-style access for getting and setting row data. ```python row = Row({'id': 1, 'name': 'Alice', 'created_at': '2024-01-01'}) # Both work interchangeably row.id == row['id'] # True row.name == row['name'] # True # Set via attribute row.status = 'active' print(row['status']) # 'active' # Set via dict row['email'] = 'new@example.com' print(row.email) # 'new@example.com' ``` -------------------------------- ### SelectQueryBuilder.from_table() Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/query-builder.md Creates a SelectQueryBuilder instance starting from a specified table. This method allows for setting a schema, an alias, and can be used to emit `FROM ONLY` for PostgreSQL. ```APIDOC ## SelectQueryBuilder.from_table() ### Description Creates a SelectQueryBuilder instance starting from a specified table. This method allows for setting a schema, an alias, and can be used to emit `FROM ONLY` for PostgreSQL. ### Method `classmethod` ### Parameters #### Path Parameters - **table_name** (str) - Required - Table name - **schema** (str) - Optional - Schema name - **only** (bool) - Optional - Emit `FROM ONLY` for PostgreSQL table inheritance - **alias** (str) - Optional - Alias for table (validated as identifier) ``` -------------------------------- ### Example EncryptedString TypeProcessor Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/types.md Demonstrates a concrete implementation of TypeProcessor for encrypting and decrypting string values. This is useful for handling sensitive data like Social Security Numbers. ```python class EncryptedString(TypeProcessor): def __init__(self, key: str): self.key = key def process_bind_param(self, value: Any) -> Any: return encrypt(value, self.key) if value is not None else None def process_result_value(self, value: Any) -> Any: return decrypt(value, self.key) if value is not None else None class Users(Table): ssn = SAColumn(String(255), type_processor=EncryptedString(key='secret')) ``` -------------------------------- ### LIKE Pattern for Prefix Search Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/core-tsql.md Use the :like% format spec to wrap a value with '%' at the end for a prefix (starts with) search. It automatically escapes SQL wildcards like '%', '_', and '\'. ```python prefix = "admin" query = t"SELECT * FROM users WHERE username LIKE {prefix:like%}" # Produces: "... username LIKE ? ESCAPE '\'" with value 'admin%' ``` -------------------------------- ### Row Attribute and Dictionary Access Example Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/types.md Demonstrates accessing and modifying row data using both attribute-style (e.g., results[0].name) and dictionary-style (e.g., results[0]['email']) access, as provided by the Row class. ```python results = query.map_results(rows) print(results[0].name) # Attribute access print(results[0]['email']) # Dict access results[0].age = 30 # Set via attribute ``` -------------------------------- ### Create SelectQueryBuilder from Table Name Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/query-builder.md Use this class method to initialize a SelectQueryBuilder from a table name, optionally specifying a schema and an alias. This is useful when you need to start building a query from a table not directly mapped to a Python class. ```python from tsql.query_builder import SelectQueryBuilder query = SelectQueryBuilder.from_table('users', schema='public', alias='u') query = query.select('u.id', 'u.name').where(t'u.age > 18') ``` -------------------------------- ### ImportError: SQLAlchemy Not Installed Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/errors.md This error occurs when attempting to use `SAColumn()` without having SQLAlchemy installed in your environment. Ensure SQLAlchemy is installed if you need to use this feature. ```python from tsql.query_builder import SAColumn # ImportError: "SQLAlchemy is not installed. Cannot use SAColumn() helper." ``` -------------------------------- ### Basic t-sql Usage with Default QMARK Style Source: https://github.com/nhumrich/t-sql/blob/main/README.md Demonstrates basic usage of t-sql by rendering a simple SQL query with a string parameter using the default QMARK style. ```python import tsql # Basic usage name = 'billy' query = t'select * from users where name={name}' # Render with default QMARK style sql, params = tsql.render(query) # ('select * from users where name = ?', ['billy']) ``` -------------------------------- ### Handle UnsafeQueryError in Python Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/types.md Example of how to catch and handle the UnsafeQueryError when rendering an UPDATE query without a WHERE clause. ```python try: Users.update(status='inactive').render() except UnsafeQueryError: print("UPDATE requires WHERE or .all_rows()") ``` -------------------------------- ### Configuration Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/README.md Information on setting up and customizing the t-sql library. ```APIDOC ## Global Default Parameter Style ### Description Set the default parameter style for all queries using `t_sql.set_style()`. ## Per-Query Style Overrides ### Description Specify a different parameter style for individual queries. ## Table Definition Configuration ### Description Configure table names, schemas, and metadata. ## Column Configuration ### Description Configure column types, constraints, default values, and type processors. ## INSERT/UPDATE/DELETE Configuration ### Description Configure conflict handling, `RETURNING` clauses, and safety guards. ## Query Builder Configuration ### Description Configure columns, joins, grouping, ordering, and pagination for query builders. ## Multi-Environment Setup ### Description Patterns for setting up the library across different environments (e.g., development, production). ``` -------------------------------- ### Fluent API Query Construction Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/README.md Demonstrates building a complex SQL query using method chaining with the fluent API. This approach enhances readability and maintainability. ```python query = ( Users .select(Users.id, Users.name) .where(Users.age > 18) .where(Users.active == True) .order_by(Users.created_at.desc()) .limit(10) ) ``` -------------------------------- ### Quick INSERT Query Source: https://github.com/nhumrich/t-sql/blob/main/README.md Use the insert helper function to generate INSERT statements. Provide the table name and key-value pairs for the columns to be inserted. ```python query = tsql.insert('users', id='abc123', name='bob', email='bob@example.com') sql, params = query.render() # ('INSERT INTO users (id, name, email) VALUES (?, ?, ?)', ['abc123', 'bob', 'bob@example.com']) ``` -------------------------------- ### QMARK Parameter Style Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/parameter-styles.md Default style using `?` placeholders. Compatible with SQLite, ODBC, and most Python drivers. Parameters are passed as a list. ```python import tsql query = TSQL(t"SELECT * FROM users WHERE name = {name} AND age = {age}") sql, params = query.render(style=tsql.styles.QMARK) # SQL: "SELECT * FROM users WHERE name = ? AND age = ?" # Params: ['billy', 30] ``` -------------------------------- ### Quick SELECT Query Source: https://github.com/nhumrich/t-sql/blob/main/README.md Use the select helper function for concise SELECT statements. It supports selecting all columns, specific columns, and adding WHERE clauses. ```python # Select all columns query = tsql.select('users') sql, params = query.render() # ('SELECT * FROM users', []) # Select specific columns query = tsql.select('users', columns=['name', 'email']) sql, params = query.render() # ('SELECT name, email FROM users', []) # With WHERE clause query = tsql.select('users', columns=['name', 'email'], where={'age': 18}) sql, params = query.render() # ('SELECT name, email FROM users WHERE age = ?', [18]) ``` -------------------------------- ### to_tsql() and render() Methods Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/query-builder.md Methods to convert the built query into its T-SQL string representation or a renderable tuple. ```APIDOC ## to_tsql() and render() Methods ```python def to_tsql(self) -> TSQL def render(self, style=None) -> tuple[str, list] ``` ``` -------------------------------- ### Override Default Style Per Query Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/parameter-styles.md Override the default parameter style for a specific query. This example shows overriding the default QMARK style to NUMERIC_DOLLAR. ```python import tsql # Default is QMARK query = TSQL(t"SELECT * FROM users WHERE id = {user_id}") sql, params = query.render() # Uses ? # Override for specific query sql, params = query.render(style=tsql.styles.NUMERIC_DOLLAR) # Uses $1 ``` -------------------------------- ### Insert Data with Custom TypeProcessors Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/type-processor.md Demonstrates inserting data into the `User` table, showing how the `EncryptedString` and `JSONType` processors automatically handle encryption and serialization. ```python # Write - automatic encryption/serialization cipher = Fernet.generate_key() enc = EncryptedString(Fernet(cipher)) json_proc = JSONType() User.insert( ssn='123-45-6789', preferences={'theme': 'dark', 'language': 'en'}, email='user@example.com' ) # SQL: INSERT INTO user (ssn, preferences, email) VALUES (?, ?, ?) # Params: ['gAAAAABl...encrypted...', '{"theme":"dark","language":"en"}', 'user@example.com'] ``` -------------------------------- ### to_tsql() and render() Methods Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/query-builder.md Methods to finalize and execute the UPDATE query. `to_tsql()` returns the TSQL object, while `render()` returns the SQL string and parameters. Both will raise an `UnsafeQueryError` if the query is not properly secured with a WHERE clause or `all_rows()` confirmation. ```APIDOC ## to_tsql() and render() Methods ```python def to_tsql(self) -> TSQL def render(self, style=None) -> tuple[str, list] ``` **Raises**: `UnsafeQueryError` if render() called without WHERE or .all_rows() ``` -------------------------------- ### Type Processors in WHERE Clauses Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/type-processor.md Type processors are automatically applied to values in WHERE clauses when comparing columns. This ensures data consistency and security, for example, by encrypting search values. ```python class Users(Table): email = SAColumn(String(255), type_processor=EncryptedString()) # The type processor is applied to the search value query = Users.select().where(Users.email == 'user@example.com') # WHERE email = ? with params: [encrypt('user@example.com')] ``` -------------------------------- ### String Matching with like(), ilike(), etc. Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/query-builder.md Builds LIKE and ILIKE conditions for pattern matching in string columns. Supports case-sensitive and case-insensitive matching. ```python def like(self, pattern: str) -> Condition def not_like(self, pattern: str) -> Condition def ilike(self, pattern: str) -> Condition # Case-insensitive def not_ilike(self, pattern: str) -> Condition ``` ```python Users.select().where(Users.email.like('%@gmail.com')) Users.select().where(Users.username.ilike('%admin%')) # Case-insensitive ``` -------------------------------- ### EncryptedString TypeProcessor Implementation Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/type-processor.md Example implementation of TypeProcessor for encrypting string values before database storage and decrypting them upon retrieval. Handles NULL values by returning None. ```python class EncryptedString(TypeProcessor): def __init__(self, key: str): self.key = key def process_bind_param(self, value: Any) -> Any: """Encrypt before storing in database.""" if value is None: return None return encrypt(value, self.key) def process_result_value(self, value: Any) -> Any: """Decrypt when reading from database.""" if value is None: return None return decrypt(value, self.key) ``` -------------------------------- ### Build SELECT query with string table/column names Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/query-builder.md Use `from_table` to specify the table, schema, and alias. Then chain `select` and `where` clauses using string identifiers. ```python SelectQueryBuilder.from_table('users', schema='public', alias='u') .select('id', 'name') .where(t'u.age > {min_age}') ``` -------------------------------- ### LIKE Pattern for Suffix Search Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/core-tsql.md Use the :%like format spec to wrap a value with '%' at the start for a suffix (ends with) search. It automatically escapes SQL wildcards like '%', '_', and '\'. ```python domain = "@gmail.com" query = t"SELECT * FROM users WHERE email LIKE {domain:%like}" # Produces: "... email LIKE ? ESCAPE '\'" with value '%@gmail.com' ``` -------------------------------- ### Table.select() Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/query-builder.md Initiates the construction of a SELECT query for a given table. Allows specifying specific columns or selecting all columns. ```APIDOC ## Table.select() ### Description Start building a SELECT query. ### Method `classmethod` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters * `*columns` (Column | Template) - Optional - Specific columns to select; omit for SELECT * ### Returns `SelectQueryBuilder` for method chaining ### Example ```python from tsql.query_builder import Table, Column class Users(Table): id: Column name: Column email: Column # SELECT all columns query = Users.select() # SELECT specific columns query = Users.select(Users.id, Users.name) # With WHERE and LIMIT query = Users.select(Users.id, Users.name).where(Users.age > 18).limit(10) ``` ``` -------------------------------- ### JSONType TypeProcessor Implementation Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/type-processor.md Example implementation of TypeProcessor for serializing Python dictionaries/lists to JSON strings before database storage and deserializing them back upon retrieval. Handles NULL values by returning None. ```python class JSONType(TypeProcessor): def process_bind_param(self, value: Any) -> Any: """Serialize Python dict/list to JSON string.""" if value is None: return None return json.dumps(value) def process_result_value(self, value: Any) -> Any: """Deserialize JSON string to Python dict/list.""" if value is None: return None return json.loads(value) ``` -------------------------------- ### Row Representation and String Conversion Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/row.md Demonstrates how to create a Row object and view its representation for debugging or its string representation. ```python row = Row(id=1, name='Alice', email='alice@example.com') print(repr(row)) # Row(id=1, name='Alice', email='alice@example.com') print(str(row)) # {'id': 1, 'name': 'Alice', 'email': 'alice@example.com'} ``` -------------------------------- ### Define Table with Custom Type Processors Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/configuration.md Define a table with columns that utilize custom type processors for data transformation. This example shows how to use `EncryptedString` for sensitive data and `JSONType` for preferences. ```python from tsql import TypeProcessor from tsql.query_builder import Table, SAColumn from sqlalchemy import String, MetaData, Integer import json metadata = MetaData() class EncryptedString(TypeProcessor): def __init__(self, key: str): self.key = key def process_bind_param(self, value): """Encrypt before insert/update.""" return encrypt(value, self.key) if value is not None else None def process_result_value(self, value): """Decrypt after fetch.""" return decrypt(value, self.key) if value is not None else None class JSONType(TypeProcessor): def process_bind_param(self, value): """Serialize dict/list to JSON.""" return json.dumps(value) if value is not None else None def process_result_value(self, value): """Deserialize JSON to Python.""" return json.loads(value) if value is not None else None class User(Table, metadata=metadata): id = SAColumn(Integer, primary_key=True) ssn = SAColumn(String(255), type_processor=EncryptedString(key='secret')) preferences = SAColumn(String, type_processor=JSONType()) ``` -------------------------------- ### KeyError on Missing Key Dict Access Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/row.md Illustrates dictionary-style access to a non-existent key on a Row object, resulting in a KeyError. Safe access is possible using the `get` method with a default value. ```python row = Row({'id': 1}) print(row['id']) # 1 (works) print(row['missing']) # KeyError: 'missing' # Safe access with get print(row.get('missing', None)) # None ``` -------------------------------- ### Parameter Styles Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/README.md Details on parameter style classes for different databases and how to manage them. ```APIDOC ## ParamStyle Base Class ### Description Abstract base class for parameter styles. ## Concrete Styles ### Description Provides 7 concrete parameter styles for various database connectors. ### Styles - `QMARK`: `?` placeholder. - `NUMERIC`: `:1`, `:2` placeholders. - `NAMED`: `:name` placeholders. - `FORMAT`: `%s` placeholder. - `PYFORMAT`: `%(name)s` placeholder. - `NUMERIC_DOLLAR`: `$1`, `$2` placeholders. - `ESCAPED`: `\?` placeholder. ### Usage Set the default style globally using `t_sql.set_style()` or per-query. ### Parameter Name Sanitization Handles sanitization of parameter names for different styles. ``` -------------------------------- ### Select Data with Custom TypeProcessors Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/type-processor.md Shows how to select data from the `User` table and then manually decrypt and deserialize the results using the custom `EncryptedString` and `JSONType` processors. ```python # Read - manual decryption/deserialization query = User.select().where(User.id == 1) sql, params = query.render() rows = await conn.fetch(sql, *params) # Decrypt and deserialize results = query.map_results(rows) # results[0].ssn = '123-45-6789' (decrypted) # results[0].preferences = {'theme': 'dark', 'language': 'en'} (deserialized) ``` -------------------------------- ### Limit and Offset results with limit() and offset() Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/query-builder.md Use limit() to restrict the number of rows returned and offset() to skip a specified number of rows. These methods are chained to the query builder. ```python Users.select().limit(10).offset(20) # LIMIT 10 OFFSET 20 ``` -------------------------------- ### select() Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/core-tsql.md Build a basic SELECT query with optional filtering and column selection. This function allows for selecting all columns or specific ones, and can filter results by one or more IDs. ```APIDOC ## select() ### Description Build a basic SELECT query with optional filtering and column selection. ### Method select ### Parameters #### Path Parameters - **table** (str) - Required - Table name (validated as identifier via :literal) - **ids** (str | int | list) - Optional - Optional ID or list of IDs to filter on #### Query Parameters - **columns** (list[str]) - Optional - List of column names to select; defaults to * ### Request Example ```python import tsql # Select all columns query = tsql.select('users') sql, params = query.render() # ('SELECT * FROM users', []) # Select specific columns query = tsql.select('users', columns=['name', 'email']) sql, params = query.render() # ('SELECT name, email FROM users', []) # With WHERE filter query = tsql.select('users', ids=123, columns=['name']) sql, params = query.render() # ('SELECT name FROM users WHERE id = ?', [123]) # With list of IDs query = tsql.select('users', ids=[1, 2, 3]) sql, params = query.render() # ('SELECT * FROM users WHERE id in (?, ?, ?)', [1, 2, 3]) ``` ### Response #### Success Response (TSQL object) - **TSQL object** - Represents the SELECT query ``` -------------------------------- ### Row Mutability Example Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/row.md Demonstrates how to mutate a Row object by changing attribute values, adding new key-value pairs, and deleting existing ones. Note that these changes are local to the Row object and do not persist in the database without an explicit save operation. ```python row = Row({'id': 1, 'name': 'Alice'}) # Mutate row.name = 'Bob' row['email'] = 'bob@example.com' del row['age'] # These mutations do not affect the database # You must explicitly save changes back to the database ``` -------------------------------- ### FORMAT Parameter Style Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/parameter-styles.md Uses `%s` placeholders. Compatible with PostgreSQL psycopg2, MySQL MySQLdb, and others. Parameters are passed as a list. ```python query = TSQL(t"SELECT * FROM users WHERE name = {name} AND age = {age}") sql, params = query.render(style=tsql.styles.FORMAT) # SQL: "SELECT * FROM users WHERE name = %s AND age = %s" # Params: ['billy', 30] ``` -------------------------------- ### Formatting Dictionary for UPDATE with as_set Source: https://github.com/nhumrich/t-sql/blob/main/README.md Demonstrates the 'as_set' format specifier for creating the SET clause of a SQL UPDATE statement from a Python dictionary. ```python values = {'name': 'joe', 'email': 'joe@example.com'} sql, params = tsql.render(t"UPDATE users SET {values:as_set} WHERE id='abc123'") # ('UPDATE users SET name = ?, email = ? WHERE id='abc123'', ['joe', 'joe@example.com']) ``` -------------------------------- ### ParamStyle Base Class Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/parameter-styles.md Abstract base class for all parameter styles. It initializes a list or dictionary for collected parameters during rendering. ```python class ParamStyle(ABC): def __init__(self) -> None: self.params: Union[list, dict] # Parameters collected during render @abstractmethod def __iter__(self): ... @staticmethod def _sanitize_param_name(name: str, used_names: set) -> str: ... ``` -------------------------------- ### Basic SELECT Query Source: https://github.com/nhumrich/t-sql/blob/main/README.md Construct a simple SELECT query for specific columns from the Users table. ```python from tsql.query_builder import Table, Column class Users(Table): id: Column username: Column email: Column age: Column # Simple SELECT query = Users.select(Users.id, Users.username) sql, params = query.render() # ('SELECT users.id, users.username FROM users', []) ``` -------------------------------- ### Build INSERT Query Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/core-tsql.md Constructs a basic INSERT query. Provide table name and column values as keyword arguments. ```python import tsql query = tsql.insert('users', id='abc123', name='bob', email='bob@example.com') sql, params = query.render() # ('INSERT INTO users (id, name, email) VALUES (?, ?, ?)', # ['abc123', 'bob', 'bob@example.com']) ``` -------------------------------- ### Build SELECT Query Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/core-tsql.md Constructs a basic SELECT query. Use to select all columns, specific columns, or filter by ID(s). ```python import tsql # Select all columns query = tsql.select('users') sql, params = query.render() # ('SELECT * FROM users', []) # Select specific columns query = tsql.select('users', columns=['name', 'email']) sql, params = query.render() # ('SELECT name, email FROM users', []) # With WHERE filter query = tsql.select('users', ids=123, columns=['name']) sql, params = query.render() # ('SELECT name FROM users WHERE id = ?', [123]) # With list of IDs query = tsql.select('users', ids=[1, 2, 3]) sql, params = query.render() # ('SELECT * FROM users WHERE id in (?, ?, ?)', [1, 2, 3]) ``` -------------------------------- ### Executing Parameterized TSQL Queries Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/core-tsql.md Demonstrates how to use the TSQLQuery type for type-safe query execution with parameterized values. ```python def execute_query(query: TSQLQuery) -> None: sql, params = tsql.render(query) cursor.execute(sql, params) # All these are type-safe: execute_query(t"SELECT * FROM users WHERE id = {id}") execute_query(Users.select()) execute_query(tsql.select('users')) # This is a type error: execute_query("SELECT * FROM users") # Raw string not allowed ``` -------------------------------- ### like(), not_like(), ilike(), not_ilike() Methods Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/query-builder.md Perform string matching using LIKE, NOT LIKE, ILIKE (case-insensitive), and NOT ILIKE conditions with specified patterns. ```APIDOC ## like(), not_like(), ilike(), not_ilike() ### Description Create LIKE conditions with pattern matching. ### Method None (Instance Method) ### Endpoint None (Instance Method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters * **pattern** (str) - Required - The pattern to match against. ### Example ```python Users.select().where(Users.email.like('%@gmail.com')) Users.select().where(Users.username.ilike('%admin%')) # Case-insensitive ``` ``` -------------------------------- ### Column Constructor Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/query-builder.md Initializes a Column object with optional table name, column name, alias, schema, and type processor. ```python def __init__( self, table_name: str | None = None, column_name: str | None = None, alias: str | None = None, schema: str | None = None, type_processor: Any | None = None ) -> None ``` -------------------------------- ### TSQL.render() Method Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/core-tsql.md Converts the template string to parameterized SQL with the specified parameter style. Supports various parameter styles for different database systems. ```APIDOC ## TSQL.render() Method ### Description Converts the template string to parameterized SQL with the specified parameter style. Supports various parameter styles for different database systems. ### Method POST ### Endpoint /render ### Parameters #### Query Parameters - **style** (ParamStyle) - Optional - Parameter style class (QMARK, NUMERIC, NAMED, FORMAT, PYFORMAT, NUMERIC_DOLLAR, ESCAPED). Defaults to the global default_style (QMARK). ### Response #### Success Response (200) - **sql** (string) - The rendered SQL query string with parameter placeholders. - **values** (tuple, list, or dict) - The values to be safely passed to the database, formatted according to the specified style. ### Request Example ```python import tsql name = 'billy' query = TSQL(t"select * from users where name={name}") sql, params = query.render() # ('select * from users where name = ?', ['billy']) # With PostgreSQL style sql, params = query.render(style=tsql.styles.NUMERIC_DOLLAR) # ('select * from users where name = $1', ['billy']) ``` ### Error Handling - **ValueError**: Raised if format spec validation fails (e.g., invalid :literal identifier). ``` -------------------------------- ### to_tsql() and render() Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/query-builder.md Converts the query builder object into a TSQL object or renders it into a SQL string and parameters tuple. ```APIDOC ## to_tsql() and render() ### Description These methods finalize the query construction. `to_tsql()` converts the query builder into a `TSQL` object, while `render()` generates the final SQL string and a list of parameters. ### Method Signatures ```python def to_tsql(self) -> TSQL def render(self, style=None) -> tuple[str, list] ``` ### Returns - **to_tsql()**: Returns a `TSQL` object representing the constructed query. - **render()**: Returns a tuple containing the SQL string and a list of parameters. ### Example ```python # Assuming 'query_builder' is an instance of SelectQueryBuilder tsql_object = query_builder.to_tsql() sql_string, params = query_builder.render() ``` ``` -------------------------------- ### Render TSQL Query with Default Style Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/core-tsql.md Renders a TSQL query template using the default parameter style (QMARK). Use this for general-purpose SQL parameterization. ```python import tsql name = 'billy' query = TSQL(t"select * from users where name={name}") sql, params = query.render() # ('select * from users where name = ?', ['billy']) ``` -------------------------------- ### Basic INSERT Statement Source: https://github.com/nhumrich/t-sql/blob/main/README.md Constructs a basic INSERT statement with specified values. The rendered SQL and parameters are returned. ```python # Basic insert query = Users.insert(id='abc123', username='john', email='john@example.com') sql, params = query.render() # ('INSERT INTO users (id, username, email) VALUES (?, ?, ?)', ['abc123', 'john', 'john@example.com']) ``` -------------------------------- ### insert() Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/core-tsql.md Build a basic INSERT query. This function takes a table name and column-value pairs to construct an INSERT statement. ```APIDOC ## insert() ### Description Build a basic INSERT query. ### Method insert ### Parameters #### Path Parameters - **table** (str) - Required - Table name (validated as identifier via :literal) #### Request Body - **values** (Any) - Required - Column names and values as keyword arguments ### Request Example ```python import tsql query = tsql.insert('users', id='abc123', name='bob', email='bob@example.com') sql, params = query.render() # ('INSERT INTO users (id, name, email) VALUES (?, ?, ?)', # ['abc123', 'bob', 'bob@example.com']) ``` ### Response #### Success Response (TSQL object) - **TSQL object** - Represents the INSERT query ### Raises - `ValueError` — If no values provided ``` -------------------------------- ### Define Columns with SQLAlchemy SAColumn Wrapper Source: https://github.com/nhumrich/t-sql/blob/main/README.md Define columns using SQLAlchemy's SAColumn wrapper for better type checking and integration with Alembic. This is the recommended approach for production environments. ```python from sqlalchemy import MetaData, Integer, String from tsql.query_builder import Table, SAColumn metadata = MetaData() class Users(Table, metadata=metadata): id = SAColumn(Integer, primary_key=True) email = SAColumn(String(255), unique=True, nullable=False) name = SAColumn(String(100)) age = SAColumn(Integer) # Use for alembic target_metadata = metadata # Use for queries query = Users.select().where(Users.age > 18) ``` -------------------------------- ### Safe LIKE Pattern Matching with t-sql Source: https://github.com/nhumrich/t-sql/blob/main/README.md Illustrates safe pattern matching using t-sql's LIKE format specifiers, including automatic escaping of wildcards to prevent injection attacks. ```python # Contains search (%value%) search = "john" sql, params = tsql.render(t"SELECT * FROM users WHERE name ILIKE {search:%like%}") # ('SELECT * FROM users WHERE name ILIKE ? ESCAPE '\'', ['%john%']) # Prefix search (value% - starts with) prefix = "admin" sql, params = tsql.render(t"SELECT * FROM users WHERE username LIKE {prefix:like%}") # ('SELECT * FROM users WHERE username LIKE ? ESCAPE '\'', ['admin%']) # Suffix search (%value - ends with) domain = "@gmail.com" sql, params = tsql.render(t"SELECT * FROM users WHERE email LIKE {domain:%like}") # ('SELECT * FROM users WHERE email LIKE ? ESCAPE '\'', ['%@gmail.com']) ``` -------------------------------- ### Define Table with Custom Name and Schema Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/configuration.md Combine custom table names and schemas for precise table placement and naming. ```python # Both custom name and schema class UserAccount(Table, table_name='accounts', schema='auth'): id: Column name: Column # Renders as: SELECT * FROM auth.accounts ``` -------------------------------- ### render() Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/core-tsql.md Renders any TSQLQuery object (TSQL, Template, or QueryBuilder) into a SQL string with placeholders and a tuple of corresponding parameter values. ```APIDOC ## render() ### Description Render any TSQLQuery (TSQL, Template, or QueryBuilder) to SQL and parameters. ### Method ```python def render(query: TSQLQuery, style: ParamStyle = None) -> RenderedQuery ``` ### Parameters #### Path Parameters - **query** (TSQLQuery) - Required - A safe parameterized query (TSQL, t-string, or QueryBuilder) - **style** (ParamStyle) - Optional - Optional parameter style (defaults to global default_style) ### Returns `RenderedQuery` with `sql` string and `values` ### Raises - `TypeError` — If a raw string is passed (not a t-string) ### Request Example ```python import tsql from tsql.query_builder import Table, Column class Users(Table): id: Column name: Column # Works with t-strings sql1, params1 = tsql.render(t"select * from users where id={user_id}") # Works with QueryBuilder sql2, params2 = tsql.render(Users.select().where(Users.id == user_id)) # Works with helper functions sql3, params3 = tsql.render(tsql.select('users', ids=user_id)) ``` ``` -------------------------------- ### is_null(), is_not_null() Methods Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/api-reference/query-builder.md Create IS NULL and IS NOT NULL conditions to check for the presence or absence of values in a column. ```APIDOC ## is_null(), is_not_null() ### Description Create IS NULL / IS NOT NULL conditions. ### Method None (Instance Method) ### Endpoint None (Instance Method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Example ```python Users.select().where(Users.deleted_at.is_null()) Users.select().where(Users.email.is_not_null()) ``` ``` -------------------------------- ### Quick DELETE Query Source: https://github.com/nhumrich/t-sql/blob/main/README.md Use the delete helper function to generate DELETE statements. You can specify the table name and either an ID value or a custom WHERE clause. ```python # Delete by ID query = tsql.delete('users', id_value='abc123') sql, params = query.render() # ('DELETE FROM users WHERE id = ?', ['abc123']) # Delete with custom WHERE query = tsql.delete('users', where={'age': 18}) sql, params = query.render() # ('DELETE FROM users WHERE age = ?', [18]) ``` -------------------------------- ### Core API Reference Source: https://github.com/nhumrich/t-sql/blob/main/_autodocs/README.md Details on the TSQL class, rendering, parameter handling, format specs, and helper functions. ```APIDOC ## Core TSQL Class and Methods ### Description Provides the main TSQL class for creating SQL queries safely. ### Methods - `TSQL(template: str, **kwargs)`: Constructor for the TSQL class. - `render(**kwargs)`: Renders the TSQL query with provided parameters. ### Parameters - `template` (str): The SQL template string. - `**kwargs`: Parameters for rendering the query. ### Response - `RenderedQuery`: An object containing the rendered SQL and parameters. ## Module Functions ### Description Functions for rendering queries, joining SQL clauses, and setting styles. ### Functions - `render(query: TSQLQuery, **kwargs)`: Renders a TSQL query. - `t_join(clauses: list[str], separator: str = ' ')`: Joins SQL clauses with a separator. - `set_style(style: str)`: Sets the default parameter style globally. ### Parameters - `query` (TSQLQuery): The query to render. - `clauses` (list[str]): A list of SQL clauses to join. - `separator` (str): The separator to use for joining clauses. - `style` (str): The parameter style to set. ### Response - `render`: `RenderedQuery` object. - `t_join`: `str` representing the joined clauses. ## Helper Functions ### Description Functions for constructing common SQL statements like SELECT, INSERT, UPDATE, and DELETE. ### Functions - `select(*columns)`: Creates a SELECT query builder. - `insert(table, **values)`: Creates an INSERT query builder. - `update(table, **values)`: Creates an UPDATE query builder. - `delete(table)`: Creates a DELETE query builder. ### Parameters - `*columns`: Columns to select. - `table`: The table to operate on. - `**values`: Values for INSERT or UPDATE. ### Response - Query builder objects for respective SQL statements. ```