easrng/kyselyVtDialect

References

Referenced 5 times

Kysely type generator for @std/sqlite

Usage

  • Fork to your account.
  • Update allowedTables to expose any tables you'd like to import the schema of.
    This will make their schemas public!
  • Add import type { DB } from "https://yourusername-kyselyVtTypes.web.val.run/?tables=tables,you,need" to your program. See that QueryParams` type at the top? Add those to your URL to set more options.

Demo

See @easrng/kyselyVtDemo.

Readme
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
type QueryParams = {
camelCase?: "true" | "false";
excludePattern?: string;
includePattern?: string;
runtimeEnums?: "true" | "false";
schema?: string;
typeOnlyImports?: "true" | "false";
tables: string; // comma separated
};
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,
// this is a minimatch pattern, but the strings are not user-controlled so it should be ok
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,
});

Kysely on val.town

Uses @easrng/kyselyVtDialect as a Kysely Dialect and @easrng/kyselyVtTypes for type autogeneration.

Readme
1
2
3
4
5
6
7
8
9
10
11
import type { DB } from "https://easrng-kyselyvttypes.web.val.run/?tables=contacts";
import { VtDialect } from "https://esm.town/v/easrng/kyselyVtDialect";
import { Kysely } from "npm:kysely@0.27.3";
// ^ pinned version because val.town's editor doesn't
// load version ranges.
const db = new Kysely<DB>({
dialect: new VtDialect(),
});
const rows = await db.selectFrom("contacts").selectAll().execute();
// ^ { contact_id: number; email: string; first_name: string; ... }[]
console.log(rows);
1
2
3
4
5
6
7
8
9
10
11
import { VtDialect } from "https://esm.town/v/easrng/kyselyVtDialect";
import type { DB } from "https://nbbaier-kyselyVtTypes.web.val.run/?tables=users";
import { Kysely } from "npm:kysely@0.27.3";
// ^ pinned version because val.town's editor doesn't
// load version ranges.
const db = new Kysely<DB>({
dialect: new VtDialect(),
});
const rows = await db.selectFrom("users").selectAll().where("id", "=", "1").execute();
// ^ { contact_id: number; email: string; first_name: string; ... }[]
console.log(rows);

Kysely type generator for @std/sqlite

Usage

  • Fork to your account.
  • Update allowedTables to expose any tables you'd like to import the schema of.
    This will make their schemas public!
  • Add import type { DB } from "https://yourusername-kyselyVtTypes.web.val.run/?tables=tables,you,need" to your program. See that QueryParams` type at the top? Add those to your URL to set more options.

Demo

See @easrng/kyselyVtDemo.

Readme
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
type QueryParams = {
camelCase?: "true" | "false";
excludePattern?: string;
includePattern?: string;
runtimeEnums?: "true" | "false";
schema?: string;
typeOnlyImports?: "true" | "false";
tables: string; // comma separated
allowTables?: "true" | "false";
};
const allowedTables: string[] = [];
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[];
allowTables?: boolean;
};
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()) ?? [];
const allowTables = params.has("allowTables") ? params.get("allowTables") === "true" : undefined;
return {
camelCase,
excludePattern,
includePattern,
runtimeEnums,
schema,
typeOnlyImports,
tables,
allowTables,
};
}
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 (options.allowTables) { allowedTables.push(table); }
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,
// this is a minimatch pattern, but the strings are not user-controlled so it should be ok
includePattern: "{" + options.tables.map(e => e).join(",") + ",}",
});
const transformer = new codegen.Transformer();
const nodes = transformer.transform({
camelCase: !!options.camelCase,

Kysely on val.town

Uses @easrng/kyselyVtDialect as a Kysely Dialect and @easrng/kyselyVtTypes for type autogeneration.

Readme
1
2
3
4
5
6
7
8
9
10
11
import type { DB } from "https://easrng-kyselyvttypes.web.val.run/?tables=contacts";
import { VtDialect } from "https://esm.town/v/easrng/kyselyVtDialect";
import { Kysely } from "npm:kysely@0.27.3";
// ^ pinned version because val.town's editor doesn't
// load version ranges.
const db = new Kysely<DB>({
dialect: new VtDialect(),
});
const rows = await db.selectFrom("contacts").selectAll().execute();
// ^ { contact_id: number; email: string; first_name: string; ... }[]
console.log(rows);
1
Next