From d87b887f8fff80eaeb79965f6127beeaf43c40f6 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Sun, 5 Jul 2026 01:50:20 +0000 Subject: [PATCH 1/3] fix: use entity field names in CLI delete select instead of PK constraint names The codegen for CLI delete handlers was using PK constraint field names (e.g. principalId) in the select clause, but these names come from PostGraphile's inflected mutation input names and may differ from the entity's actual field names (e.g. id) in the Select type. Use buildSelectObject() for delete (same as create/update) to ensure select uses entity field names that match the generated Select types. --- .../__snapshots__/cli-generator.test.ts.snap | 25 +++++++++++++++---- .../codegen/cli/table-command-generator.ts | 9 +------ .../src/auth/cli/commands/principal.ts | 10 +++++++- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/graphql/codegen/src/__tests__/codegen/__snapshots__/cli-generator.test.ts.snap b/graphql/codegen/src/__tests__/codegen/__snapshots__/cli-generator.test.ts.snap index 0f725ca98..583fa9f0e 100644 --- a/graphql/codegen/src/__tests__/codegen/__snapshots__/cli-generator.test.ts.snap +++ b/graphql/codegen/src/__tests__/codegen/__snapshots__/cli-generator.test.ts.snap @@ -949,7 +949,12 @@ async function handleDelete(argv: Partial>, prompter: In id: answers.id as string }, select: { - id: true + id: true, + make: true, + model: true, + year: true, + isElectric: true, + createdAt: true } }).execute(); console.log(JSON.stringify(result, null, 2)); @@ -1375,7 +1380,9 @@ async function handleDelete(argv: Partial>, prompter: In id: answers.id as string }, select: { - id: true + id: true, + name: true, + licenseNumber: true } }).execute(); console.log(JSON.stringify(result, null, 2)); @@ -3412,7 +3419,9 @@ async function handleDelete(argv: Partial>, prompter: In id: answers.id as string }, select: { - id: true + id: true, + email: true, + name: true } }).execute(); console.log(JSON.stringify(result, null, 2)); @@ -3628,7 +3637,8 @@ async function handleDelete(argv: Partial>, prompter: In id: answers.id as string }, select: { - id: true + id: true, + role: true } }).execute(); console.log(JSON.stringify(result, null, 2)); @@ -3904,7 +3914,12 @@ async function handleDelete(argv: Partial>, prompter: In id: answers.id as string }, select: { - id: true + id: true, + make: true, + model: true, + year: true, + isElectric: true, + createdAt: true } }).execute(); console.log(JSON.stringify(result, null, 2)); diff --git a/graphql/codegen/src/core/codegen/cli/table-command-generator.ts b/graphql/codegen/src/core/codegen/cli/table-command-generator.ts index 7471776f0..3542bec3c 100644 --- a/graphql/codegen/src/core/codegen/cli/table-command-generator.ts +++ b/graphql/codegen/src/core/codegen/cli/table-command-generator.ts @@ -1177,14 +1177,7 @@ function buildMutationHandler( } } - const selectObj = - operation === 'delete' - ? t.objectExpression( - pkFields.map((pkField) => - t.objectProperty(t.identifier(pkField.name), t.booleanLiteral(true)), - ), - ) - : buildSelectObject(table, typeRegistry); + const selectObj = buildSelectObject(table, typeRegistry); let ormArgs: t.ObjectExpression; diff --git a/sdk/constructive-cli/src/auth/cli/commands/principal.ts b/sdk/constructive-cli/src/auth/cli/commands/principal.ts index b3b742cc7..17d5b485a 100644 --- a/sdk/constructive-cli/src/auth/cli/commands/principal.ts +++ b/sdk/constructive-cli/src/auth/cli/commands/principal.ts @@ -259,7 +259,15 @@ async function handleDelete(argv: Partial>, prompter: In principalId: answers.principalId as string, }, select: { - principalId: true, + id: true, + createdAt: true, + updatedAt: true, + ownerId: true, + userId: true, + name: true, + allowedMask: true, + isReadOnly: true, + bypassStepUp: true, }, }) .execute(); From ca6010b0fa80db9cc51a9ba650fc767c88dea741 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Sun, 5 Jul 2026 02:03:03 +0000 Subject: [PATCH 2/3] fix: resolve entity field names for delete select instead of selecting all fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Map PK constraint names back to entity field names via reverse inflection (e.g. principalId → id) so delete select stays minimal while using correct field names that exist on the generated *Select type. --- .../__snapshots__/cli-generator.test.ts.snap | 25 ++++------------- .../codegen/cli/table-command-generator.ts | 27 ++++++++++++++++++- .../src/auth/cli/commands/principal.ts | 8 ------ 3 files changed, 31 insertions(+), 29 deletions(-) diff --git a/graphql/codegen/src/__tests__/codegen/__snapshots__/cli-generator.test.ts.snap b/graphql/codegen/src/__tests__/codegen/__snapshots__/cli-generator.test.ts.snap index 583fa9f0e..0f725ca98 100644 --- a/graphql/codegen/src/__tests__/codegen/__snapshots__/cli-generator.test.ts.snap +++ b/graphql/codegen/src/__tests__/codegen/__snapshots__/cli-generator.test.ts.snap @@ -949,12 +949,7 @@ async function handleDelete(argv: Partial>, prompter: In id: answers.id as string }, select: { - id: true, - make: true, - model: true, - year: true, - isElectric: true, - createdAt: true + id: true } }).execute(); console.log(JSON.stringify(result, null, 2)); @@ -1380,9 +1375,7 @@ async function handleDelete(argv: Partial>, prompter: In id: answers.id as string }, select: { - id: true, - name: true, - licenseNumber: true + id: true } }).execute(); console.log(JSON.stringify(result, null, 2)); @@ -3419,9 +3412,7 @@ async function handleDelete(argv: Partial>, prompter: In id: answers.id as string }, select: { - id: true, - email: true, - name: true + id: true } }).execute(); console.log(JSON.stringify(result, null, 2)); @@ -3637,8 +3628,7 @@ async function handleDelete(argv: Partial>, prompter: In id: answers.id as string }, select: { - id: true, - role: true + id: true } }).execute(); console.log(JSON.stringify(result, null, 2)); @@ -3914,12 +3904,7 @@ async function handleDelete(argv: Partial>, prompter: In id: answers.id as string }, select: { - id: true, - make: true, - model: true, - year: true, - isElectric: true, - createdAt: true + id: true } }).execute(); console.log(JSON.stringify(result, null, 2)); diff --git a/graphql/codegen/src/core/codegen/cli/table-command-generator.ts b/graphql/codegen/src/core/codegen/cli/table-command-generator.ts index 3542bec3c..9ddb70522 100644 --- a/graphql/codegen/src/core/codegen/cli/table-command-generator.ts +++ b/graphql/codegen/src/core/codegen/cli/table-command-generator.ts @@ -1177,7 +1177,32 @@ function buildMutationHandler( } } - const selectObj = buildSelectObject(table, typeRegistry); + const selectObj = + operation === 'delete' + ? t.objectExpression( + pkFields.map((pkField) => { + // PK constraint names come from PostGraphile inflection (e.g. "principalId" + // for the "id" column on the Principal table). The select clause must use + // entity field names that exist on the generated *Select type. + const scalarFields = getScalarFields(table); + const directMatch = scalarFields.find((f) => f.name === pkField.name); + if (directMatch) { + return t.objectProperty(t.identifier(pkField.name), t.booleanLiteral(true)); + } + // Reverse the standard inflection: {lcFirst(typeName)}Id → id + const prefix = lcFirst(typeName); + if (pkField.name.startsWith(prefix)) { + const stripped = lcFirst(pkField.name.slice(prefix.length)); + const match = scalarFields.find((f) => f.name === stripped); + if (match) { + return t.objectProperty(t.identifier(stripped), t.booleanLiteral(true)); + } + } + // Fallback: use the PK name as-is (will surface a TS error if wrong) + return t.objectProperty(t.identifier(pkField.name), t.booleanLiteral(true)); + }), + ) + : buildSelectObject(table, typeRegistry); let ormArgs: t.ObjectExpression; diff --git a/sdk/constructive-cli/src/auth/cli/commands/principal.ts b/sdk/constructive-cli/src/auth/cli/commands/principal.ts index 17d5b485a..2917cb29a 100644 --- a/sdk/constructive-cli/src/auth/cli/commands/principal.ts +++ b/sdk/constructive-cli/src/auth/cli/commands/principal.ts @@ -260,14 +260,6 @@ async function handleDelete(argv: Partial>, prompter: In }, select: { id: true, - createdAt: true, - updatedAt: true, - ownerId: true, - userId: true, - name: true, - allowedMask: true, - isReadOnly: true, - bypassStepUp: true, }, }) .execute(); From b7e11690b363fd21ed0afa185fddcf4968013f97 Mon Sep 17 00:00:00 2001 From: Dan Lynch Date: Sun, 5 Jul 2026 03:39:00 +0000 Subject: [PATCH 3/3] fix: distinguish custom SQL function mutations from CRUD in codegen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit matchMutationOperations now checks the payload type before claiming a mutation as CRUD. PostGraphile CRUD payloads always contain a field named lcFirst(entityName) whose type is the entity (e.g. DeleteUserPayload has `user: User`). Custom SQL-function mutations that happen to follow the same naming convention (e.g. `deletePrincipal`) return something else — typically `result: Boolean` — and are no longer mistaken for CRUD. This fixes Principal, whose delete/create are custom SQL functions (`delete_principal()`, `create_principal()`) that PostGraphile exposes as `deletePrincipal` / `createPrincipal`. The codegen was treating these as standard CRUD mutations, which caused a TS error because the inferred PK constraint name (`principalId`, from the function arg) did not match the entity field name (`id`) in PrincipalSelect. Reverts the earlier reverse-inflection workaround in table-command-generator.ts — the root cause is now fixed upstream in infer-tables.ts. --- .../__tests__/introspect/infer-tables.test.ts | 8 +- .../codegen/cli/table-command-generator.ts | 24 +- graphql/query/src/introspect/infer-tables.ts | 43 ++- .../src/auth/cli/commands/principal.ts | 288 ++++++------------ 4 files changed, 139 insertions(+), 224 deletions(-) diff --git a/graphql/codegen/src/__tests__/introspect/infer-tables.test.ts b/graphql/codegen/src/__tests__/introspect/infer-tables.test.ts index df21806b2..d5678101d 100644 --- a/graphql/codegen/src/__tests__/introspect/infer-tables.test.ts +++ b/graphql/codegen/src/__tests__/introspect/infer-tables.test.ts @@ -732,7 +732,7 @@ describe('Mutation Operation Matching', () => { fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], }, { name: 'UsersConnection', kind: 'OBJECT', fields: [] }, - { name: 'CreateUserPayload', kind: 'OBJECT', fields: [] }, + { name: 'CreateUserPayload', kind: 'OBJECT', fields: [{ name: 'user', type: object('User') }] }, ], [{ name: 'users', type: object('UsersConnection') }], [ @@ -760,8 +760,8 @@ describe('Mutation Operation Matching', () => { fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], }, { name: 'UsersConnection', kind: 'OBJECT', fields: [] }, - { name: 'UpdateUserPayload', kind: 'OBJECT', fields: [] }, - { name: 'DeleteUserPayload', kind: 'OBJECT', fields: [] }, + { name: 'UpdateUserPayload', kind: 'OBJECT', fields: [{ name: 'user', type: object('User') }] }, + { name: 'DeleteUserPayload', kind: 'OBJECT', fields: [{ name: 'user', type: object('User') }] }, ], [{ name: 'users', type: object('UsersConnection') }], [ @@ -797,7 +797,7 @@ describe('Mutation Operation Matching', () => { fields: [{ name: 'id', type: nonNull(scalar('UUID')) }], }, { name: 'UsersConnection', kind: 'OBJECT', fields: [] }, - { name: 'UpdateUserPayload', kind: 'OBJECT', fields: [] }, + { name: 'UpdateUserPayload', kind: 'OBJECT', fields: [{ name: 'user', type: object('User') }] }, ], [{ name: 'users', type: object('UsersConnection') }], [ diff --git a/graphql/codegen/src/core/codegen/cli/table-command-generator.ts b/graphql/codegen/src/core/codegen/cli/table-command-generator.ts index 9ddb70522..7471776f0 100644 --- a/graphql/codegen/src/core/codegen/cli/table-command-generator.ts +++ b/graphql/codegen/src/core/codegen/cli/table-command-generator.ts @@ -1180,27 +1180,9 @@ function buildMutationHandler( const selectObj = operation === 'delete' ? t.objectExpression( - pkFields.map((pkField) => { - // PK constraint names come from PostGraphile inflection (e.g. "principalId" - // for the "id" column on the Principal table). The select clause must use - // entity field names that exist on the generated *Select type. - const scalarFields = getScalarFields(table); - const directMatch = scalarFields.find((f) => f.name === pkField.name); - if (directMatch) { - return t.objectProperty(t.identifier(pkField.name), t.booleanLiteral(true)); - } - // Reverse the standard inflection: {lcFirst(typeName)}Id → id - const prefix = lcFirst(typeName); - if (pkField.name.startsWith(prefix)) { - const stripped = lcFirst(pkField.name.slice(prefix.length)); - const match = scalarFields.find((f) => f.name === stripped); - if (match) { - return t.objectProperty(t.identifier(stripped), t.booleanLiteral(true)); - } - } - // Fallback: use the PK name as-is (will surface a TS error if wrong) - return t.objectProperty(t.identifier(pkField.name), t.booleanLiteral(true)); - }), + pkFields.map((pkField) => + t.objectProperty(t.identifier(pkField.name), t.booleanLiteral(true)), + ), ) : buildSelectObject(table, typeRegistry); diff --git a/graphql/query/src/introspect/infer-tables.ts b/graphql/query/src/introspect/infer-tables.ts index e5b78652c..51c10e943 100644 --- a/graphql/query/src/introspect/infer-tables.ts +++ b/graphql/query/src/introspect/infer-tables.ts @@ -290,7 +290,7 @@ function buildCleanTable( // Match query and mutation operations const queryOps = matchQueryOperations(entityName, queryFields, entityToConnection); - const mutationOps = matchMutationOperations(entityName, mutationFields); + const mutationOps = matchMutationOperations(entityName, mutationFields, typeMap); // Check if we found at least one real operation (not a fallback) const hasRealOperation = !!( @@ -699,6 +699,30 @@ interface MutationOperations { bulkDelete: string | null; } +/** + * Check whether a mutation field is a real PostGraphile CRUD mutation. + * + * CRUD mutation payloads always contain a field named lcFirst(entityName) + * whose type is the entity itself (e.g. DeleteUserPayload has `user: User`). + * Custom SQL-function mutations that happen to follow the same naming + * convention (e.g. `deletePrincipal`) return something else — typically + * `result: Boolean` or `result: UUID` — and must not be treated as CRUD. + */ +function isCrudMutation( + field: IntrospectionField, + entityName: string, + typeMap: Map, +): boolean { + const payloadTypeName = getBaseTypeName(field.type); + if (!payloadTypeName) return false; + const payloadType = typeMap.get(payloadTypeName); + if (!payloadType || !payloadType.fields) return false; + const entityFieldName = lcFirst(entityName); + return payloadType.fields.some( + (f) => f.name === entityFieldName && getBaseTypeName(f.type) === entityName, + ); +} + /** * Match mutation operations for an entity * @@ -710,10 +734,15 @@ interface MutationOperations { * - bulkUpsert{PluralName} (bulk upsert) * - bulkUpdate{PluralName} (bulk update) * - bulkDelete{PluralName} (bulk delete) + * + * A candidate is only accepted if its payload type returns the entity + * (i.e. it is a real CRUD mutation, not a custom SQL function that + * happens to share the naming convention). */ function matchMutationOperations( entityName: string, mutationFields: IntrospectionField[], + typeMap: Map, ): MutationOperations { let create: string | null = null; let update: string | null = null; @@ -736,28 +765,30 @@ function matchMutationOperations( for (const field of mutationFields) { // Exact match for create - if (field.name === expectedCreate) { + if (field.name === expectedCreate && isCrudMutation(field, entityName, typeMap)) { create = field.name; } // Match update (could be updateUser, updateUserById, or updateUserByFooAndBar for composite PKs) - if (field.name === expectedUpdate) { + if (field.name === expectedUpdate && isCrudMutation(field, entityName, typeMap)) { update = field.name; } else if ( !update && (field.name === `${expectedUpdate}ById` || - field.name.startsWith(`${expectedUpdate}By`)) + field.name.startsWith(`${expectedUpdate}By`)) && + isCrudMutation(field, entityName, typeMap) ) { update = field.name; } // Match delete (could be deleteUser, deleteUserById, or deleteUserByFooAndBar for composite PKs) - if (field.name === expectedDelete) { + if (field.name === expectedDelete && isCrudMutation(field, entityName, typeMap)) { del = field.name; } else if ( !del && (field.name === `${expectedDelete}ById` || - field.name.startsWith(`${expectedDelete}By`)) + field.name.startsWith(`${expectedDelete}By`)) && + isCrudMutation(field, entityName, typeMap) ) { del = field.name; } diff --git a/sdk/constructive-cli/src/auth/cli/commands/principal.ts b/sdk/constructive-cli/src/auth/cli/commands/principal.ts index 2917cb29a..9066f9d2e 100644 --- a/sdk/constructive-cli/src/auth/cli/commands/principal.ts +++ b/sdk/constructive-cli/src/auth/cli/commands/principal.ts @@ -3,70 +3,52 @@ * @generated by @constructive-io/graphql-codegen * DO NOT EDIT - changes will be overwritten */ -import { CLIOptions, Inquirerer, extractFirst } from 'inquirerer'; -import { getClient } from '../executor'; -import { coerceAnswers, parseFindFirstArgs, parseFindManyArgs, stripUndefined } from '../utils'; -import type { FieldSchema } from '../utils'; -import type { - CreatePrincipalInput, - PrincipalPatch, - PrincipalSelect, - PrincipalFilter, - PrincipalOrderBy, -} from '../../orm/input-types'; -import type { FindManyArgs, FindFirstArgs } from '../../orm/select-types'; +import { CLIOptions, Inquirerer, extractFirst } from "inquirerer"; +import { getClient } from "../executor"; +import { coerceAnswers, parseFindFirstArgs, parseFindManyArgs, stripUndefined } from "../utils"; +import type { FieldSchema } from "../utils"; +import type { CreatePrincipalInput, PrincipalPatch, PrincipalSelect, PrincipalFilter, PrincipalOrderBy } from "../../orm/input-types"; +import type { FindManyArgs, FindFirstArgs } from "../../orm/select-types"; const fieldSchema: FieldSchema = { - id: 'uuid', - createdAt: 'string', - updatedAt: 'string', - ownerId: 'uuid', - userId: 'uuid', - name: 'string', - allowedMask: 'string', - isReadOnly: 'boolean', - bypassStepUp: 'boolean', + id: "uuid", + createdAt: "string", + updatedAt: "string", + ownerId: "uuid", + userId: "uuid", + name: "string", + allowedMask: "string", + isReadOnly: "boolean", + bypassStepUp: "boolean" }; -const usage = - '\nprincipal \n\nCommands:\n list List principal records\n find-first Find first matching principal record\n get Get a principal by ID\n create Create a new principal\n delete Delete a principal\n\nList Options:\n --limit Max number of records to return (forward pagination)\n --last Number of records from the end (backward pagination)\n --after Cursor for forward pagination\n --before Cursor for backward pagination\n --offset Number of records to skip\n --select Comma-separated list of fields to return\n --where.. Filter (dot-notation, e.g. --where.name.equalTo foo)\n --condition.. Condition filter (dot-notation)\n --orderBy Comma-separated ordering values (e.g. NAME_ASC,CREATED_AT_DESC)\n\nFind-First Options:\n --select Comma-separated list of fields to return\n --where.. Filter (dot-notation, e.g. --where.status.equalTo active)\n --condition.. Condition filter (dot-notation)\n --orderBy Comma-separated ordering values (e.g. NAME_ASC,CREATED_AT_DESC)\n\n --help, -h Show this help message\n'; -export default async ( - argv: Partial>, - prompter: Inquirerer, - _options: CLIOptions -) => { +const usage = "\nprincipal \n\nCommands:\n list List principal records\n find-first Find first matching principal record\n create Create a new principal\n\nList Options:\n --limit Max number of records to return (forward pagination)\n --last Number of records from the end (backward pagination)\n --after Cursor for forward pagination\n --before Cursor for backward pagination\n --offset Number of records to skip\n --select Comma-separated list of fields to return\n --where.. Filter (dot-notation, e.g. --where.name.equalTo foo)\n --condition.. Condition filter (dot-notation)\n --orderBy Comma-separated ordering values (e.g. NAME_ASC,CREATED_AT_DESC)\n\nFind-First Options:\n --select Comma-separated list of fields to return\n --where.. Filter (dot-notation, e.g. --where.status.equalTo active)\n --condition.. Condition filter (dot-notation)\n --orderBy Comma-separated ordering values (e.g. NAME_ASC,CREATED_AT_DESC)\n\n --help, -h Show this help message\n"; +export default async (argv: Partial>, prompter: Inquirerer, _options: CLIOptions) => { if (argv.help || argv.h) { console.log(usage); process.exit(0); } - const { first: subcommand, newArgv } = extractFirst(argv); + const { + first: subcommand, + newArgv + } = extractFirst(argv); if (!subcommand) { - const answer = await prompter.prompt(argv, [ - { - type: 'autocomplete', - name: 'subcommand', - message: 'What do you want to do?', - options: ['list', 'find-first', 'get', 'create', 'delete'], - }, - ]); + const answer = await prompter.prompt(argv, [{ + type: "autocomplete", + name: "subcommand", + message: "What do you want to do?", + options: ["list", "find-first", "create"] + }]); return handleTableSubcommand(answer.subcommand as string, newArgv, prompter); } return handleTableSubcommand(subcommand, newArgv, prompter); }; -async function handleTableSubcommand( - subcommand: string, - argv: Partial>, - prompter: Inquirerer -) { +async function handleTableSubcommand(subcommand: string, argv: Partial>, prompter: Inquirerer) { switch (subcommand) { - case 'list': + case "list": return handleList(argv, prompter); - case 'find-first': + case "find-first": return handleFindFirst(argv, prompter); - case 'get': - return handleGet(argv, prompter); - case 'create': + case "create": return handleCreate(argv, prompter); - case 'delete': - return handleDelete(argv, prompter); default: console.log(usage); process.exit(1); @@ -83,18 +65,16 @@ async function handleList(argv: Partial>, _prompter: Inq name: true, allowedMask: true, isReadOnly: true, - bypassStepUp: true, + bypassStepUp: true }; - const findManyArgs = parseFindManyArgs< - FindManyArgs & { - select: PrincipalSelect; - } - >(argv, defaultSelect); + const findManyArgs = parseFindManyArgs & { + select: PrincipalSelect; + }>(argv, defaultSelect); const client = getClient(); const result = await client.principal.findMany(findManyArgs).execute(); console.log(JSON.stringify(result, null, 2)); } catch (error) { - console.error('Failed to list records.'); + console.error("Failed to list records."); if (error instanceof Error) { console.error(error.message); } @@ -112,54 +92,16 @@ async function handleFindFirst(argv: Partial>, _prompter name: true, allowedMask: true, isReadOnly: true, - bypassStepUp: true, + bypassStepUp: true }; - const findFirstArgs = parseFindFirstArgs< - FindFirstArgs & { - select: PrincipalSelect; - } - >(argv, defaultSelect); + const findFirstArgs = parseFindFirstArgs & { + select: PrincipalSelect; + }>(argv, defaultSelect); const client = getClient(); const result = await client.principal.findFirst(findFirstArgs).execute(); console.log(JSON.stringify(result, null, 2)); } catch (error) { - console.error('Failed to find record.'); - if (error instanceof Error) { - console.error(error.message); - } - process.exit(1); - } -} -async function handleGet(argv: Partial>, prompter: Inquirerer) { - try { - const answers = await prompter.prompt(argv, [ - { - type: 'text', - name: 'principalId', - message: 'principalId', - required: true, - }, - ]); - const client = getClient(); - const result = await client.principal - .findOne({ - principalId: answers.principalId as string, - select: { - id: true, - createdAt: true, - updatedAt: true, - ownerId: true, - userId: true, - name: true, - allowedMask: true, - isReadOnly: true, - bypassStepUp: true, - }, - }) - .execute(); - console.log(JSON.stringify(result, null, 2)); - } catch (error) { - console.error('Record not found.'); + console.error("Failed to find record."); if (error instanceof Error) { console.error(error.message); } @@ -168,107 +110,67 @@ async function handleGet(argv: Partial>, prompter: Inqui } async function handleCreate(argv: Partial>, prompter: Inquirerer) { try { - const rawAnswers = await prompter.prompt(argv, [ - { - type: 'text', - name: 'ownerId', - message: 'ownerId', - required: true, - }, - { - type: 'text', - name: 'userId', - message: 'userId', - required: true, - }, - { - type: 'text', - name: 'name', - message: 'name', - required: true, - }, - { - type: 'text', - name: 'allowedMask', - message: 'allowedMask', - required: true, - }, - { - type: 'boolean', - name: 'isReadOnly', - message: 'isReadOnly', - required: true, - }, - { - type: 'boolean', - name: 'bypassStepUp', - message: 'bypassStepUp', - required: true, - }, - ]); + const rawAnswers = await prompter.prompt(argv, [{ + type: "text", + name: "ownerId", + message: "ownerId", + required: true + }, { + type: "text", + name: "userId", + message: "userId", + required: true + }, { + type: "text", + name: "name", + message: "name", + required: true + }, { + type: "text", + name: "allowedMask", + message: "allowedMask", + required: true + }, { + type: "boolean", + name: "isReadOnly", + message: "isReadOnly", + required: true + }, { + type: "boolean", + name: "bypassStepUp", + message: "bypassStepUp", + required: true + }]); const answers = coerceAnswers(rawAnswers, fieldSchema); - const cleanedData = stripUndefined(answers, fieldSchema) as CreatePrincipalInput['principal']; + const cleanedData = stripUndefined(answers, fieldSchema) as CreatePrincipalInput["principal"]; const client = getClient(); - const result = await client.principal - .create({ - data: { - ownerId: cleanedData.ownerId, - userId: cleanedData.userId, - name: cleanedData.name, - allowedMask: cleanedData.allowedMask, - isReadOnly: cleanedData.isReadOnly, - bypassStepUp: cleanedData.bypassStepUp, - }, - select: { - id: true, - createdAt: true, - updatedAt: true, - ownerId: true, - userId: true, - name: true, - allowedMask: true, - isReadOnly: true, - bypassStepUp: true, - }, - }) - .execute(); - console.log(JSON.stringify(result, null, 2)); - } catch (error) { - console.error('Failed to create record.'); - if (error instanceof Error) { - console.error(error.message); - } - process.exit(1); - } -} -async function handleDelete(argv: Partial>, prompter: Inquirerer) { - try { - const rawAnswers = await prompter.prompt(argv, [ - { - type: 'text', - name: 'principalId', - message: 'principalId', - required: true, + const result = await client.principal.create({ + data: { + ownerId: cleanedData.ownerId, + userId: cleanedData.userId, + name: cleanedData.name, + allowedMask: cleanedData.allowedMask, + isReadOnly: cleanedData.isReadOnly, + bypassStepUp: cleanedData.bypassStepUp }, - ]); - const answers = coerceAnswers(rawAnswers, fieldSchema); - const client = getClient(); - const result = await client.principal - .delete({ - where: { - principalId: answers.principalId as string, - }, - select: { - id: true, - }, - }) - .execute(); + select: { + id: true, + createdAt: true, + updatedAt: true, + ownerId: true, + userId: true, + name: true, + allowedMask: true, + isReadOnly: true, + bypassStepUp: true + } + }).execute(); console.log(JSON.stringify(result, null, 2)); } catch (error) { - console.error('Failed to delete record.'); + console.error("Failed to create record."); if (error instanceof Error) { console.error(error.message); } process.exit(1); } -} +} \ No newline at end of file