Changeset 14

Show
Ignore:
Timestamp:
08/25/08 18:53:24 (4 years ago)
Author:
fumanchu
Message:

New 'global' function to fake passing records to functions. Needs tests. Also added an assert_values function (also needs tests), and made assert_rows take FROM clauses.

Location:
trunk/epic
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • trunk/epic/epic.sql

    r13 r14  
    211211 
    212212 
     213-------------------------------- global records -------------------------------- 
     214 
     215 
     216CREATE OR REPLACE FUNCTION _ensure_globals() RETURNS boolean AS $$ 
     217BEGIN 
     218  SET client_min_messages = warning; 
     219   
     220  BEGIN 
     221    CREATE SEQUENCE _global_ids; 
     222  EXCEPTION WHEN duplicate_table THEN 
     223    NULL; 
     224  END; 
     225   
     226  RETURN TRUE; 
     227END; 
     228$$ LANGUAGE plpgsql; 
     229SELECT * FROM _ensure_globals(); 
     230DROP FUNCTION _ensure_globals(); 
     231 
     232 
     233CREATE OR REPLACE FUNCTION global(call text) RETURNS record AS $$ 
     234-- Stores the given call's output in a TEMP table, and returns it as a record. 
     235--  
     236-- 'call' can be any table, view, or procedure that returns records. 
     237--  
     238-- The returned record includes the following additional attributes: 
     239--   * tablename (text): The complete name of the TEMP table. This allows you 
     240--       to pass my_record_var.tablename to functions that take a 'call text' 
     241--       argument, such as assert_column, assert_values, and assert_empty 
     242--       (since no procedural languages support passing records as args). 
     243DECLARE 
     244  tablename      text; 
     245  result         record; 
     246BEGIN 
     247  tablename := '_global_' || nextval('_global_ids'); 
     248  EXECUTE 'CREATE TEMP TABLE ' || tablename || ' AS SELECT * FROM ' || call; 
     249  EXECUTE 'SELECT ''' || tablename || '''::text AS tablename, * FROM ' || tablename INTO result; 
     250  RETURN result; 
     251END; 
     252$$ LANGUAGE plpgsql; 
     253 
     254 
     255CREATE OR REPLACE FUNCTION attributes(tablename text) RETURNS SETOF pg_attribute AS $$ 
     256DECLARE 
     257  rec      record; 
     258BEGIN 
     259  FOR rec IN 
     260    SELECT * FROM pg_attribute 
     261    WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = tablename) 
     262    -- Exclude system columns 
     263    AND attnum >= 1 
     264  LOOP 
     265    RETURN NEXT rec; 
     266  END LOOP; 
     267END; 
     268$$ LANGUAGE plpgsql; 
     269 
     270 
    213271------------------------------ Runners ------------------------------ 
    214272 
     
    484542-- Example: 
    485543-- 
    486 --    PERFORM test.assert_raises('get_transaction_by_id("a")', 'Bad argument', NULL); 
     544--    PERFORM test.assert_raises('get_transaction_by_id(''a'')', 'Bad argument', NULL); 
    487545-- 
    488546-- If errm or state are NULL, that value will not be tested. This allows 
     
    527585-- 
    528586-- Both arguments should be SELECT statements yielding a single row or a set of rows. 
    529 -- It is common for the 'expected' arg to be sans a FROM clause, and simply SELECT values. 
     587-- Either may also be any table, view, or procedure call that returns records. 
     588-- It is also common for the 'expected' arg to be sans a FROM clause, and simply SELECT values. 
    530589-- Neither source nor expected need to be sorted. Either may include a trailing semicolon. 
    531590-- 
     
    536595DECLARE 
    537596  rec     record; 
    538 BEGIN 
    539   FOR rec in EXECUTE rtrim(source, ';') || ' EXCEPT ' || rtrim(expected, ';') 
     597  s       text; 
     598  e       text; 
     599BEGIN 
     600  s := rtrim(source, ';'); 
     601  IF NOT s ILIKE 'SELECT%' THEN 
     602    s := 'SELECT * FROM ' || s; 
     603  END IF; 
     604   
     605  e := rtrim(expected, ';'); 
     606  IF NOT e ILIKE 'SELECT%' THEN 
     607    e := 'SELECT * FROM ' || e; 
     608  END IF; 
     609   
     610  FOR rec in EXECUTE s || ' EXCEPT ' || e 
    540611  LOOP 
    541612    RAISE EXCEPTION 'Record: % from: % not found in: %', rec, source, expected; 
    542613  END LOOP; 
    543614   
    544   FOR rec in EXECUTE rtrim(expected, ';') || ' EXCEPT ' || rtrim(source, ';') 
     615  FOR rec in EXECUTE e || ' EXCEPT ' || s 
    545616  LOOP 
    546617    RAISE EXCEPTION 'Record: % from: % not found in: %', rec, expected, source; 
     
    634705 
    635706 
     707CREATE OR REPLACE FUNCTION test.assert_values(call_1 text, call_2 text, columns text) RETURNS VOID AS $$ 
     708-- Raises an exception if SELECT columns FROM call_1 != SELECT columns FROM call_2. 
     709-- 
     710-- Example: 
     711--    row_1 := obj('get_favorite_user_ids(' || user_id || ')') 
     712--    PERFORM test.assert_equal(row_1.object, 'users WHERE user_id = 355', 'last_name'); 
     713-- 
     714BEGIN 
     715  PERFORM test.assert_rows( 
     716    'SELECT ' || columns || ' FROM ' || call_1, 
     717    'SELECT ' || columns || ' FROM ' || call_2 
     718    ); 
     719END; 
     720$$ LANGUAGE plpgsql; 
     721 
     722 
    636723CREATE OR REPLACE FUNCTION test.assert_empty(tablenames text[]) RETURNS VOID AS $$ 
    637724-- Raises an exception if the given tables have any rows. 
  • trunk/epic/test/test_asserts.sql

    r13 r14  
    315315    'SELECT tablename FROM pg_tables;', 
    316316    'SELECT relname FROM pg_class where relkind = ''r'''); 
     317  -- SELECT-less argument 
     318  PERFORM test.assert_rows( 
     319    'SELECT adrelid, adnum, adbin, adsrc FROM pg_attrdef', 
     320    'pg_attrdef'); 
    317321   
    318322  -- ...and an assertion that should fail 
     
    320324  BEGIN 
    321325    PERFORM test.assert_rows( 
    322       'SELECT * FROM generate_series(1, 10)',  
     326      'generate_series(1, 10)',  
    323327      'SELECT * FROM generate_series(1, 5)'); 
    324328  EXCEPTION WHEN OTHERS THEN 
    325329    failed := true; 
    326     IF SQLERRM = 'Record: (6) from: SELECT * FROM generate_series(1, 10) not found in: SELECT * FROM generate_series(1, 5)' THEN 
     330    IF SQLERRM = 'Record: (6) from: generate_series(1, 10) not found in: SELECT * FROM generate_series(1, 5)' THEN 
    327331      NULL; 
    328332    ELSE