From 8bf98a237a10b9f495ee402cbf176621c04cd7fb Mon Sep 17 00:00:00 2001 From: Nicola Marcacci Rossi Date: Wed, 9 Aug 2023 15:45:17 +0200 Subject: [PATCH] fix: Delete --- .eslintrc | 2 +- package.json | 3 +- src/resolvers/mutations.ts | 2 +- tests/api/__snapshots__/delete.spec.ts.snap | 18 ++++++++++++ tests/api/delete.spec.ts | 28 +++++++++++++++++++ .../unit/__snapshots__/generate.spec.ts.snap | 14 ++++++++++ tests/unit/__snapshots__/resolve.spec.ts.snap | 3 ++ tests/utils/database/schema.ts | 11 ++++++++ tests/utils/database/seed.ts | 1 + tests/utils/models.ts | 12 +++++++- 10 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 tests/api/__snapshots__/delete.spec.ts.snap create mode 100644 tests/api/delete.spec.ts diff --git a/.eslintrc b/.eslintrc index 39a2134..b40a3a3 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,7 +2,7 @@ "extends": ["@smartive/eslint-config"], "parser": "@typescript-eslint/parser", "parserOptions": { - "project": "./tsconfig.json" + "project": "./tsconfig.jest.json" }, "rules": { "@typescript-eslint/no-explicit-any": "off", diff --git a/package.json b/package.json index 042440e..d316e34 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ "lint": "eslint src", "lint:fix": "eslint src --fix", "deps": "docker-compose up", - "test": "npm run lint && npm run test:unit && npm run test:api && npm run build", + "test": "npm run lint && npm run test:all && npm run build", + "test:all": "jest tests --no-cache --no-watchman", "test:unit": "jest tests/unit --no-cache --no-watchman", "test:api": "jest tests/api --no-cache --no-watchman", "generate-migration": "esbuild tests/utils/generate-migration.ts --bundle --platform=node --outdir=tmp --out-extension:.js=.cjs --format=cjs --packages=external && node tmp/generate-migration.cjs", diff --git a/src/resolvers/mutations.ts b/src/resolvers/mutations.ts index e2e856c..94484b7 100644 --- a/src/resolvers/mutations.ts +++ b/src/resolvers/mutations.ts @@ -116,7 +116,7 @@ const del = async (model: Model, { where, dryRun }: { where: any; dryRun: boolea if (entity.id in toDelete[currentModel.name]) { return; } - entity[currentModel.displayField || 'id'] || entity.id; + toDelete[currentModel.name][entity.id] = entity[currentModel.displayField || 'id'] || entity.id; if (!dryRun) { const normalizedInput = { deleted: true, deletedAt: ctx.now, deletedById: ctx.user.id }; diff --git a/tests/api/__snapshots__/delete.spec.ts.snap b/tests/api/__snapshots__/delete.spec.ts.snap new file mode 100644 index 0000000..d46e8cb --- /dev/null +++ b/tests/api/__snapshots__/delete.spec.ts.snap @@ -0,0 +1,18 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`delete works with self-referential entities 1`] = ` +{ + "deleteAnotherObject": "226a20e8-5c18-4423-99ca-eb0df6ff4fdd", +} +`; + +exports[`delete works with self-referential entities 2`] = ` +{ + "anotherObjects": [ + { + "deleted": true, + "id": "226a20e8-5c18-4423-99ca-eb0df6ff4fdd", + }, + ], +} +`; diff --git a/tests/api/delete.spec.ts b/tests/api/delete.spec.ts new file mode 100644 index 0000000..ebe2cb1 --- /dev/null +++ b/tests/api/delete.spec.ts @@ -0,0 +1,28 @@ +import { gql } from '../../src'; +import { ANOTHER_ID } from '../utils/database/seed'; +import { withServer } from '../utils/server'; + +describe('delete', () => { + it('works with self-referential entities', async () => { + await withServer(async (request) => { + expect( + await request(gql` + mutation DeleteAnotherObject { + deleteAnotherObject(where: { id: "${ANOTHER_ID}" }) + } + `) + ).toMatchSnapshot(); + + expect( + await request(gql` + query GetAnotherObject { + anotherObjects(where: { id: "${ANOTHER_ID}", deleted: true }) { + id + deleted + } + } + `) + ).toMatchSnapshot(); + }); + }); +}); diff --git a/tests/unit/__snapshots__/generate.spec.ts.snap b/tests/unit/__snapshots__/generate.spec.ts.snap index 74fe72e..7285acf 100644 --- a/tests/unit/__snapshots__/generate.spec.ts.snap +++ b/tests/unit/__snapshots__/generate.spec.ts.snap @@ -3,11 +3,21 @@ exports[`generate generates a schema 1`] = ` "type AnotherObject { id: ID! + myself: AnotherObject + deleted: Boolean! + deletedAt: DateTime + deletedBy: User + self(where: AnotherObjectWhere, orderBy: [AnotherObjectOrderBy!], limit: Int, offset: Int): AnotherObject manyObjects(where: SomeObjectWhere, search: String, orderBy: [SomeObjectOrderBy!], limit: Int, offset: Int): [SomeObject!]! } +input AnotherObjectOrderBy { + deletedAt: Order +} + input AnotherObjectWhere { id: [ID!] + deleted: [Boolean!] = false } input AnotherObjectWhereUnique { @@ -21,6 +31,8 @@ input CreateSomeObject { scalar DateTime type Mutation { + deleteAnotherObject(where: AnotherObjectWhereUnique!, dryRun: Boolean): ID! + restoreAnotherObject(where: AnotherObjectWhereUnique!): ID! createSomeObject(data: CreateSomeObject!): SomeObject! updateSomeObject(where: SomeObjectWhereUnique!, data: UpdateSomeObject!): SomeObject! deleteSomeObject(where: SomeObjectWhereUnique!, dryRun: Boolean): ID! @@ -35,6 +47,7 @@ enum Order { type Query { me: User someObject(where: SomeObjectWhereUnique!): SomeObject! + anotherObjects(where: AnotherObjectWhere, orderBy: [AnotherObjectOrderBy!], limit: Int, offset: Int): [AnotherObject!]! manyObjects(where: SomeObjectWhere, search: String, orderBy: [SomeObjectOrderBy!], limit: Int, offset: Int): [SomeObject!]! } @@ -95,6 +108,7 @@ type User { id: ID! username: String role: Role + deletedAnotherObjects(where: AnotherObjectWhere, orderBy: [AnotherObjectOrderBy!], limit: Int, offset: Int): [AnotherObject!]! createdManyObjects(where: SomeObjectWhere, search: String, orderBy: [SomeObjectOrderBy!], limit: Int, offset: Int): [SomeObject!]! updatedManyObjects(where: SomeObjectWhere, search: String, orderBy: [SomeObjectOrderBy!], limit: Int, offset: Int): [SomeObject!]! deletedManyObjects(where: SomeObjectWhere, search: String, orderBy: [SomeObjectOrderBy!], limit: Int, offset: Int): [SomeObject!]! diff --git a/tests/unit/__snapshots__/resolve.spec.ts.snap b/tests/unit/__snapshots__/resolve.spec.ts.snap index 301c61b..a3bca81 100644 --- a/tests/unit/__snapshots__/resolve.spec.ts.snap +++ b/tests/unit/__snapshots__/resolve.spec.ts.snap @@ -4,11 +4,14 @@ exports[`resolvers are generated correctly 1`] = ` { "Mutation": { "createSomeObject": [Function], + "deleteAnotherObject": [Function], "deleteSomeObject": [Function], + "restoreAnotherObject": [Function], "restoreSomeObject": [Function], "updateSomeObject": [Function], }, "Query": { + "anotherObjects": [Function], "manyObjects": [Function], "me": [Function], "someObject": [Function], diff --git a/tests/utils/database/schema.ts b/tests/utils/database/schema.ts index b463166..f704b81 100644 --- a/tests/utils/database/schema.ts +++ b/tests/utils/database/schema.ts @@ -19,8 +19,19 @@ export const setupSchema = async (knex: Knex) => { await knex.schema.createTable('AnotherObject', (table) => { table.uuid('id').notNullable().primary(); + table.uuid('myselfId').notNullable(); + table.foreign('myselfId').references('id').inTable('AnotherObject'); + table.boolean('deleted').notNullable().defaultTo(false); + table.timestamp('deletedAt').nullable(); + table.uuid('deletedById').nullable(); + table.foreign('deletedById').references('id').inTable('User'); }); + await knex.schema.createTable('AnotherObjectRevision', (table) => { + table.uuid('id').notNullable().primary(); + table.boolean('deleted').notNullable(); + }); + await knex.schema.createTable('SomeObject', (table) => { table.uuid('id').notNullable().primary(); table.string('field', undefined).nullable(); diff --git a/tests/utils/database/seed.ts b/tests/utils/database/seed.ts index d9b3330..9302e63 100644 --- a/tests/utils/database/seed.ts +++ b/tests/utils/database/seed.ts @@ -19,6 +19,7 @@ export const seed = { AnotherObject: [ { id: ANOTHER_ID, + myselfId: ANOTHER_ID, }, ], SomeObject: [ diff --git a/tests/utils/models.ts b/tests/utils/models.ts index f579148..9286b8f 100644 --- a/tests/utils/models.ts +++ b/tests/utils/models.ts @@ -37,7 +37,17 @@ export const rawModels: RawModels = [ { type: 'object', name: 'AnotherObject', - fields: [], + listQueriable: true, + deletable: true, + fields: [ + { + type: 'AnotherObject', + name: 'myself', + toOne: true, + reverse: 'self', + relation: true + } + ], }, { type: 'object',