209 lines
4.9 KiB
TypeScript
209 lines
4.9 KiB
TypeScript
// @deno-types="https://unpkg.com/pocketbase@0.12.0/dist/pocketbase.es.d.mts"
|
|
import { SchemaField } from "https://unpkg.com/pocketbase@0.12.0/dist/pocketbase.es.mjs";
|
|
import { RawCsvRow } from "../types/csv.ts";
|
|
import { RawJsonRow } from "../types/json.ts";
|
|
import {
|
|
POCKETBASE_TYPE,
|
|
PocketbaseRowSchema,
|
|
PocketbaseType,
|
|
} 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);
|
|
}
|
|
|
|
switch (schemaField.type) {
|
|
case POCKETBASE_TYPE.BOOL:
|
|
return POCKETBASE_TYPE.BOOL;
|
|
|
|
case POCKETBASE_TYPE.NUMBER:
|
|
return POCKETBASE_TYPE.NUMBER;
|
|
|
|
case POCKETBASE_TYPE.PLAIN_TEXT:
|
|
return POCKETBASE_TYPE.PLAIN_TEXT;
|
|
|
|
case POCKETBASE_TYPE.EMAIL:
|
|
return POCKETBASE_TYPE.EMAIL;
|
|
|
|
case POCKETBASE_TYPE.JSON:
|
|
return POCKETBASE_TYPE.JSON;
|
|
|
|
case POCKETBASE_TYPE.DATETIME:
|
|
return POCKETBASE_TYPE.DATETIME;
|
|
|
|
case POCKETBASE_TYPE.URL:
|
|
return POCKETBASE_TYPE.URL;
|
|
|
|
default:
|
|
console.error(
|
|
`%cPbTypeError: Unsupported type '${schemaField.type}'`,
|
|
"color: red",
|
|
);
|
|
Deno.exit(-2);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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 new SchemaField({
|
|
name,
|
|
type,
|
|
system: false,
|
|
required: false,
|
|
unique: false,
|
|
options: {},
|
|
});
|
|
case POCKETBASE_TYPE.NUMBER:
|
|
return new SchemaField({
|
|
name,
|
|
type,
|
|
system: false,
|
|
required: false,
|
|
unique: false,
|
|
options: {
|
|
min: null,
|
|
max: null,
|
|
},
|
|
});
|
|
case POCKETBASE_TYPE.PLAIN_TEXT:
|
|
return new SchemaField({
|
|
name,
|
|
type,
|
|
system: false,
|
|
required: false,
|
|
unique: false,
|
|
options: {
|
|
min: null,
|
|
max: null,
|
|
pattern: "",
|
|
},
|
|
});
|
|
case POCKETBASE_TYPE.EMAIL:
|
|
return new SchemaField({
|
|
name,
|
|
type,
|
|
system: false,
|
|
required: false,
|
|
unique: false,
|
|
options: {
|
|
min: null,
|
|
max: null,
|
|
},
|
|
});
|
|
case POCKETBASE_TYPE.JSON:
|
|
return new SchemaField({
|
|
name,
|
|
type,
|
|
system: false,
|
|
required: false,
|
|
unique: false,
|
|
options: {},
|
|
});
|
|
case POCKETBASE_TYPE.DATETIME:
|
|
return new SchemaField({
|
|
name,
|
|
type,
|
|
system: false,
|
|
required: false,
|
|
unique: false,
|
|
options: {
|
|
min: null,
|
|
max: null,
|
|
},
|
|
});
|
|
case POCKETBASE_TYPE.URL:
|
|
return new SchemaField({
|
|
name,
|
|
type,
|
|
system: false,
|
|
required: false,
|
|
unique: false,
|
|
options: {
|
|
exceptDomains: null,
|
|
onlyDomains: null,
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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",
|
|
): SchemaField[] {
|
|
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;
|
|
}
|