Skip to content

Latest commit

 

History

History

func_as_constraint

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 

Functions as Constraints

July 2024

We've seen that we can use the constraints API to add artifacts to the database. An interesting application is to colocate the definition for custom functions defined as Func:

class HelloWorld(Func):
    function = "hello_world"
    output_field = models.CharField()

    create_function = """\
        CREATE OR REPLACE FUNCTION hello_world()
        RETURNS varchar
        AS $$
        BEGIN
            RETURN 'Hello World!';
        END;
        $$ LANGUAGE plpgsql;
    """


class PlaceholderModel(models.Model):
    class Meta:
        constraints = [
            func_as_constraint(HelloWorld),
        ]

Using a simple function we can create a RawSQL constraint defined in Having Fun with Constraints

def func_as_constraint(func_class):
    sql = textwrap.dedent(func_class.create_function).strip()
    return RawSQL(
        name=func_class.function,
        sql=sql,
        ...
    )

A next step might be to create a reverse for RawSQL that drops the function:

def func_as_constraint(func_class):
    sql = textwrap.dedent(func_class.create_function).strip()
    return RawSQL(
        name=func_class.function,
        sql=sql,
        reverse_sql=f"DROP FUNCTION IF EXISTS {func_class.function}",
    )

We can even go so far as to add a comment to the function if the function class has a docstring:

def func_as_constraint(func_class):
    sql = textwrap.dedent(func_class.create_function).strip()
    if func_class.__doc__:
        comment = psycopg_any_sql.quote(textwrap.dedent(func_class.__doc__).strip())
        if sql[-1] != ";":
            sql += ";"
        sql += f"COMMENT ON FUNCTION {func_class.function} IS {comment};"
    return RawSQL(
        name=func_class.function,
        sql=sql,
        reverse_sql=f"DROP FUNCTION IF EXISTS {func_class.function}",
    )