From 61849d5e359c7f1232ada845cd3abf63cfea2666 Mon Sep 17 00:00:00 2001 From: Jonathan Bernard Date: Fri, 15 Feb 2019 14:23:44 -0600 Subject: [PATCH] WIP work on macro-based ORM layer. --- api/Makefile | 2 +- api/src/main/nim/personal_measure_apipkg/db | Bin 168688 -> 0 bytes .../main/nim/personal_measure_apipkg/db.nim | 188 ++++++++++-------- .../nim/personal_measure_apipkg/models.nim | 35 ++++ .../20190214122514-initial-schema-up.sql | 2 +- 5 files changed, 145 insertions(+), 82 deletions(-) delete mode 100755 api/src/main/nim/personal_measure_apipkg/db create mode 100644 api/src/main/nim/personal_measure_apipkg/models.nim diff --git a/api/Makefile b/api/Makefile index 0fae820..d09f47b 100644 --- a/api/Makefile +++ b/api/Makefile @@ -22,4 +22,4 @@ delete-postgres-container: rm postgres.container.id connect: - PGPASSWORD=password psql -p 5500 -U postgres -h localhost + PGPASSWORD=password psql -p 5500 -U postgres -h localhost ${DB_NAME} diff --git a/api/src/main/nim/personal_measure_apipkg/db b/api/src/main/nim/personal_measure_apipkg/db deleted file mode 100755 index 10a7594a37f6d8e71b00dc78270c856ffd7c5818..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 168688 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 q?XQq)se`u_kUX05>h diff --git a/api/src/main/nim/personal_measure_apipkg/db.nim b/api/src/main/nim/personal_measure_apipkg/db.nim index 763b1d3..cd90d9e 100644 --- a/api/src/main/nim/personal_measure_apipkg/db.nim +++ b/api/src/main/nim/personal_measure_apipkg/db.nim @@ -1,30 +1,11 @@ import db_postgres, macros, options, postgres, sequtils, strutils, times, timeutils, uuids +import ./models + import nre except toSeq from unicode import capitalize, toLower type - User* = object - id*: UUID - displayName*, email*, hashedPwd*: string - - ApiToken* = object - id*, userId: UUID - name*, hashedToken: string - expires: Option[DateTime] - - Measure* = object - id*, userId*: UUID - slug*, name*, description*, domainUnits*, rangeUnits*: string - domainSource*, rangeSource*: Option[string] - analysis*: seq[string] - - Value* = object - id*, measureId*: UUID - value: int - timestamp: DateTime - extData: string - MutateClauses = object columns*: seq[string] placeholders*: seq[string] @@ -47,66 +28,108 @@ proc dbFormat[T](list: seq[T]): string = proc dbFormat[T](item: T): string = return $item -macro populateMutateClauses(t: typed, newRecord: bool, mc: var MutateClauses): untyped = +proc createParseStmts(t: NimNode, value: string): NimNode = + result = newStmtList() - # Must be working with an object. + if t.typeKind == ntyObject: + if t.getType == UUID.getType: + result.add quote do: + discard parseUUID(`value`) + elif t.getType == DateTime.getType: + result.add quote do: + discard `value`.parseIso8601 + + elif t.typeKind == ntyString: + result.add quote do: + discard `value` + +template walkFieldDefs(t: NimNode, body: untyped) = let tTypeImpl = t.getTypeImpl - if not (tTypeImpl.typeKind == ntyObject): - error $t & " is not an object." + + var nodeToItr: NimNode + if tTypeImpl.typeKind == ntyObject: nodeToItr = tTypeImpl[2] + elif tTypeImpl.typeKind == ntyTypeDesc: nodeToItr = tTypeImpl.getType[1].getType[2] + else: error $t & " is not an object or type desc (it's a " & $tTypeImpl.typeKind & ")." + + for fieldDef {.inject.} in nodeToItr.children: + # ignore AST nodes that are not field definitions + if fieldDef.kind == nnkIdentDefs: + let fieldIdent {.inject.} = fieldDef[0] + let fieldType {.inject.} = fieldDef[1] + body + + elif fieldDef.kind == nnkSym: + let fieldIdent {.inject.} = fieldDef + let fieldType {.inject.} = fieldDef.getType + body + +macro populateMutateClauses(t: typed, newRecord: bool, mc: var MutateClauses): untyped = result = newStmtList() # iterate over all the object's fields - for child in tTypeImpl[2].children: + t.walkFieldDefs: - # ignore AST nodes that are not field definitions - if child.kind == nnkIdentDefs: + # grab the field, it's string name, and it's type + let fieldName = $fieldIdent - # grab the field, it's string name, and it's type - let field = child[0] - let fieldType = child[1] - let fieldName = $field + # we do not update the ID, but we do check: if we're creating a new + # record, we should not have an existing ID + if fieldName == "id": + result.add quote do: + if `newRecord` and not `t`.id.isZero: + raise newException( + AssertionError, + "Trying to create a new record, but the record already has an ID.") - # we do not update the ID, but we do check: if we're creating a new - # record, we should not have an existing ID - if fieldName == "id": - result.add quote do: - if `newRecord` and not `t`.id.isZero: - raise newException( - AssertionError, - "Trying to create a new record, but the record already has an ID.") + # if we're looking at an optional field, add logic to check for presence + elif fieldType.kind == nnkBracketExpr and + fieldType.len > 0 and + fieldType[0] == Option.getType: - # if we're looking at an optional field, add logic to check for presence - elif fieldType.kind == nnkBracketExpr and - fieldType.len > 0 and - fieldType[0] == Option.getType: - - result.add quote do: - `mc`.columns.add(`fieldName`) - if `t`.`field`.isSome: - `mc`.placeholders.add("?") - `mc`.values.add(dbFormat(`t`.`field`.get)) - else: - `mc`.placeholders.add("NULL") - - # otherwise assume we can convert and go ahead. - else: - result.add quote do: - `mc`.columns.add(`fieldName`) + result.add quote do: + `mc`.columns.add(identNameToDb(`fieldName`)) + if `t`.`fieldIdent`.isSome: `mc`.placeholders.add("?") - `mc`.values.add(dbFormat(`t`.`field`)) + `mc`.values.add(dbFormat(`t`.`fieldIdent`.get)) + else: + `mc`.placeholders.add("NULL") + + # otherwise assume we can convert and go ahead. + else: + result.add quote do: + `mc`.columns.add(identNameToDb(`fieldName`)) + `mc`.placeholders.add("?") + `mc`.values.add(dbFormat(`t`.`fieldIdent`)) #echo result.repr # TODO -#macro rowToRecord(recType: untyped, row: seq[string]): untyped -# echo recType +macro rowToModel(modelType: typed): untyped = + result = newStmtList() -macro recordName(rec: typed): string = - return $rec.getTypeInst + #echo modelType.getType[1].getType.treeRepr + modelType.walkFieldDefs: + result.add createParseStmts(fieldType, "") + #[ + result.add quote do: + User( + id: genUUID + #modelType.walkFieldDefs: + ]# -proc tableNameForRecord[T](rec: T): string = - return recordName(rec).replace(UPPERCASE_PATTERN, "$1_$2").toLower() & "s" +macro modelName(model: typed): string = + return $model.getTypeInst + +proc identNameToDb(name: string): string = + return name.replace(UPPERCASE_PATTERN, "$1_$2").toLower() + +proc dbNameToIdent(name: string): string = + let parts = name.split("_") + return @[parts[0]].concat(parts[1..^1].mapIt(capitalize(it))).join("") + +proc tableName[T](rec: T): string = + return modelName(rec).identNameToDb & "s" proc createRecord[T](db: DbConn, rec: T): T = var mc = newMutateClauses() @@ -115,7 +138,7 @@ proc createRecord[T](db: DbConn, rec: T): T = # Confusingly, getRow allows inserts and updates. We use it to get back the ID # we want from the row. let newIdStr = db.getValue(sql( - "INSERT INTO " & tableNameForRecord(rec) & + "INSERT INTO " & tableName(rec) & " (" & mc.columns.join(",") & ") " & " VALUES (" & mc.placeholders.join(",") & ") " & " RETURNING id"), mc.values) @@ -129,7 +152,7 @@ proc updateRecord[T](db: DbConn, rec: T): bool = let setClause = zip(mc.columns, mc.placeholders).mapIt(it.a & " = " it.b).join(',') let numRowsUpdated = db.execAffectedRows(sql( - "UPDATE " & tableNameForRecord(rec) & + "UPDATE " & tableName(rec) & " SET " & setClause & " WHERE id = ? "), mc.values.concat(@[rec.id])) @@ -138,33 +161,38 @@ proc updateRecord[T](db: DbConn, rec: T): bool = # TODO #proc getRecord[T](db: DbConn, UUID id): T = -macro listFieldNames(t: typed): untyped = - let tTypeImpl = t.getTypeImpl +macro listFields(t: typed): untyped = + var fields: seq[tuple[n: string, t: string]] = @[] + t.walkFieldDefs: + if fieldDef.kind == nnkSym: fields.add((n: $fieldIdent, t: fieldType.repr)) + else: fields.add((n: $fieldIdent, t: $fieldType)) - if not (tTypeImpl.typeKind == ntyObject): - error $t & " is not an object." - - var fieldNames: seq[tuple[n: string, t: string]] = @[] - for child in tTypeImpl[2].children: - if child.kind == nnkIdentDefs: - echo $child[1] - fieldNames.add((n: $child[0], t: $child[1])) - - result = newLit(fieldNames) + result = newLit(fields) +# proc create: Typed create methods for specific records proc createUser*(db: DbConn, user: User): User = db.createRecord(user) proc createApiToken*(db: DbConn, token: ApiToken): ApiToken = db.createRecord(token) proc createMeasure*(db: DbConn, measure: Measure): Measure = db.createRecord(measure) proc createValue*(db: DbConn, value: Value): Value = db.createRecord(value) -#[ when isMainModule: + rowToModel(User) + let u = User( displayName: "Bob", email: "bob@bobsco.com", hashedPwd: "test") - echo createRecord(nil, u) +#[ + let db = open("", "", "", "host=localhost port=5500 dbname=personal_measure user=postgres password=password") + for row in db.fastRows(sql"SELECT * FROM users"): + echo $row + echo "----" + rowToModel(User) + + echo "New user:\n\t" & $db.createUser(u) + for row in db.fastRows(sql"SELECT * FROM users"): + echo $row ]# diff --git a/api/src/main/nim/personal_measure_apipkg/models.nim b/api/src/main/nim/personal_measure_apipkg/models.nim new file mode 100644 index 0000000..452aa95 --- /dev/null +++ b/api/src/main/nim/personal_measure_apipkg/models.nim @@ -0,0 +1,35 @@ +import options, times, uuids + +type + User* = object + id*: UUID + displayName*, email*, hashedPwd*: string + + ApiToken* = object + id*, userId*: UUID + name*, hashedToken*: string + expires*: Option[DateTime] + + Measure* = object + id*, userId*: UUID + slug*, name*, description*, domainUnits*, rangeUnits*: string + domainSource*, rangeSource*: Option[string] + analysis*: seq[string] + + Value* = object + id*, measureId*: UUID + value*: int + timestamp*: DateTime + extData*: string + +proc `$`*(u: User): string = + return "User " & ($u.id)[0..6] & " - " & u.displayName & " <" & u.email & ">" + +proc `$`*(tok: ApiToken): string = + return "ApiToken " & ($tok.id)[0..6] & " - " & tok.name + +proc `$`*(m: Measure): string = + return "Measure " & ($m.id)[0..6] & " - " & m.slug + +proc `$`*(v: Value): string = + return "Value " & ($v.id)[0..6] & " - " & ($v.measureId)[0..6] & " = " & $v.value diff --git a/api/src/main/sql/migrations/20190214122514-initial-schema-up.sql b/api/src/main/sql/migrations/20190214122514-initial-schema-up.sql index c4ad3f6..cfb51ce 100644 --- a/api/src/main/sql/migrations/20190214122514-initial-schema-up.sql +++ b/api/src/main/sql/migrations/20190214122514-initial-schema-up.sql @@ -5,7 +5,7 @@ create table "users" ( id uuid default uuid_generate_v4() primary key, display_name varchar not null, email varchar not null, - hashedpwd varchar not null + hashed_pwd varchar not null ); create table "api_tokens" (