diff --git a/.gitignore b/.gitignore index ac8b1240..44a9bf14 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ /index.js /index.d.ts /yarn-error.log +package-lock.json diff --git a/.husky/.gitignore b/.husky/.gitignore deleted file mode 100644 index 31354ec1..00000000 --- a/.husky/.gitignore +++ /dev/null @@ -1 +0,0 @@ -_ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3e23f093..f02562fb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -264,7 +264,7 @@ Versioned Tables are unsuitable. - Create a new module in `src/db/models` with the same name that the table will have. Inside this module: - - Pick an appropriate function to base your model definition om, i.e: + - Pick an appropriate function to base your model definition on, i.e: - `defineIDModel`: to describe a table that was previously defined using sequelize, and that has a unique ID field diff --git a/package.json b/package.json index 51419487..675cfde8 100644 --- a/package.json +++ b/package.json @@ -21,12 +21,12 @@ "devDependencies": { "@types/lodash": "^4.14.170", "@types/node": "^14.0.5", - "@unocha/hpc-repo-tools": "^0.1.1", - "eslint": "^7.27.0", - "husky": "^6.0.0", + "@unocha/hpc-repo-tools": "^0.1.4", + "eslint": "^7.32.0", + "husky": "^7.0.2", "lint-staged": "^11.0.0", "prettier": "2.3.2", - "typescript": "^4.2.3" + "typescript": "^4.3.5" }, "lint-staged": { "*.{ts,js}": [ diff --git a/src/db/index.ts b/src/db/index.ts index a75af9a8..391d0cbd 100644 --- a/src/db/index.ts +++ b/src/db/index.ts @@ -1,6 +1,6 @@ import Knex = require('knex'); -import attachmentVersion from './models/attachmentVersion'; import attachment from './models/attachment'; +import attachmentVersion from './models/attachmentVersion'; import authGrant from './models/authGrant'; import authGrantee from './models/authGrantee'; import authGrantLog from './models/authGrantLog'; @@ -10,6 +10,7 @@ import form from './models/form'; import governingEntity from './models/governingEntity'; import operation from './models/operation'; import operationCluster from './models/operationCluster'; +import participant from './models/participant'; import reportingWindow from './models/reportingWindow'; import reportingWindowAssignment from './models/reportingWindowAssignment'; @@ -25,6 +26,7 @@ export default (conn: Knex) => ({ governingEntity: governingEntity(conn), operation: operation(conn), operationCluster: operationCluster(conn), + participant: participant(conn), reportingWindow: reportingWindow(conn), reportingWindowAssignment: reportingWindowAssignment(conn), }); diff --git a/src/db/models/authGrant.ts b/src/db/models/authGrant.ts index f932618a..92ed093b 100644 --- a/src/db/models/authGrant.ts +++ b/src/db/models/authGrant.ts @@ -39,7 +39,7 @@ const authGrantModel = (conn: Knex) => { // expose wrappers that require that a user is specified, // and transactionally create logs - const create = async ( + const create = ( data: UserData, actor: ParticipantId, date = new Date() @@ -61,10 +61,7 @@ const authGrantModel = (conn: Knex) => { }); }; - const update = async ( - data: UserData, - actor: ParticipantId - ): Promise => { + const update = (data: UserData, actor: ParticipantId): Promise => { return conn.transaction(async (trx) => { await authGrantLog.create( { diff --git a/src/db/models/form.ts b/src/db/models/form.ts index 04f14eb8..f2499cb1 100644 --- a/src/db/models/form.ts +++ b/src/db/models/form.ts @@ -47,12 +47,13 @@ export default defineVersionedModel({ }, }, }, - prepare: async (data) => ({ - belongsToType: data.belongsTo.type, - belongsToId: - data.belongsTo.type === 'operation' - ? data.belongsTo.operation - : undefined, - }), + prepare: (data) => + Promise.resolve({ + belongsToType: data.belongsTo.type, + belongsToId: + data.belongsTo.type === 'operation' + ? data.belongsTo.operation + : undefined, + }), }, }); diff --git a/src/db/models/operation.ts b/src/db/models/operation.ts index 5f22f76a..3e68eb85 100644 --- a/src/db/models/operation.ts +++ b/src/db/models/operation.ts @@ -47,6 +47,6 @@ export default defineVersionedModel({ data: OPERATION_DATA, lookupColumns: { columns: {}, - prepare: async () => ({}), + prepare: () => Promise.resolve({}), }, }); diff --git a/src/db/models/operationCluster.ts b/src/db/models/operationCluster.ts index 78804670..b5233bab 100644 --- a/src/db/models/operationCluster.ts +++ b/src/db/models/operationCluster.ts @@ -52,8 +52,9 @@ export default defineVersionedModel({ }, }, }, - prepare: async (data) => ({ - operationId: data.operation, - }), + prepare: (data) => + Promise.resolve({ + operationId: data.operation, + }), }, }); diff --git a/src/db/models/participant.ts b/src/db/models/participant.ts index 38a5414c..afb7609f 100644 --- a/src/db/models/participant.ts +++ b/src/db/models/participant.ts @@ -2,6 +2,7 @@ import * as t from 'io-ts'; import { brandedType } from '../../util/io-ts'; import { Brand } from '../../util/types'; +import { defineIDModel } from '../util/id-model'; export type ParticipantId = Brand< number, @@ -10,3 +11,22 @@ export type ParticipantId = Brand< >; export const PARTICIPANT_ID = brandedType(t.number); + +export default defineIDModel({ + tableName: 'participant', + fields: { + generated: { + id: { kind: 'branded-integer', brand: PARTICIPANT_ID }, + }, + optional: { + hidId: { kind: 'checked', type: t.string }, + hidSub: { kind: 'checked', type: t.string }, + email: { kind: 'checked', type: t.string }, + name_given: { kind: 'checked', type: t.string }, + name_family: { kind: 'checked', type: t.string }, + }, + required: {}, + }, + idField: 'id', + softDeletionEnabled: false, +}); diff --git a/src/db/models/reportingWindow.ts b/src/db/models/reportingWindow.ts index c4a5562e..36dbba9a 100644 --- a/src/db/models/reportingWindow.ts +++ b/src/db/models/reportingWindow.ts @@ -59,12 +59,13 @@ export default defineVersionedModel({ }, }, }, - prepare: async (data) => ({ - belongsToType: data.belongsTo.type, - belongsToId: - data.belongsTo.type === 'operation' - ? data.belongsTo.operation - : undefined, - }), + prepare: (data) => + Promise.resolve({ + belongsToType: data.belongsTo.type, + belongsToId: + data.belongsTo.type === 'operation' + ? data.belongsTo.operation + : undefined, + }), }, }); diff --git a/src/db/util/id-model.ts b/src/db/util/id-model.ts index 867e90b0..4a783c69 100644 --- a/src/db/util/id-model.ts +++ b/src/db/util/id-model.ts @@ -76,7 +76,7 @@ export const defineIDModel = const model = defineSequelizeModel(opts)(conn); - const get = async (id: ID): Promise => + const get = (id: ID): Promise => model.findOne({ where: { [idField]: id, diff --git a/src/db/util/sequelize-model.ts b/src/db/util/sequelize-model.ts index ed598519..57c651a0 100644 --- a/src/db/util/sequelize-model.ts +++ b/src/db/util/sequelize-model.ts @@ -87,7 +87,7 @@ export const defineSequelizeModel = fields, })(conn); - const create: CreateFn = async (data, opts) => { + const create: CreateFn = (data, opts) => { return model.create( { ...data, @@ -98,7 +98,7 @@ export const defineSequelizeModel = ); }; - const update: UpdateFn = async (args) => { + const update: UpdateFn = (args) => { return model.update({ ...args, values: { diff --git a/src/util/types.ts b/src/util/types.ts index 9a936898..b9b1c1df 100644 --- a/src/util/types.ts +++ b/src/util/types.ts @@ -18,3 +18,6 @@ export type Brand = T & { readonly __brand__: S; readonly __label__: Label; }; + +export const createBrandedValue = >(v: T): B => + v as B; diff --git a/yarn.lock b/yarn.lock index 5b8f66cc..e5a9b411 100644 --- a/yarn.lock +++ b/yarn.lock @@ -30,10 +30,10 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@eslint/eslintrc@^0.4.2": - version "0.4.2" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.2.tgz#f63d0ef06f5c0c57d76c4ab5f63d3835c51b0179" - integrity sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg== +"@eslint/eslintrc@^0.4.3": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" + integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== dependencies: ajv "^6.12.4" debug "^4.1.1" @@ -45,6 +45,20 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" +"@humanwhocodes/config-array@^0.5.0": + version "0.5.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" + integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== + dependencies: + "@humanwhocodes/object-schema" "^1.2.0" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf" + integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -155,10 +169,10 @@ "@typescript-eslint/types" "4.28.0" eslint-visitor-keys "^2.0.0" -"@unocha/hpc-repo-tools@^0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@unocha/hpc-repo-tools/-/hpc-repo-tools-0.1.1.tgz#b3b7863605065977411607db5ddd5687d658da18" - integrity sha512-PISsdsxLvPnd1R+RrihSavEZc5S7Tdt/oui5GDC3Huk3LEvtRj1GXHNLplWfHoyquu0mLlTHtkmvOlkFk30ksQ== +"@unocha/hpc-repo-tools@^0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@unocha/hpc-repo-tools/-/hpc-repo-tools-0.1.4.tgz#586e8028a338169175a9b3ae27c88b535ac7e14b" + integrity sha512-ODI050wwaYN9R3PVNZazv9+YI4/xj3SQx2QogMN9ZwfFIu3tWgTJFGoT0vVZngkPHnMHvLxa1zTYghKiHpGu7A== dependencies: "@typescript-eslint/eslint-plugin" "^4.26.0" "@typescript-eslint/parser" "^4.26.0" @@ -641,13 +655,14 @@ eslint-visitor-keys@^2.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint@^7.27.0: - version "7.29.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.29.0.tgz#ee2a7648f2e729485e4d0bd6383ec1deabc8b3c0" - integrity sha512-82G/JToB9qIy/ArBzIWG9xvvwL3R86AlCjtGw+A29OMZDqhTybz/MByORSukGxeI+YPCR4coYyITKk8BFH9nDA== +eslint@^7.32.0: + version "7.32.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" + integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== dependencies: "@babel/code-frame" "7.12.11" - "@eslint/eslintrc" "^0.4.2" + "@eslint/eslintrc" "^0.4.3" + "@humanwhocodes/config-array" "^0.5.0" ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" @@ -1077,10 +1092,10 @@ human-signals@^2.1.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -husky@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/husky/-/husky-6.0.0.tgz#810f11869adf51604c32ea577edbc377d7f9319e" - integrity sha512-SQS2gDTB7tBN486QSoKPKQItZw97BMOd+Kdb6ghfpBc0yXyzrddI0oDV5MkDAbuB4X2mO3/nj60TRMcYxwzZeQ== +husky@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.2.tgz#21900da0f30199acca43a46c043c4ad84ae88dff" + integrity sha512-8yKEWNX4z2YsofXAMT7KvA1g8p+GxtB1ffV8XtpAEGuXNAbCV5wdNKH+qTpw8SM9fh4aMPDR+yQuKfgnreyZlg== ignore@^4.0.6: version "4.0.6" @@ -2314,10 +2329,10 @@ type-fest@^0.21.3: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== -typescript@^4.2.3: - version "4.2.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961" - integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg== +typescript@^4.3.5: + version "4.3.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4" + integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA== unc-path-regex@^0.1.2: version "0.1.2"