import { pickAuthInput } from './auth.ts' import { airtableRequest } from './client.ts' import { mapRecord } from './models.ts' import { recordsPath } from './setup.ts' import type { AirtableAuthInput, AirtableRecordSummary, DryRunResult, JsonRecord, } from './types.ts' import { optionalBoolean, requireConfirmOrDryRun, requireRecord, requireString, } from './types.ts' export type UpdateRecordInput = AirtableAuthInput & { baseId: string tableIdOrName: string recordId: string fields: JsonRecord typecast?: boolean confirm?: boolean dryRun?: boolean } function updatePayload(input: UpdateRecordInput): { path: string body: JsonRecord } { const fields = requireRecord(input.fields, 'fields') if (Object.keys(fields).length === 0) { throw new Error('update-record requires at least one field to change.') } const body: JsonRecord = { records: [ { id: requireString(input.recordId, 'recordId'), fields, }, ], } const typecast = optionalBoolean(input.typecast, 'typecast') if (typecast !== undefined) body.typecast = typecast return { path: recordsPath( requireString(input.baseId, 'baseId'), requireString(input.tableIdOrName, 'tableIdOrName'), ), body, } } /** * Update an Airtable record. Requires `confirm: true`, or use `dryRun: true`. * Needs `data.records:write`. * @example * import updateRecord from 'kody:@kody/airtable/update-record' * const preview = await updateRecord({ * baseId: 'appXXXXXXXXXXXXXX', * tableIdOrName: 'tblXXXXXXXXXXXXXX', * recordId: 'recXXXXXXXXXXXXXX', * fields: { Status: 'Done' }, * dryRun: true, * }) */ export async function updateRecord( input: UpdateRecordInput, ): Promise< AirtableRecordSummary | DryRunResult<{ method: string; path: string; body: JsonRecord }> > { const payload = updatePayload(input) if (requireConfirmOrDryRun(input, 'Updating an Airtable record') === 'dryRun') { return { dryRun: true, wouldCall: { method: 'PATCH', ...payload } } } const result = await airtableRequest<{ records?: Array }>({ ...input, operation: 'records.write', method: 'PATCH', path: payload.path, body: payload.body, }) const body = result.data && typeof result.data === 'object' ? result.data : {} const updated = Array.isArray(body.records) ? body.records[0] : null if (!updated) throw new Error('Airtable update record did not return a record.') return mapRecord(updated) } /** * Update an Airtable record. Requires `confirm: true`, or use `dryRun: true`. * @example * import updateRecord from 'kody:@kody/airtable/update-record' * const preview = await updateRecord({ * baseId: 'appXXXXXXXXXXXXXX', * tableIdOrName: 'Tasks', * recordId: 'recXXXXXXXXXXXXXX', * fields: { Status: 'Done' }, * dryRun: true, * }) */ export default async function updateRecordEntrypoint( params: Partial & Record = {}, ) { const input = requireRecord(params, 'update-record') return updateRecord({ baseId: requireString(input.baseId, 'baseId'), tableIdOrName: requireString(input.tableIdOrName, 'tableIdOrName'), recordId: requireString(input.recordId, 'recordId'), fields: requireRecord(input.fields, 'fields'), typecast: optionalBoolean(input.typecast, 'typecast'), ...pickAuthInput(input), confirm: optionalBoolean(input.confirm, 'confirm'), dryRun: optionalBoolean(input.dryRun, 'dryRun'), }) }