Home > OS >  Norm - Querying entries within generics causes type mismatch compilation error
Norm - Querying entries within generics causes type mismatch compilation error

Time:04-08

I write a web application in the nim programming language and use norm as my ORM.

There I follow the standard repository pattern, meaning you have associated with a given URL a controller which calls services that contain business logic on what should happen on the database, which call repositories to perform the actual queries.

I have a generic repository that performs various very repetitive queries for me. The following query for example fetches a list of all entries related to a "Campaign" that has a specific name:

import norm/[model, sqlite]
import <path to the file with the definitions of the used Model and newModel>


proc getCampaignList*[M: Model](connection: DbConn, campaignName: string, modelType: typedesc[M]): seq[M] =
    ##[ Retrieves all rows/entries for a campaign with the given name and 
    returns them as Model M. 
    
    ``campaignName`` must be exactly equal to the name of the targetted campaign,
    the comparison is case-sensitive.]##
    mixin newModel

    var entries: seq[M] = @[]
    entries.add(newModel(M))
    
    connection.select(entries, "campaign_id.name = ?", campaignName)

    result = entries

This works fine if I call the proc directly. I have, however, also been writing generic procs that build controller-procs for me as my application is very CRUD heavy and thus very repetitive. So I have a genericService and more.

When used within these several layers of generics, the proc breaks mysteriously:

type mismatch: got <DbConn, seq[DiaryEntryRead], string, DbValue>
but expected one of:
...
<Unnecessary examples>
...
proc select[T: Model](dbConn; objs: var seq[T]; cond: string;
                      params: varargs[DbValue, dbValue])
  first type mismatch at position: 4
  required type for params: varargs[DbValue]
  but expression 'dbValue(campaignName)' is of type: DbValue

expression: select(connection, entries, "campaign_id.name = ?", dbValue(campaignName))

I'm not sure why this suddenly happens when it worked perfectly fine before. What could my issue be?

CodePudding user response:

The issue appears to be somewhere in the interaction between nim generics and converting types properly into varargs (Thanks to "Solitude" and "Rika" from nim's discord server for the help!). I haven't dug any deeper into it as to why this happens, but at very least it's fixable.

The parameters you throw in as the parameters at position 4 and onwards can just be converted into DbValue and stuffed into an array or seq. Below the way I solved this and "foolproofed" the proc (I used an array because why use a seq when the number of parameters is static and you know it ahead of time):

proc getCampaignList*[M: Model](connection: MyDbConn, campaignName: string, modelType: typedesc[M]): seq[M] =
    ##[ Retrieves all rows/entries of a campaign with the given name and 
    returns them as Model M. 
    
    ``campaignName`` must be exactly equal to the name of the targetted campaign,
    the comparison is case-sensitive.]##
    mixin newModel

    var entries: seq[M] = @[]
    entries.add(newModel(M))
    
    let queryParams: array[1, DbValue] = [campaignName.dbValue()]
    connection.select(entries, "campaign_id.name = ?", queryParams)

    result = entries
  • Related