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<unknown> }>({
...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<UpdateRecordInput> & Record<string, unknown> = {},
) {
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'),
})
}