Archive for July 20th, 2006

QuickChecking imperative code

Haskell’s QuickCheck is a very neat tool for automated testing. One specifies properties that one would like a program to satisfy, and generators for test data, usually involving some form of randomisation. QuickCheck then uses the generators to produce test cases and check the properties against them.

The original QuickCheck was designed to test purely functional code only. However, the project I am working on contains a fair amount of imperative code, most of it performing operations on a database. Is it possible to employ QuickCheck for testing this code?

Continue Reading Add comment July 20th, 2006 matthias

Updateable views in PostgreSQL

In one of our projects I needed to do some processing on data stored in a PostgreSQL database. The data contains timestamps but the processing requires time to be represented as seconds since the epoch. What to do?

Generally, date&time processing is major headache. There are just way too many opportunities to get things wrong. In particular, obtaining the right result when the data has been passed through several layers of conversion - database, database driver, o/r layer, programming language - is fraught with difficulty. So I usually try to do the conversions as close to the source as possible. In this instance that means doing the conversion in the database. The quick solution is to construct an appropriate SQL query that does the conversion. A better idea though is to create a view. Here’s what I ended up with:

CREATE VIEW intervals AS
    SELECT t.id as id,
           t.user_id as user_id,
           t.task_id as task_id,
           CAST(EXTRACT(EPOCH FROM t.start_time AT TIME ZONE 'UTC')) as start_time,
           CAST(EXTRACT(EPOCH FROM t.end_time AT TIME ZONE 'UTC') as end_time
    FROM task_time t;

This works all very well as long as all we want to do is retrieve data. What about updates? It turns out that the PostgreSQL rule system allows us to make the above view behave like an ordinary table, with insert, update and delete all working as expected. The documentation of this feature is excellent, and with its help it took me just a few minutes to produce the following:

CREATE RULE intervals_ins AS ON INSERT TO intervals
    DO INSTEAD
    INSERT INTO task_time VALUES(
        DEFAULT,
        NEW.user_id,
        NEW.task_id,
        TIMESTAMP 'epoch' + NEW.start_time * INTERVAL '1 second',
        TIMESTAMP 'epoch' + NEW.end_time * INTERVAL '1 second');

CREATE RULE intervals_upd AS ON UPDATE TO intervals
    DO INSTEAD
    UPDATE task_time
       SET id = NEW.id,
           user_id = NEW.user_id,
           task_id = NEW.task_id,
           start_time = TIMESTAMP 'epoch' + NEW.start_time * INTERVAL '1 second',
           end_time = TIMESTAMP 'epoch' + NEW.end_time * INTERVAL '1 second'
    WHERE id = OLD.id;

CREATE RULE intervals_del AS ON DELETE TO intervals
    DO INSTEAD
    DELETE FROM task_time
    WHERE id = OLD.id;

With the above in place my code simply accesses the intervals table for all operations that previously involved the task_time table, and all time format conversions are done behind the scenes in the database.

Add comment July 20th, 2006 matthias

Calendar

July 2006
M T W T F S S
« Jun   Aug »
 12
3456789
10111213141516
17181920212223
24252627282930
31  

Posts by Month

Posts by Category