type QueryParams = {
camelCase?: "true" | "false";
excludePattern?: string;
includePattern?: string;
runtimeEnums?: "true" | "false";
schema?: string;
typeOnlyImports?: "true" | "false";
tables: string;
};
const allowedTables: string[] = ["contacts"];
import { escape as escapeRegex } from "https://deno.land/std@0.221.0/regexp/escape.ts";
import * as codegen from "https://esm.sh/kysely-codegen@0.14.2?alias=git-diff:lodash.noop,pg:lodash.noop,fs:lodash.noop,mysql2:lodash.noop,kysely-bun-worker:lodash.noop,better-sqlite3:lodash.noop,@libsql/kysely-libsql:lodash.noop,dotenv:lodash.noop,dotenv-
import { VtDialect } from "https://esm.town/v/easrng/kyselyVtDialect";
import { Kysely } from "npm:kysely@^0.27.3";
class CodegenVtDialect extends codegen.Dialect {
readonly adapter: codegen.SqliteAdapter;
readonly introspector: codegen.SqliteDialect["introspector"];
constructor() {
super();
const d = new codegen.SqliteDialect();
this.adapter = d.adapter;
this.introspector = d.introspector;
}
async createKyselyDialect() {
return new VtDialect();
}
}
type GenerateOptions = {
camelCase?: boolean;
excludePattern?: string;
includePattern?: string;
runtimeEnums?: boolean;
schema?: string;
typeOnlyImports?: boolean;
tables: string[];
};
function parseOptions(params: URLSearchParams): GenerateOptions {
const camelCase = params.has("camelCase") ? params.get("camelCase") === "true" : undefined;
const excludePattern = params.get("excludePattern") ?? undefined;
const includePattern = params.get("includePattern") ?? undefined;
const runtimeEnums = params.has("runtimeEnums") ? params.get("runtimeEnums") === "true" : undefined;
const schema = params.get("schema") ?? undefined;
const typeOnlyImports = params.has("typeOnlyImports") ? params.get("typeOnlyImports") === "true" : undefined;
const tables = params.get("tables")?.split(",")?.map(e => e.trim()) ?? [];
return {
camelCase,
excludePattern,
includePattern,
runtimeEnums,
schema,
typeOnlyImports,
tables,
};
}
export default async function(req: Request): Promise<Response> {
const url = new URL(req.url);
if (url.pathname !== "/") return new Response(null, { status: 404 });
if (req.method !== "GET") return new Response(null, { status: 405 });
if (
[
"object",
"iframe",
"frame",
"fencedframe",
"embed",
"document",
].includes(req.headers.get("sec-fetch-dest"))
)
return new Response(
"This endpoint returns TypeScript. Usage:\n```ts\nimport type { DB } from " + JSON.stringify(req.url) + "\n```",
);
try {
const options = parseOptions(url.searchParams);
const notAllowed = [];
for (const table of options.tables) {
if (!allowedTables.includes(table)) {
notAllowed.push(table);
}
}
if (notAllowed.length > 0) {
throw new Error("some tables you requested are not public: " + notAllowed.join(", "));
}
const db = new Kysely({
dialect: new VtDialect(),
});
const dialectInstance = new CodegenVtDialect();
const metadata = await dialectInstance.introspector.introspect({
db: db,
includePattern: "{" + options.tables.map(e => e).join(",") + ",}",
});
const transformer = new codegen.Transformer();
const nodes = transformer.transform({
camelCase: !!options.camelCase,
defaultSchema: options.schema,
dialect: dialectInstance,
metadata,
runtimeEnums: !!options.runtimeEnums,
});