fastflowtransform.stdlib¶
sql_safe_cast ¶
sql_safe_cast(expr, target_type, *, default=None, engine=None)
Engine-aware “safe cast” builder.
Semantics by engine¶
DuckDB: TRY_CAST(expr AS type) BigQuery: SAFE_CAST(expr AS type) Spark (3.x+): TRY_CAST(expr AS type) Snowflake: CAST(expr AS type) # TRY_CAST(FLOAT -> NUMBER) is not supported Postgres / Redshift / Generic: CAST(expr AS type)
If default is provided, it is treated as a raw SQL snippet and
wrapped via COALESCE(…, default).
Source code in src/fastflowtransform/stdlib/casts.py
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | |
sql_date_add ¶
sql_date_add(expr, part, amount, *, engine=None)
Build an engine-aware date / timestamp addition expression.
Parameters¶
expr: SQL expression / column reference to add to. part: "day", "month", "year", ... (engine-specific support may vary). amount: Integer offset (positive or negative). engine: Engine key/hint ("duckdb", "postgres", "bigquery", "snowflake", "spark", ...).
Examples (golden SQL)¶
DuckDB / Postgres / Redshift / Generic: sql_date_add("order_date", "day", 3, engine="duckdb") -> "CAST(order_date AS TIMESTAMP) + INTERVAL '3 day'"
Snowflake
sql_date_add("created_at", "month", 1, engine="snowflake") -> "DATEADD(MONTH, 1, created_at)"
BigQuery
sql_date_add("order_date", "day", -7, engine="bigquery") -> "DATE_ADD(order_date, INTERVAL -7 DAY)"
Source code in src/fastflowtransform/stdlib/dates.py
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | |
sql_date_trunc ¶
sql_date_trunc(expr, part='day', *, engine=None)
Build an engine-aware DATE_TRUNC expression.
Parameters¶
expr: SQL expression / column reference, e.g. "order_date" or "CAST(ts AS TIMESTAMP)". part: Date part like "day", "month", "year", "week", ... engine: Engine key/hint (e.g. "duckdb", "postgres", "bigquery"). If omitted, "generic" semantics are used.
Examples (golden SQL)¶
DuckDB / Postgres / Redshift / Snowflake / Spark: sql_date_trunc("order_date", "day", engine="duckdb") -> "date_trunc('day', order_date)"
BigQuery
sql_date_trunc("order_date", "day", engine="bigquery") -> "DATE_TRUNC(order_date, DAY)"
Generic
sql_date_trunc("created_at", "month") -> "date_trunc('month', created_at)"
Source code in src/fastflowtransform/stdlib/dates.py
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | |
engine_family ¶
engine_family(engine)
Return a broad engine family key.
For now this is identical to normalize_engine(), but having a separate function makes it easy to distinguish “exact engine” vs “family” later.
Source code in src/fastflowtransform/stdlib/engine.py
54 55 56 57 58 59 60 61 | |
is_engine ¶
is_engine(engine, *candidates)
Convenience helper: check if engine matches any of the given candidates.
Examples¶
is_engine("duckdb", "duckdb", "postgres") True is_engine("bigquery", "duckdb", "postgres") False
Source code in src/fastflowtransform/stdlib/engine.py
64 65 66 67 68 69 70 71 72 73 74 75 76 77 | |
normalize_engine ¶
normalize_engine(engine)
Normalize an engine string into a canonical key.
- None / empty → "generic"
- Known aliases → canonical (e.g. "postgresql" → "postgres")
- Other values → lower-case as-is
Examples¶
normalize_engine("Postgres") 'postgres' normalize_engine("databricks_spark") 'spark' normalize_engine(None) 'generic'
Source code in src/fastflowtransform/stdlib/engine.py
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | |
sql_partition_filter ¶
sql_partition_filter(column, start=None, end=None, *, engine=None)
Build a WHERE predicate for a range of partition values.
Semantics
- start only → col >=
- end only → col <=
- both → col BETWEEN
AND - neither → "1=1" (no-op filter)
start and end are Python values and will be converted with sql_literal(),
so you can safely pass datetime.date, datetime.datetime, strings, ints, etc.
Parameters¶
column: Partition column name / expression, e.g. "ds" or "DATE(event_time)". start, end: Python values interpreted as partition bounds. engine: Currently unused but accepted so callers can pass it consistently.
Examples (golden SQL)¶
Daily date partition: sql_partition_filter("ds", date(2024, 1, 1), date(2024, 1, 31)) -> "ds BETWEEN '2024-01-01' AND '2024-01-31'"
Open interval
sql_partition_filter("ds", start=date(2024, 1, 1), end=None) -> "ds >= '2024-01-01'"
Source code in src/fastflowtransform/stdlib/partitions.py
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | |
sql_partition_in ¶
sql_partition_in(column, values, *, engine=None)
Build an IN() predicate for a set of partition values.
- Empty values → "1=0" (guaranteed false, useful for guard rails).
- Non-empty → col IN (
, , ...)
Examples (golden SQL)¶
Daily partitions: sql_partition_in("ds", [date(2024, 1, 1), date(2024, 1, 2)]) -> "ds IN ('2024-01-01', '2024-01-02')"
String partitions
sql_partition_in("region", ["EU", "US"]) -> "region IN ('EU', 'US')"
Source code in src/fastflowtransform/stdlib/partitions.py
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | |
sql_literal ¶
sql_literal(value)
Convert a Python value into a SQL literal string.
- None -> "NULL"
- bool -> "TRUE"/"FALSE"
- int/float -> "123" (no quotes)
- str -> quoted with single quotes and escaped
- other -> JSON-dumped and treated as a string literal
Source code in src/fastflowtransform/stdlib/sql.py
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | |
register_jinja ¶
register_jinja(env, *, engine_resolver=None, engine=None)
Register all stdlib helpers into a Jinja Environment.
Either pass
- engine_resolver: a callable returning the current engine key, OR
- engine: a fixed engine key string.
Example from core
from fastflowtransform import stdlib as ff_stdlib ff_stdlib.register_jinja(env, engine_resolver=self._current_engine)
Source code in src/fastflowtransform/stdlib/__init__.py
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | |