Files
pyrseas/tests/dbobject/test_cast.py
T
2025-05-20 09:24:29 -04:00

172 lines
7.5 KiB
Python

# -*- coding: utf-8 -*-
"""Test casts"""
import pytest
from pyrseas.testutils import DatabaseToMapTestCase
from pyrseas.testutils import InputMapToSqlTestCase, fix_indent
SOURCE = "SELECT CAST($1::int AS boolean)"
CREATE_FUNC = "CREATE FUNCTION int2_bool(smallint) RETURNS boolean " \
"LANGUAGE sql IMMUTABLE AS $_$%s$_$" % SOURCE
CREATE_DOMAIN = "CREATE DOMAIN d1 AS integer"
CREATE_STMT1 = "CREATE CAST (smallint AS boolean) WITH FUNCTION " \
"sd.int2_bool(smallint)"
CREATE_STMT3 = "CREATE CAST (d1 AS integer) WITH INOUT AS IMPLICIT"
DROP_STMT = "DROP CAST IF EXISTS (smallint AS boolean)"
COMMENT_STMT = "COMMENT ON CAST (smallint AS boolean) IS 'Test cast 1'"
class CastToMapTestCase(DatabaseToMapTestCase):
"""Test mapping of existing casts"""
def test_map_cast_function(self):
"Map a cast with a function"
dbmap = self.to_map([CREATE_FUNC, CREATE_STMT1], superuser=True)
expmap = {'function': 'sd.int2_bool(smallint)', 'context': 'explicit',
'method': 'function'}
assert dbmap['cast (smallint as boolean)'] == expmap
def test_map_cast_inout(self):
"Map a cast with INOUT"
dbmap = self.to_map([CREATE_DOMAIN, CREATE_STMT3])
expmap = {'context': 'implicit', 'method': 'inout',
'depends_on': ['domain d1']}
assert dbmap['cast (sd.d1 as integer)'] == expmap
def test_map_cast_comment(self):
"Map a cast comment"
dbmap = self.to_map([CREATE_FUNC, CREATE_STMT1, COMMENT_STMT],
superuser=True)
assert dbmap['cast (smallint as boolean)']['description'] == \
'Test cast 1'
class CastToSqlTestCase(InputMapToSqlTestCase):
"""Test SQL generation from input casts"""
def test_create_cast_function(self):
"Create a cast with a function"
stmts = [DROP_STMT, CREATE_FUNC]
inmap = self.std_map()
inmap.update({'cast (smallint as boolean)': {
'function': 'sd.int2_bool(smallint)', 'context': 'explicit',
'method': 'function'}})
sql = self.to_sql(inmap, stmts)
assert fix_indent(sql[0]) == CREATE_STMT1
def test_create_cast_inout(self):
"Create a cast with INOUT"
stmts = [CREATE_DOMAIN, "DROP CAST IF EXISTS (d1 AS integer)"]
inmap = self.std_map()
inmap.update({'cast (d1 as integer)': {
'context': 'implicit', 'method': 'inout'}})
inmap['schema sd'].update({'domain d1': {'type': 'integer'}})
sql = self.to_sql(inmap, stmts)
assert fix_indent(sql[0]) == CREATE_STMT3
def test_create_cast_schema(self):
"Create a cast using a type/domain in a non-default schema"
stmts = ["CREATE SCHEMA s1", "CREATE DOMAIN s1.d1 AS integer",
"DROP CAST IF EXISTS (integer AS s1.d1)"]
inmap = self.std_map()
inmap.update({'cast (integer as s1.d1)': {
'context': 'assignment', 'method': 'binary coercible'}})
inmap.update({'schema s1': {'domain d1': {'type': 'integer'}}})
sql = self.to_sql(inmap, stmts)
assert fix_indent(sql[0]) == "CREATE CAST (integer AS s1.d1) " \
"WITHOUT FUNCTION AS ASSIGNMENT"
def test_bad_cast_map(self):
"Error creating a cast with a bad map"
inmap = self.std_map()
inmap.update({'(smallint as boolean)': {
'function': 'int2_bool(smallint)', 'context': 'explicit',
'method': 'function'}})
with pytest.raises(KeyError):
self.to_sql(inmap)
def test_drop_cast(self):
"Drop an existing cast"
stmts = [DROP_STMT, CREATE_FUNC, CREATE_STMT1]
sql = self.to_sql(self.std_map(), stmts, superuser=True)
assert sql[0] == "DROP CAST (smallint AS boolean)"
def test_cast_with_comment(self):
"Create a cast with a comment"
inmap = self.std_map()
inmap.update({'cast (smallint as boolean)': {
'description': 'Test cast 1', 'function': 'sd.int2_bool(smallint)',
'context': 'explicit', 'method': 'function'}})
inmap['schema sd'].update({'function int2_bool(smallint)': {
'returns': 'boolean', 'language': 'sql', 'immutable': True,
'source': SOURCE}})
sql = self.to_sql(inmap, [DROP_STMT])
# sql[0:1] -> SET, CREATE FUNCTION
assert fix_indent(sql[2]) == CREATE_STMT1
assert sql[3] == COMMENT_STMT
def test_comment_on_cast(self):
"Create a comment for an existing cast"
stmts = [DROP_STMT, CREATE_FUNC, CREATE_STMT1]
inmap = self.std_map()
inmap.update({'cast (smallint as boolean)': {
'description': 'Test cast 1', 'function': 'int2_bool(smallint)',
'context': 'explicit', 'method': 'function'}})
inmap['schema sd'].update({'function int2_bool(smallint)': {
'returns': 'boolean', 'language': 'sql', 'immutable': True,
'source': SOURCE}})
sql = self.to_sql(inmap, stmts, superuser=True)
assert sql == [COMMENT_STMT]
def test_drop_cast_comment(self):
"Drop a comment on an existing cast"
stmts = [DROP_STMT, CREATE_FUNC, CREATE_STMT1, COMMENT_STMT]
inmap = self.std_map()
inmap.update({'cast (smallint as boolean)': {
'function': 'int2_bool(smallint)', 'context': 'explicit',
'method': 'function'}})
inmap['schema sd'].update({'function int2_bool(smallint)': {
'returns': 'boolean', 'language': 'sql', 'immutable': True,
'source': SOURCE}})
assert self.to_sql(inmap, stmts, superuser=True) == \
["COMMENT ON CAST (smallint AS boolean) IS NULL"]
def test_change_cast_comment(self):
"Change existing comment on a cast"
stmts = [DROP_STMT, CREATE_FUNC, CREATE_STMT1, COMMENT_STMT]
inmap = self.std_map()
inmap.update({'cast (smallint as boolean)': {
'description': 'Changed cast 1', 'function': 'int2_bool(smallint)',
'context': 'explicit', 'method': 'function'}})
inmap['schema sd'].update({'function int2_bool(smallint)': {
'returns': 'boolean', 'language': 'sql', 'immutable': True,
'source': SOURCE}})
assert self.to_sql(inmap, stmts, superuser=True) == \
["COMMENT ON CAST (smallint AS boolean) IS 'Changed cast 1'"]
def test_cast_function_view_depends(self):
"Cast that depends on a function that depends on a view. See #86"
stmts = ["CREATE TABLE t1 (id integer)"]
inmap = self.std_map()
inmap.update({'cast (sd.v1 as sd.t1)': {
'context': 'explicit', 'function': 'sd.v1_to_t1(sd.v1)',
'method': 'function'}})
inmap['schema sd'].update({
'function v1_to_t1(sd.v1)': {
'returns': 'sd.t1', 'language': 'plpgsql',
'source': "\nDECLARE o sd.t1;\nBEGIN o:= ROW($1.id)::t1;\n"
"RETURN o;\nEND"},
'table t1': {'columns': [{'id': {'type': 'integer'}}]},
'view v1': {'definition': " SELECT t1.id\n FROM sd.t1;",
'depends_on': ['table t1']}})
sql = self.to_sql(inmap, stmts)
assert len(sql) == 3
assert fix_indent(sql[0]) == \
"CREATE VIEW sd.v1 AS SELECT t1.id FROM sd.t1"
assert fix_indent(sql[1]) == "CREATE FUNCTION sd.v1_to_t1(sd.v1) " \
"RETURNS sd.t1 LANGUAGE plpgsql AS $_$\nDECLARE o sd.t1;\n" \
"BEGIN o:= ROW($1.id)::t1;\nRETURN o;\nEND$_$"
assert fix_indent(sql[2]) == "CREATE CAST (sd.v1 AS sd.t1) WITH " \
"FUNCTION sd.v1_to_t1(sd.v1)"