我正在替换数据库中的一个遗留函数get_data
,它接受一些entity_id
并返回一个refcursor。
我正在编写一个新函数get_data_new
,它使用不同的数据源,但对于相同的输入,输出应该与get_data
相同。
我想用pgtap验证这一点,并在测试中按照如下方式进行验证(_expected
和_actual
是返回游标的名称(:
SELECT schema.get_data('_expected', 123);
SELECT schema.get_data_new('_actual', 123);
SELECT results_eq(
'FETCH ALL FROM _actual',
'FETCH ALL FROM _expected',
'get_data_new should return identical results to the legacy version'
);
这与其他函数的预期一样,但get_data
中的查询恰好返回了一些json
列,这意味着与ERROR: could not identify an equality operator for type json
的比较预计会失败。
我宁愿保留遗留函数,这样就不可能重构到jsonb
。我设想了一种变通方法,即在比较之前转换数据,假设使用SELECT entity_id, json_column::jsonb FROM (FETCH ALL FROM _actual)
之类的方法,但这种特定的尝试显然是无效的。
这里建议的方法是什么?编写一个助手函数,将游标中的数据插入到几个临时表中?我希望有一个我还没有发现的更清洁的解决方案。
使用postgres 11.14,pgtap11
通过创建一个函数在光标上循环并将结果作为表返回,解决了这个问题。不幸的是,这不是一个通用的解决方案——它只适用于具有特定数据的游标。
在这种特定情况下,json_column
可以隐式转换为类型jsonb
,因此这就是所需的全部内容。然而,我们现在可以SELECT * FROM cursor_to_table('_actual')
,这意味着我们可以对结果进行任何需要的转换。
CREATE OR REPLACE FUNCTION cursor_to_table(_cursor refcursor)
RETURNS TABLE (entity_id bigint, json_column jsonb)
AS $func$
BEGIN
LOOP
FETCH _cursor INTO entity_id, json_column
EXIT WHEN NOT FOUND;
RETURN NEXT;
END LOOP;
RETURN;
END
$func$ LANGUAGE plpgsql;
SELECT results_eq(
'SELECT * FROM cursor_to_table(''_actual'')',
'SELECT * FROM cursor_to_table(''_expected'')',
'get_data_new should return identical results to the legacy version'
);