From 33eff538f8133fdcf90f326497fdbf505da6ca2c Mon Sep 17 00:00:00 2001 From: Jonathan Bernard Date: Tue, 19 Feb 2019 17:50:59 -0600 Subject: [PATCH] DB changes, getXXXBy -> findXXXBy, add PG-specific timestamp parse function. --- .../main/nim/personal_measure_apipkg/db.nim | 8 +++++++ .../nim/personal_measure_apipkg/db_common.nim | 22 ++++++++++--------- .../nim/personal_measure_apipkg/db_util.nim | 21 ++++++++++++++---- 3 files changed, 37 insertions(+), 14 deletions(-) diff --git a/api/src/main/nim/personal_measure_apipkg/db.nim b/api/src/main/nim/personal_measure_apipkg/db.nim index e414a0c..d69a423 100644 --- a/api/src/main/nim/personal_measure_apipkg/db.nim +++ b/api/src/main/nim/personal_measure_apipkg/db.nim @@ -4,6 +4,8 @@ import db_postgres, macros, options, postgres, sequtils, strutils, import ./models import ./db_common +export db_common.NotFoundError + type PMApiDb* = ref object conn: DbConn @@ -15,7 +17,13 @@ proc connect*(connString: string): PMApiDb = generateProcsForModels([User, ApiToken, Measure, Measurement]) generateLookup(User, @["email"]) + generateLookup(ApiToken, @["userId"]) generateLookup(ApiToken, @["hashedToken"]) + generateLookup(Measure, @["userId"]) +generateLookup(Measure, @["userId", "id"]) +generateLookup(Measure, @["userId", "slug"]) + generateLookup(Measurement, @["measureId"]) +generateLookup(Measurement, @["measureId", "id"]) diff --git a/api/src/main/nim/personal_measure_apipkg/db_common.nim b/api/src/main/nim/personal_measure_apipkg/db_common.nim index 4ffa835..8503b8a 100644 --- a/api/src/main/nim/personal_measure_apipkg/db_common.nim +++ b/api/src/main/nim/personal_measure_apipkg/db_common.nim @@ -4,6 +4,8 @@ from unicode import capitalize import ./db_util +type NotFoundError* = object of CatchableError + proc newMutateClauses(): MutateClauses = return MutateClauses( columns: @[], @@ -50,11 +52,11 @@ template getRecord*(db: DbConn, modelType: type, id: UUID): untyped = " WHERE id = ?"), @[$id]) if row.allIt(it.len == 0): - raise newException(KeyError, "no record for id " & $id) + raise newException(NotFoundError, "no record for id " & $id) rowToModel(modelType, row) -template getRecordsWhere*(db: DbConn, modelType: type, whereClause: string, values: varargs[string, dbFormat]): untyped = +template findRecordsWhere*(db: DbConn, modelType: type, whereClause: string, values: varargs[string, dbFormat]): untyped = db.getAllRows(sql( "SELECT " & columnNamesForModel(modelType).join(",") & " FROM " & tableName(modelType) & @@ -67,7 +69,7 @@ template getAllRecords*(db: DbConn, modelType: type): untyped = " FROM " & tableName(modelType))) .mapIt(rowToModel(modelType, it)) -template getRowsBy*(db: DbConn, modelType: type, lookups: seq[tuple[field: string, value: string]]): untyped = +template findRecordsBy*(db: DbConn, modelType: type, lookups: seq[tuple[field: string, value: string]]): untyped = db.getAllRows(sql( "SELECT " & columnNamesForModel(modelType).join(",") & " FROM " & tableName(modelType) & @@ -82,15 +84,15 @@ macro generateProcsForModels*(modelTypes: openarray[type]): untyped = let modelName = $(t.getType[1]) let getName = ident("get" & modelName) let getAllName = ident("getAll" & modelName) - let getWhereName = ident("get" & modelName & "sWhere") + let findWhereName = ident("find" & modelName & "sWhere") let createName = ident("create" & modelName) let updateName = ident("update" & modelName) let deleteName = ident("delete" & modelName) result.add quote do: proc `getName`*(db: PMApiDb, id: UUID): `t` = getRecord(db.conn, `t`, id) proc `getAllName`*(db: PMApiDb): seq[`t`] = getAllRecords(db.conn, `t`) - proc `getWhereName`*(db: PMApiDb, whereClause: string, values: varargs[string, dbFormat]): seq[`t`] = - return getRecordsWhere(db.conn, `t`, whereClause, values) + proc `findWhereName`*(db: PMApiDb, whereClause: string, values: varargs[string, dbFormat]): seq[`t`] = + return findRecordsWhere(db.conn, `t`, whereClause, values) proc `createName`*(db: PMApiDb, rec: `t`): `t` = createRecord(db.conn, rec) proc `updateName`*(db: PMApiDb, rec: `t`): bool = updateRecord(db.conn, rec) proc `deleteName`*(db: PMApiDb, rec: `t`): bool = deleteRecord(db.conn, rec) @@ -98,12 +100,12 @@ macro generateProcsForModels*(modelTypes: openarray[type]): untyped = macro generateLookup*(modelType: type, fields: seq[string]): untyped = let fieldNames = fields[1].mapIt($it) - let procName = ident("get" & $modelType.getType[1] & "sBy" & fieldNames.mapIt(it.capitalize).join("And")) + let procName = ident("find" & $modelType.getType[1] & "sBy" & fieldNames.mapIt(it.capitalize).join("And")) # Create proc skeleton result = quote do: proc `procName`*(db: PMApiDb): seq[`modelType`] = - return getRowsBy(db.conn, `modelType`) + return findRecordsBy(db.conn, `modelType`) var callParams = quote do: @[] @@ -125,12 +127,12 @@ macro generateProcsForFieldLookups*(modelsAndFields: openarray[tuple[t: type, fi var modelType = i[1][0] let fieldNames = i[1][1][1].mapIt($it) - let procName = ident("get" & $modelType & "By" & fieldNames.mapIt(it.capitalize).join("And")) + let procName = ident("find" & $modelType & "sBy" & fieldNames.mapIt(it.capitalize).join("And")) # Create proc skeleton let procDefAST = quote do: proc `procName`*(db: PMApiDb): seq[`modelType`] = - return getRowsBy(db.conn, `modelType`) + return findRecordsBy(db.conn, `modelType`) var callParams = quote do: @[] diff --git a/api/src/main/nim/personal_measure_apipkg/db_util.nim b/api/src/main/nim/personal_measure_apipkg/db_util.nim index 1c415da..01822fa 100644 --- a/api/src/main/nim/personal_measure_apipkg/db_util.nim +++ b/api/src/main/nim/personal_measure_apipkg/db_util.nim @@ -1,6 +1,8 @@ -import macros, options, sequtils, strutils, times, timeutils, unicode, uuids +import json, macros, options, sequtils, strutils, times, timeutils, unicode, + uuids -const underscoreRune = "_".toRunes[0] +const UNDERSCORE_RUNE = "_".toRunes[0] +const PG_TIMESTAMP_FORMAT = "yyyy-MM-dd HH:mm:sszz" type MutateClauses* = object @@ -23,7 +25,7 @@ proc identNameToDb*(name: string): string = if resultRunes.len == 0: resultRunes.add(toLower(cur)) elif isLower(prev) and isUpper(cur): - resultRunes.add(underscoreRune) + resultRunes.add(UNDERSCORE_RUNE) resultRunes.add(toLower(cur)) else: resultRunes.add(toLower(cur)) @@ -120,7 +122,7 @@ proc createParseStmt*(t, value: NimNode): NimNode = result = quote do: parseUUID(`value`) elif t.getType == DateTime.getType: - result = quote do: `value`.parseIso8601 + result = quote do: `value`.parse(PG_TIMESTAMP_FORMAT) elif t.getTypeInst == Option.getType: let innerType = t.getTypeImpl[2][0][0][1] @@ -132,6 +134,14 @@ proc createParseStmt*(t, value: NimNode): NimNode = else: error "Unknown value object type: " & $t.getTypeInst + elif t.typeKind == ntyRef: + + if $t.getTypeInst == "JsonNode": + result = quote do: parseJson(`value`) + + else: + error "Unknown ref type: " & $t.getTypeInst + elif t.typeKind == ntySequence: let innerType = t[1] @@ -145,6 +155,9 @@ proc createParseStmt*(t, value: NimNode): NimNode = elif t.typeKind == ntyInt: result = quote do: parseInt(`value`) + elif t.typeKind == ntyBool: + result = quote do: "true".startsWith(`value`.toLower) + else: error "Unknown value type: " & $t.typeKind