196 lines
4.5 KiB
TypeScript
196 lines
4.5 KiB
TypeScript
import { RawCsvRow } from "../types/csv.ts";
|
|
import { RawJsonRow } from "../types/json.ts";
|
|
import {
|
|
POCKETBASE_TYPE,
|
|
PocketbaseRowSchema,
|
|
PocketbaseType,
|
|
SchemaField,
|
|
BoolField,
|
|
NumberField,
|
|
TextField,
|
|
EmailField,
|
|
JsonField,
|
|
DateField,
|
|
UrlField
|
|
} from "../types/pocketbase.ts";
|
|
import { addSchemaField as addCsvSchemaField } from "./csv.ts";
|
|
import { addSchemaField as addJsonSchemaField } from "./json.ts";
|
|
|
|
/**
|
|
* Finds column's type in the schema.
|
|
* @param column Column name.
|
|
* @param schema PocketBase collection schema.
|
|
* @returns
|
|
*/
|
|
export function getSchemaType(
|
|
column: string,
|
|
schema: SchemaField[],
|
|
): PocketbaseType {
|
|
const schemaField = schema.find((field) => field.name === column);
|
|
|
|
// if somehow the data got structured wrong
|
|
if (schemaField === undefined) {
|
|
console.error(
|
|
`%cSchemaError: Supplied column '${column}' not found in collection schema`,
|
|
"color: red",
|
|
);
|
|
Deno.exit(-1);
|
|
return "text";
|
|
}
|
|
|
|
if (schemaField.type == null) {
|
|
console.error(
|
|
`%cSchemaError: Column type missing for '${column}'`,
|
|
"color: red",
|
|
);
|
|
Deno.exit(-1);
|
|
return "text";
|
|
}
|
|
|
|
return schemaField.type;
|
|
}
|
|
|
|
/**
|
|
* Builds a `SchemaField` object based on data type.
|
|
* @param name Column name.
|
|
* @param type PocketBase type.
|
|
* @returns
|
|
*/
|
|
export function createSchemaField(
|
|
name: string,
|
|
type: PocketbaseType,
|
|
): SchemaField {
|
|
switch (type) {
|
|
case POCKETBASE_TYPE.BOOL:
|
|
return {
|
|
hidden: false,
|
|
name,
|
|
presentable: false,
|
|
required: false,
|
|
system: false,
|
|
type,
|
|
} as BoolField;
|
|
case POCKETBASE_TYPE.NUMBER:
|
|
return {
|
|
hidden: false,
|
|
max: undefined,
|
|
min: undefined,
|
|
name,
|
|
onlyInt: false,
|
|
presentable: false,
|
|
required: false,
|
|
system: false,
|
|
type,
|
|
} as NumberField;
|
|
case POCKETBASE_TYPE.PLAIN_TEXT:
|
|
return {
|
|
autogeneratePattern: "",
|
|
hidden: false,
|
|
max: 0,
|
|
min: 0,
|
|
name,
|
|
pattern: "",
|
|
presentable: false,
|
|
primaryKey: false,
|
|
required: false,
|
|
system: false,
|
|
type,
|
|
} as TextField;
|
|
case POCKETBASE_TYPE.EMAIL:
|
|
return {
|
|
exceptDomains: undefined,
|
|
hidden: false,
|
|
name,
|
|
onlyDomains: undefined,
|
|
presentable: false,
|
|
required: false,
|
|
system: false,
|
|
type,
|
|
} as EmailField;
|
|
case POCKETBASE_TYPE.JSON:
|
|
return {
|
|
hidden: false,
|
|
maxSize: 0,
|
|
name,
|
|
presentable: false,
|
|
required: false,
|
|
system: false,
|
|
type,
|
|
} as JsonField;
|
|
case POCKETBASE_TYPE.DATETIME:
|
|
return {
|
|
hidden: false,
|
|
max: "",
|
|
min: "",
|
|
name,
|
|
presentable: false,
|
|
required: false,
|
|
system: false,
|
|
type,
|
|
} as DateField;
|
|
case POCKETBASE_TYPE.URL:
|
|
return {
|
|
hidden: false,
|
|
exceptDomains: undefined,
|
|
name,
|
|
onlyDomains: undefined,
|
|
presentable: false,
|
|
required: false,
|
|
system: false,
|
|
type,
|
|
} as UrlField;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates a row object schema from PocketBase collection schema.
|
|
* @param schema PocketBase collection schema.
|
|
* @returns
|
|
*/
|
|
export function generateRowSchema(schema: SchemaField[]): PocketbaseRowSchema {
|
|
let instance: PocketbaseRowSchema = {};
|
|
let fieldType: PocketbaseType;
|
|
|
|
schema.forEach((field) => {
|
|
fieldType = getSchemaType(field.name, schema);
|
|
instance = { ...instance, [field.name]: fieldType };
|
|
});
|
|
|
|
return instance;
|
|
}
|
|
|
|
/**
|
|
* Parses raw objects into PocketBase collection schema fields.
|
|
* @param data Raw input data.
|
|
* @returns
|
|
*/
|
|
// deno-lint-ignore no-explicit-any
|
|
export function createSchema(
|
|
data: { [key: string]: any },
|
|
stringifyId: boolean,
|
|
inputFormat: "csv" | "json",
|
|
) {
|
|
const schema: SchemaField[] = [];
|
|
|
|
// Seeks patterns in up to 1k records to avoid poor performance on large datasets
|
|
if (data.length > 1000) {
|
|
data = data.slice(0, 1000);
|
|
}
|
|
|
|
// Analyzes each column, deducts a type and creates a schema field
|
|
for (const prop in data[0]) {
|
|
// respect --id option
|
|
if (stringifyId && prop.toLowerCase() === "id") {
|
|
schema.push(createSchemaField(`_${prop}`, "text"));
|
|
} else {
|
|
schema.push(
|
|
inputFormat === "csv"
|
|
? addCsvSchemaField(data as RawCsvRow[], prop)
|
|
: addJsonSchemaField(data as RawJsonRow[], prop),
|
|
);
|
|
}
|
|
}
|
|
|
|
return schema;
|
|
}
|