Hi!
In Norm, I'm parsing type section at compile time and generate the db schema from it. Currently, a seq[SqlQuery] is generated with code like this:
proc genTableSchema(dbObjRepr: ObjRepr, dbObjReprs: openArray[ObjRepr]): SqlQuery =
## Generate table schema for an object representation.
var schema: string
schema.add "CREATE TABLE $# (\n" % dbObjRepr.getTable()
var columns: seq[string]
for field in dbObjRepr.fields:
columns.add "\t$#" % genColStmt(field, dbObjReprs)
schema.add columns.join(",\n")
schema.add "\n)"
result = sql schema
proc genTableSchemas*(dbObjReprs: openArray[ObjRepr]): seq[SqlQuery] =
## Generate table schemas for a list of object representations.
for dbObjRepr in dbObjReprs:
result.add genTableSchema(dbObjRepr, dbObjReprs)
genTableSchemas is called in db macro to generate withDb macro and createTables proc inside it.
Everything works fine.
Now, I'd like to have more control over the generated scheme and store it as a table, not a sequence:
proc genTableSchemas2*(dbObjReprs: openArray[ObjRepr]): Table[string, SqlQuery] =
## Generate table schemas for a list of object representations.
for dbObjRepr in dbObjReprs:
result[dbObjRepr.signature.name] = genTableSchema(dbObjRepr, dbObjReprs)
debugEcho result
I get the correct table printed with debugEcho:
{"Edition": CREATE TABLE editions (
id INTEGER NOT NULL PRIMARY KEY,
title TEXT NOT NULL,
bookId INTEGER NOT NULL REFERENCES books (id) ON DELETE CASCADE
), "Publisher": CREATE TABLE publishers (
id INTEGER NOT NULL PRIMARY KEY,
title TEXT NOT NULL UNIQUE,
licensed INTEGER NOT NULL
), "Book": CREATE TABLE books (
id INTEGER NOT NULL PRIMARY KEY,
title TEXT NOT NULL,
authorEmail TEXT NOT NULL REFERENCES users (email) ON DELETE CASCADE,
publisherTitle TEXT NOT NULL REFERENCES publishers (title)
), "User": CREATE TABLE users (
id INTEGER NOT NULL PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
ssn INTEGER,
birthDate INTEGER NOT NULL,
lastLogin INTEGER NOT NULL
)}
BUT when the table is used in macro generation, I get this instead of the generated table:
template genWithDb(connection, user, password, database: string,
tableSchemas, dropTableQueries: openArray[SqlQuery],
tableSchemas2: Table[string, SqlQuery]): untyped {.dirty.} =
## Generate withDb templates.
debugEcho tableSchemas2
outputs:
(data: @[(hcode: 4832918131319623104, key: "Edition", val: CREATE TABLE editions (
id INTEGER NOT NULL PRIMARY KEY,
title TEXT NOT NULL,
bookId INTEGER NOT NULL REFERENCES books (id) ON DELETE CASCADE
)), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: -2021507301530313398, key: "Publisher", val: CREATE TABLE publishers (
id INTEGER NOT NULL PRIMARY KEY,
title TEXT NOT NULL UNIQUE,
licensed INTEGER NOT NULL
)), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 3086448670947841634, key: "Book", val: CREATE TABLE books ( id INTEGER NOT NULL PRIMARY KEY,
title TEXT NOT NULL,
authorEmail TEXT NOT NULL REFERENCES users (email) ON DELETE CASCADE,
publisherTitle TEXT NOT NULL REFERENCES publishers (title)
)), (hcode: 0, key: "", val: ), (hcode: -9076128372746368988, key: "User", val: CREATE TABLE users (
id INTEGER NOT NULL PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
ssn INTEGER,
birthDate INTEGER NOT NULL,
lastLogin INTEGER NOT NULL
)), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: ), (hcode: 0, key: "", val: )], counter: 4)
It looks like instead of the actual table, I'm getting its implementation.
Why is that? How to I get the table I generated?
T
debugEcho is showing you the table repr
Write your own $ proc for type Table[string, SqlQuery] so that
echo tableSchemas2
gives you what you want.
You can't rely on what repr/$ prints at compile-time. Object variant used to display all the branches in the past as well.
seq at compile-time are the same as array. And enums/bool are the same as integers so when crossing some proc boundaries you get an unexpected type:
Just to clarify.
It's not that repr/$ shows the wrong thing, it's that some “high level” types are being implicitly replaced with “lower level” types during compilation. And these replacements effectively disregard arg types in proc signatures.
Like, even if you have an arg of type seq[SqlQuery] in a proc definition, this arg value will have type array[string] when the proc body is executed during compilation, because seq is replaced with array and SqlQuery is replaced with its string repr.
Am I understanding this right?