diff --git a/lib/tooling/schema/discovery.py b/lib/tooling/schema/discovery.py index 571afa6..250de7d 100644 --- a/lib/tooling/schema/discovery.py +++ b/lib/tooling/schema/discovery.py @@ -143,6 +143,14 @@ def get_prop(expr, Type): es = expr.args['properties'].expressions return next((e for e in es if isinstance(e, Type))) +def create_function(expr: Expression, command_e: str) -> Stmt.Op: + match = re.search(r"FUNCTION\s+(?:(\w+)\.)?(\w+)\s*\(", command_e, re.IGNORECASE) + if not match: + raise TypeError(f'unknown {repr(e)}') + s_name = match.group(1) if match.group(1) else None + t_name = match.group(2) + return Stmt.CreateFunction(expr, s_name, t_name) + def expr_as_op(expr: Expression) -> Optional[Stmt.Op]: match expr: case sql_expr.Create(kind="SCHEMA", this=schema_def): @@ -171,12 +179,9 @@ def expr_as_op(expr: Expression) -> Optional[Stmt.Op]: case sql_expr.Command(this="CREATE", expression=e): match re.findall(f'\w+', e.lower()): case ['function', *_]: - match = re.search(r"FUNCTION\s+(?:(\w+)\.)?(\w+)\s*\(", e, re.IGNORECASE) - if not match: - raise TypeError(f'unknown {repr(e)}') - s_name = match.group(1) if match.group(1) else None - t_name = match.group(2) - return Stmt.CreateFunction(expr, s_name, t_name) + return create_function(expr, e) + case ['or', 'replace', 'function', *_]: + return create_function(expr, e) case ['type', s_name, t_name, 'as', *_]: return Stmt.CreateType(expr, s_name, t_name) case ['type', t_name, 'as', *_]: diff --git a/lib/tooling/schema/tests/test_discovery.py b/lib/tooling/schema/tests/test_discovery.py index 161c113..d15e61b 100644 --- a/lib/tooling/schema/tests/test_discovery.py +++ b/lib/tooling/schema/tests/test_discovery.py @@ -28,7 +28,7 @@ def test_expr_as_op(snapshot, sql: str): operations = sql_as_operations(sql) snapshot.assert_match(pformat(operations, width=150), 'schema') -def test_function(): +def test_create_function(): sql = \ "CREATE FUNCTION a.c(input TEXT) RETURNS TEXT $$ BEGIN RETURN ''; END; $$ LANGUAGE plpgsql" schema = sql_as_operations(sql) @@ -36,6 +36,14 @@ def test_function(): assert create_function.schema_name == 'a' assert create_function.type_name == 'c' +def test_create_or_replace_function(): + sql = \ + "CREATE OR REPLACE FUNCTION a.c(input TEXT) RETURNS TEXT $$ BEGIN RETURN ''; END; $$ LANGUAGE plpgsql" + schema = sql_as_operations(sql) + create_function = next(o for o in schema.operations) + assert create_function.schema_name == 'a' + assert create_function.type_name == 'c' + def test_schema_for_parition(): sql = \ "CREATE TABLE a.c PARTITION OF b.a FOR VALUES WITH (MODULUS 8, REMAINDER 0)" diff --git a/sql/nsw_gnb/schema/001_APPLY_init.sql b/sql/nsw_gnb/schema/001_APPLY_init.sql index d6e2615..6230523 100644 --- a/sql/nsw_gnb/schema/001_APPLY_init.sql +++ b/sql/nsw_gnb/schema/001_APPLY_init.sql @@ -66,3 +66,9 @@ SELECT DISTINCT ON (property_id, strata_lot_number) LEFT JOIN nsw_gnb.street USING (street_id, locality_id) LEFT JOIN nsw_gnb.locality USING (locality_id); +CREATE OR REPLACE FUNCTION nsw_gnb.addr_str(a nsw_gnb.full_property_address) RETURNS TEXT +LANGUAGE SQL IMMUTABLE PARALLEL SAFE AS $$ + SELECT (a.street_number || ' ' || a.street_name || ' ' || a.locality_name || ' ' || a.postcode); +$$; + +