(core) DocApi meta endpoints: GET /tables and POST/PATCH /tables and /columns

Summary:
Adds new API endpoints to list tables in a document and create or modify tables and columns. The request and response formats are designed to mirror the style of the existing `GET /columns` and `GET/POST/PATCH /records` endpoints.

Discussion: https://grist.slack.com/archives/C0234CPPXPA/p1665139807125649?thread_ts=1628957179.010500&cid=C0234CPPXPA

Test Plan: DocApi test

Reviewers: jarek

Reviewed By: jarek

Subscribers: paulfitz

Differential Revision: https://phab.getgrist.com/D3667
This commit is contained in:
Alex Hall
2022-10-20 21:24:14 +02:00
parent 4c662253a9
commit 62792329c3
5 changed files with 417 additions and 8 deletions

View File

@@ -10,6 +10,13 @@ export const NewRecord = t.iface([], {
})),
});
export const NewRecordWithStringId = t.iface([], {
"id": t.opt("string"),
"fields": t.opt(t.iface([], {
[t.indexKey]: "CellValue",
})),
});
export const Record = t.iface([], {
"id": "number",
"fields": t.iface([], {
@@ -17,6 +24,13 @@ export const Record = t.iface([], {
}),
});
export const RecordWithStringId = t.iface([], {
"id": "string",
"fields": t.iface([], {
[t.indexKey]: "CellValue",
}),
});
export const AddOrUpdateRecord = t.iface([], {
"require": t.intersection(t.iface([], {
[t.indexKey]: "CellValue",
@@ -46,14 +60,41 @@ export const MinimalRecord = t.iface([], {
"id": "number",
});
export const ColumnsPost = t.iface([], {
"columns": t.tuple("NewRecordWithStringId", t.rest(t.array("NewRecordWithStringId"))),
});
export const ColumnsPatch = t.iface([], {
"columns": t.tuple("RecordWithStringId", t.rest(t.array("RecordWithStringId"))),
});
export const TablePost = t.iface(["ColumnsPost"], {
"id": t.opt("string"),
});
export const TablesPost = t.iface([], {
"tables": t.tuple("TablePost", t.rest(t.array("TablePost"))),
});
export const TablesPatch = t.iface([], {
"tables": t.tuple("RecordWithStringId", t.rest(t.array("RecordWithStringId"))),
});
const exportedTypeSuite: t.ITypeSuite = {
NewRecord,
NewRecordWithStringId,
Record,
RecordWithStringId,
AddOrUpdateRecord,
RecordsPatch,
RecordsPost,
RecordsPut,
RecordId,
MinimalRecord,
ColumnsPost,
ColumnsPatch,
TablePost,
TablesPost,
TablesPatch,
};
export default exportedTypeSuite;

View File

@@ -11,6 +11,15 @@ export interface NewRecord {
fields?: { [coldId: string]: CellValue };
}
export interface NewRecordWithStringId {
id?: string; // tableId or colId
/**
* Initial values of cells in record. Optional, if not set cells are left
* blank.
*/
fields?: { [coldId: string]: CellValue };
}
/**
* JSON schema for api /record endpoint. Used in PATCH method for updating existing records.
*/
@@ -19,6 +28,11 @@ export interface Record {
fields: { [coldId: string]: CellValue };
}
export interface RecordWithStringId {
id: string; // tableId or colId
fields: { [coldId: string]: CellValue };
}
/**
* JSON schema for api /record endpoint. Used in PUT method for adding or updating records.
*/
@@ -65,3 +79,27 @@ export type RecordId = number;
export interface MinimalRecord {
id: number
}
export interface ColumnsPost {
columns: [NewRecordWithStringId, ...NewRecordWithStringId[]]; // at least one column is required
}
export interface ColumnsPatch {
columns: [RecordWithStringId, ...RecordWithStringId[]]; // at least one column is required
}
/**
* Creating tables requires a list of columns.
* `fields` is not accepted because it's not generally sensible to set the metadata fields on new tables.
*/
export interface TablePost extends ColumnsPost {
id?: string;
}
export interface TablesPost {
tables: [TablePost, ...TablePost[]]; // at least one table is required
}
export interface TablesPatch {
tables: [RecordWithStringId, ...RecordWithStringId[]]; // at least one table is required
}

View File

@@ -199,7 +199,9 @@ export async function handleSandboxErrorOnPlatform<T>(
if (match) {
platform.throwError('', `Invalid row id ${match[1]}`, 400);
}
match = message.match(/\[Sandbox] KeyError u?'(?:Table \w+ has no column )?(\w+)'/);
match = message.match(
/\[Sandbox] (?:KeyError u?'(?:Table \w+ has no column )?|ValueError No such table: )(\w+)/
);
if (match) {
if (match[1] === tableId) {
platform.throwError('', `Table not found "${tableId}"`, 404);