digitallyinduced/ihp

Underscore in ID column leads to compile error in code generation

Closed this issue · 0 comments

It seems to me that if the primary key of a table contains an underscore, the code generation outputs code that doesn't compile.

This schema

CREATE TABLE artworks (
    artwork_id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL
);

leads to code generation in Artwork.hs looking like this:

instance QueryBuilder.FilterPrimaryKey "artworks" where
    filterWhereId artwork_id builder =
        builder |> QueryBuilder.filterWhere (#artworkId, artworkId)
    {-# INLINE filterWhereId #-}

Note that the second part of the argument to filterWhere is artworkId, which is different to the argument of the function, which is named artwork_id.
Which results in a compile error

    • Couldn't match type: Id' "artworks"
                     with: Artwork' -> Id' "artworks"

I am not at all well versed with this codebase, but after poking around a bit, I think I might have found the issue.

Within compileFilterPrimaryKeyInstance, there seems to be inconsistent naming of the argument of filterWhereId, especially line 742 looks out of the ordinary, because it doesn't use columnNameToFieldName to convert artwork_id to artworkId, while everything else does, and line 749 expects the argument to be named artworkId.

ihp/IHP/SchemaCompiler.hs

Lines 732 to 749 in 3ebcd95

compileFilterPrimaryKeyInstance :: (?schema :: Schema) => CreateTable -> Text
compileFilterPrimaryKeyInstance table@(CreateTable { name, columns, constraints }) = cs [i|
instance QueryBuilder.FilterPrimaryKey "#{name}" where
filterWhereId #{primaryKeyPattern} builder =
builder |> #{intercalate " |> " primaryKeyFilters}
{-# INLINE filterWhereId #-}
|]
where
primaryKeyPattern = case primaryKeyColumns table of
[] -> error $ "Impossible happened in compilePrimaryKeyInstance. No primary keys found for table " <> cs name <> ". At least one primary key is required."
[c] -> c.name
cs -> "(Id (" <> intercalate ", " (map (columnNameToFieldName . (.name)) cs) <> "))"
primaryKeyFilters :: [Text]
primaryKeyFilters = map primaryKeyFilter $ primaryKeyColumns table
primaryKeyFilter :: Column -> Text
primaryKeyFilter Column {name} = "QueryBuilder.filterWhere (#" <> columnNameToFieldName name <> ", " <> columnNameToFieldName name <> ")"