@ponder/client 0.9.0-next.1 → 0.9.0-next.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +37 -8
- package/dist/index.js +86 -24
- package/dist/index.js.map +1 -1
- package/package.json +7 -2
- package/src/index.ts +145 -22
- package/src/setDatabaseSchema.ts +0 -16
package/dist/index.d.ts
CHANGED
|
@@ -1,22 +1,51 @@
|
|
|
1
|
+
import { SQLWrapper, QueryWithTypings } from 'drizzle-orm';
|
|
2
|
+
export { and, asc, avg, avgDistinct, between, count, countDistinct, desc, eq, exists, gt, gte, ilike, inArray, isNotNull, isNull, like, lt, lte, max, min, ne, not, notBetween, notExists, notIlike, notInArray, notLike, or, relations, sql, sum, sumDistinct } from 'drizzle-orm';
|
|
1
3
|
import { PgRemoteDatabase } from 'drizzle-orm/pg-proxy';
|
|
2
|
-
export { and, asc, avg, avgDistinct, between, count, countDistinct, desc, eq, exists, gt, gte, inArray, isNotNull, isNull, like, lt, lte, max, min, ne, not, notBetween, notExists, notIlike, notInArray, or, relations, sql, sum, sumDistinct } from 'drizzle-orm';
|
|
3
4
|
export { alias, except, exceptAll, intersect, intersectAll, union, unionAll } from 'drizzle-orm/pg-core';
|
|
4
5
|
|
|
5
|
-
declare const setDatabaseSchema: <T extends {
|
|
6
|
-
[name: string]: unknown;
|
|
7
|
-
}>(schema: T, schemaName: string) => T;
|
|
8
|
-
|
|
9
6
|
type Schema = {
|
|
10
7
|
[name: string]: unknown;
|
|
11
8
|
};
|
|
12
9
|
type Prettify<T> = {
|
|
13
10
|
[K in keyof T]: T[K];
|
|
14
11
|
} & {};
|
|
12
|
+
type Status = {
|
|
13
|
+
[network: string]: {
|
|
14
|
+
block: {
|
|
15
|
+
number: number;
|
|
16
|
+
timestamp: number;
|
|
17
|
+
} | null;
|
|
18
|
+
ready: boolean;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
type ClientDb<schema extends Schema = Schema> = Prettify<Omit<PgRemoteDatabase<schema>, "insert" | "update" | "delete" | "transaction" | "refreshMaterializedView" | "_">>;
|
|
15
22
|
type Client<schema extends Schema = Schema> = {
|
|
16
|
-
|
|
23
|
+
/** Query the database. */
|
|
24
|
+
db: ClientDb<schema>;
|
|
25
|
+
/** Subscribe to live updates. */
|
|
26
|
+
live: <result>(queryFn: (db: ClientDb<schema>) => Promise<result>, onData: (result: result) => void, onError?: (error: Error) => void) => {
|
|
27
|
+
unsubscribe: () => void;
|
|
28
|
+
};
|
|
29
|
+
/** Get the status of all chains. */
|
|
30
|
+
getStatus: () => Promise<Status>;
|
|
17
31
|
};
|
|
18
|
-
declare const
|
|
32
|
+
declare const compileQuery: (query: SQLWrapper) => QueryWithTypings;
|
|
33
|
+
/**
|
|
34
|
+
* Create a client for querying Ponder apps.
|
|
35
|
+
*
|
|
36
|
+
* @param baseUrl - The URL of the Ponder app.
|
|
37
|
+
* @param schema - The schema of the Ponder app.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* import { createClient } from "@ponder/client";
|
|
42
|
+
* import * as schema from "../ponder.schema";
|
|
43
|
+
*
|
|
44
|
+
* const client = createClient("https://.../sql", { schema });
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
declare const createClient: <schema extends Schema>(baseUrl: string, { schema }: {
|
|
19
48
|
schema: schema;
|
|
20
49
|
}) => Client<schema>;
|
|
21
50
|
|
|
22
|
-
export { type Client,
|
|
51
|
+
export { type Client, type Status, compileQuery, createClient };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import { drizzle } from "drizzle-orm/pg-proxy";
|
|
3
|
+
import superjson from "superjson";
|
|
3
4
|
import {
|
|
4
5
|
sql,
|
|
5
6
|
eq,
|
|
@@ -17,6 +18,8 @@ import {
|
|
|
17
18
|
between,
|
|
18
19
|
notBetween,
|
|
19
20
|
like,
|
|
21
|
+
notLike,
|
|
22
|
+
ilike,
|
|
20
23
|
notIlike,
|
|
21
24
|
not,
|
|
22
25
|
asc,
|
|
@@ -42,32 +45,89 @@ import {
|
|
|
42
45
|
except,
|
|
43
46
|
exceptAll
|
|
44
47
|
} from "drizzle-orm/pg-core";
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
var getEventSource = async () => {
|
|
49
|
+
let SSE;
|
|
50
|
+
if (typeof window === "undefined") {
|
|
51
|
+
const undici = await import(
|
|
52
|
+
/* webpackIgnore: true */
|
|
53
|
+
"undici"
|
|
54
|
+
);
|
|
55
|
+
SSE = undici.EventSource;
|
|
56
|
+
} else {
|
|
57
|
+
SSE = EventSource;
|
|
54
58
|
}
|
|
55
|
-
return
|
|
59
|
+
return SSE;
|
|
56
60
|
};
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
61
|
+
var getUrl = (baseUrl, method, query) => {
|
|
62
|
+
const url = new URL(`${baseUrl}/${method}`);
|
|
63
|
+
if (query) {
|
|
64
|
+
url.searchParams.set("sql", superjson.stringify(query));
|
|
65
|
+
}
|
|
66
|
+
return url;
|
|
67
|
+
};
|
|
68
|
+
var noopDatabase = drizzle(() => Promise.resolve({ rows: [] }), {
|
|
69
|
+
casing: "snake_case"
|
|
70
|
+
});
|
|
71
|
+
var dialect = noopDatabase.dialect;
|
|
72
|
+
var compileQuery = (query) => {
|
|
73
|
+
return dialect.sqlToQuery(query.getSQL());
|
|
74
|
+
};
|
|
75
|
+
var createClient = (baseUrl, { schema }) => {
|
|
76
|
+
let sse;
|
|
77
|
+
let liveCount = 0;
|
|
78
|
+
const client = {
|
|
79
|
+
db: drizzle(
|
|
80
|
+
async (sql2, params, _, typings) => {
|
|
81
|
+
const builtQuery = { sql: sql2, params, typings };
|
|
82
|
+
const response = await fetch(getUrl(baseUrl, "db", builtQuery), {
|
|
83
|
+
method: "POST"
|
|
84
|
+
});
|
|
85
|
+
if (response.ok === false) {
|
|
86
|
+
const error = new Error(await response.text());
|
|
87
|
+
error.stack = void 0;
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
const result = await response.json();
|
|
91
|
+
return {
|
|
92
|
+
...result,
|
|
93
|
+
rows: result.rows.map((row) => Object.values(row))
|
|
94
|
+
};
|
|
95
|
+
},
|
|
96
|
+
{ schema, casing: "snake_case" }
|
|
97
|
+
),
|
|
98
|
+
live: (queryFn, onData, onError) => {
|
|
99
|
+
const addEventListeners = () => {
|
|
100
|
+
sse.addEventListener("message", () => {
|
|
101
|
+
queryFn(client.db).then(onData).catch(onError);
|
|
102
|
+
});
|
|
103
|
+
sse.addEventListener("error", () => {
|
|
104
|
+
onError?.(new Error("server disconnected"));
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
liveCount++;
|
|
108
|
+
if (sse === void 0) {
|
|
109
|
+
getEventSource().then((SSE) => {
|
|
110
|
+
sse = new SSE(getUrl(baseUrl, "live"));
|
|
111
|
+
addEventListeners();
|
|
112
|
+
});
|
|
113
|
+
} else {
|
|
114
|
+
addEventListeners();
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
unsubscribe: () => {
|
|
118
|
+
if (--liveCount === 0)
|
|
119
|
+
sse?.close();
|
|
120
|
+
}
|
|
121
|
+
};
|
|
67
122
|
},
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
123
|
+
getStatus: async () => {
|
|
124
|
+
const response = await fetch(getUrl(baseUrl, "status"), {
|
|
125
|
+
method: "POST"
|
|
126
|
+
});
|
|
127
|
+
return response.json();
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
return client;
|
|
71
131
|
};
|
|
72
132
|
export {
|
|
73
133
|
alias,
|
|
@@ -76,6 +136,7 @@ export {
|
|
|
76
136
|
avg,
|
|
77
137
|
avgDistinct,
|
|
78
138
|
between,
|
|
139
|
+
compileQuery,
|
|
79
140
|
count,
|
|
80
141
|
countDistinct,
|
|
81
142
|
createClient,
|
|
@@ -86,6 +147,7 @@ export {
|
|
|
86
147
|
exists,
|
|
87
148
|
gt,
|
|
88
149
|
gte,
|
|
150
|
+
ilike,
|
|
89
151
|
inArray,
|
|
90
152
|
intersect,
|
|
91
153
|
intersectAll,
|
|
@@ -102,9 +164,9 @@ export {
|
|
|
102
164
|
notExists,
|
|
103
165
|
notIlike,
|
|
104
166
|
notInArray,
|
|
167
|
+
notLike,
|
|
105
168
|
or,
|
|
106
169
|
relations,
|
|
107
|
-
setDatabaseSchema,
|
|
108
170
|
sql,
|
|
109
171
|
sum,
|
|
110
172
|
sumDistinct,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { QueryWithTypings, SQLWrapper } from \"drizzle-orm\";\nimport type { PgDialect } from \"drizzle-orm/pg-core\";\nimport { type PgRemoteDatabase, drizzle } from \"drizzle-orm/pg-proxy\";\nimport superjson from \"superjson\";\n\nconst getEventSource = async () => {\n let SSE: typeof EventSource;\n if (typeof window === \"undefined\") {\n const undici = await import(/* webpackIgnore: true */ \"undici\");\n // @ts-ignore\n SSE = undici.EventSource;\n } else {\n SSE = EventSource;\n }\n\n return SSE;\n};\n\ntype Schema = { [name: string]: unknown };\n\ntype Prettify<T> = {\n [K in keyof T]: T[K];\n} & {};\n\nexport type Status = {\n [network: string]: {\n block: { number: number; timestamp: number } | null;\n ready: boolean;\n };\n};\n\ntype ClientDb<schema extends Schema = Schema> = Prettify<\n Omit<\n PgRemoteDatabase<schema>,\n | \"insert\"\n | \"update\"\n | \"delete\"\n | \"transaction\"\n | \"refreshMaterializedView\"\n | \"_\"\n >\n>;\n\nexport type Client<schema extends Schema = Schema> = {\n /** Query the database. */\n db: ClientDb<schema>;\n /** Subscribe to live updates. */\n live: <result>(\n queryFn: (db: ClientDb<schema>) => Promise<result>,\n onData: (result: result) => void,\n onError?: (error: Error) => void,\n ) => {\n unsubscribe: () => void;\n };\n /** Get the status of all chains. */\n getStatus: () => Promise<Status>;\n};\n\nconst getUrl = (\n baseUrl: string,\n method: \"live\" | \"db\" | \"status\",\n query?: QueryWithTypings,\n) => {\n const url = new URL(`${baseUrl}/${method}`);\n if (query) {\n url.searchParams.set(\"sql\", superjson.stringify(query));\n }\n return url;\n};\n\nconst noopDatabase = drizzle(() => Promise.resolve({ rows: [] }), {\n casing: \"snake_case\",\n});\n\n// @ts-ignore\nconst dialect: PgDialect = noopDatabase.dialect;\n\nexport const compileQuery = (query: SQLWrapper) => {\n return dialect.sqlToQuery(query.getSQL());\n};\n\n/**\n * Create a client for querying Ponder apps.\n *\n * @param baseUrl - The URL of the Ponder app.\n * @param schema - The schema of the Ponder app.\n *\n * @example\n * ```ts\n * import { createClient } from \"@ponder/client\";\n * import * as schema from \"../ponder.schema\";\n *\n * const client = createClient(\"https://.../sql\", { schema });\n * ```\n */\nexport const createClient = <schema extends Schema>(\n baseUrl: string,\n { schema }: { schema: schema },\n): Client<schema> => {\n let sse: EventSource | undefined;\n let liveCount = 0;\n\n const client: Client<schema> = {\n db: drizzle(\n async (sql, params, _, typings) => {\n const builtQuery = { sql, params, typings };\n const response = await fetch(getUrl(baseUrl, \"db\", builtQuery), {\n method: \"POST\",\n });\n\n if (response.ok === false) {\n const error = new Error(await response.text());\n error.stack = undefined;\n throw error;\n }\n\n const result = await response.json();\n\n return {\n ...result,\n rows: result.rows.map((row: object) => Object.values(row)),\n };\n },\n { schema, casing: \"snake_case\" },\n ),\n live: (queryFn, onData, onError) => {\n const addEventListeners = () => {\n sse!.addEventListener(\"message\", () => {\n queryFn(client.db).then(onData).catch(onError);\n });\n\n sse!.addEventListener(\"error\", () => {\n onError?.(new Error(\"server disconnected\"));\n });\n };\n\n liveCount++;\n if (sse === undefined) {\n getEventSource().then((SSE) => {\n sse = new SSE(getUrl(baseUrl, \"live\"));\n addEventListeners();\n });\n } else {\n addEventListeners();\n }\n\n return {\n unsubscribe: () => {\n if (--liveCount === 0) sse?.close();\n },\n };\n },\n getStatus: async () => {\n const response = await fetch(getUrl(baseUrl, \"status\"), {\n method: \"POST\",\n });\n\n return response.json();\n },\n };\n\n return client;\n};\n\nexport {\n sql,\n eq,\n gt,\n gte,\n lt,\n lte,\n ne,\n isNull,\n isNotNull,\n inArray,\n notInArray,\n exists,\n notExists,\n between,\n notBetween,\n like,\n notLike,\n ilike,\n notIlike,\n not,\n asc,\n desc,\n and,\n or,\n count,\n countDistinct,\n avg,\n avgDistinct,\n sum,\n sumDistinct,\n max,\n min,\n relations,\n} from \"drizzle-orm\";\n\nexport {\n alias,\n union,\n unionAll,\n intersect,\n intersectAll,\n except,\n exceptAll,\n} from \"drizzle-orm/pg-core\";\n"],"mappings":"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","names":["sql"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ponder/client",
|
|
3
|
-
"version": "0.9.0-next.
|
|
3
|
+
"version": "0.9.0-next.11",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -26,6 +26,9 @@
|
|
|
26
26
|
"import": "./dist/index.js"
|
|
27
27
|
}
|
|
28
28
|
},
|
|
29
|
+
"browser": {
|
|
30
|
+
"undici": false
|
|
31
|
+
},
|
|
29
32
|
"peerDependencies": {
|
|
30
33
|
"typescript": ">=5.0.4"
|
|
31
34
|
},
|
|
@@ -35,7 +38,9 @@
|
|
|
35
38
|
}
|
|
36
39
|
},
|
|
37
40
|
"dependencies": {
|
|
38
|
-
"drizzle-orm": "0.36.4"
|
|
41
|
+
"drizzle-orm": "0.36.4",
|
|
42
|
+
"superjson": "^2.2.2",
|
|
43
|
+
"undici": "^7.2.0"
|
|
39
44
|
},
|
|
40
45
|
"devDependencies": {
|
|
41
46
|
"tsup": "^8.0.1"
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
1
|
+
import type { QueryWithTypings, SQLWrapper } from "drizzle-orm";
|
|
2
|
+
import type { PgDialect } from "drizzle-orm/pg-core";
|
|
1
3
|
import { type PgRemoteDatabase, drizzle } from "drizzle-orm/pg-proxy";
|
|
4
|
+
import superjson from "superjson";
|
|
5
|
+
|
|
6
|
+
const getEventSource = async () => {
|
|
7
|
+
let SSE: typeof EventSource;
|
|
8
|
+
if (typeof window === "undefined") {
|
|
9
|
+
const undici = await import(/* webpackIgnore: true */ "undici");
|
|
10
|
+
// @ts-ignore
|
|
11
|
+
SSE = undici.EventSource;
|
|
12
|
+
} else {
|
|
13
|
+
SSE = EventSource;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return SSE;
|
|
17
|
+
};
|
|
2
18
|
|
|
3
19
|
type Schema = { [name: string]: unknown };
|
|
4
20
|
|
|
@@ -6,37 +22,144 @@ type Prettify<T> = {
|
|
|
6
22
|
[K in keyof T]: T[K];
|
|
7
23
|
} & {};
|
|
8
24
|
|
|
25
|
+
export type Status = {
|
|
26
|
+
[network: string]: {
|
|
27
|
+
block: { number: number; timestamp: number } | null;
|
|
28
|
+
ready: boolean;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
type ClientDb<schema extends Schema = Schema> = Prettify<
|
|
33
|
+
Omit<
|
|
34
|
+
PgRemoteDatabase<schema>,
|
|
35
|
+
| "insert"
|
|
36
|
+
| "update"
|
|
37
|
+
| "delete"
|
|
38
|
+
| "transaction"
|
|
39
|
+
| "refreshMaterializedView"
|
|
40
|
+
| "_"
|
|
41
|
+
>
|
|
42
|
+
>;
|
|
43
|
+
|
|
9
44
|
export type Client<schema extends Schema = Schema> = {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
45
|
+
/** Query the database. */
|
|
46
|
+
db: ClientDb<schema>;
|
|
47
|
+
/** Subscribe to live updates. */
|
|
48
|
+
live: <result>(
|
|
49
|
+
queryFn: (db: ClientDb<schema>) => Promise<result>,
|
|
50
|
+
onData: (result: result) => void,
|
|
51
|
+
onError?: (error: Error) => void,
|
|
52
|
+
) => {
|
|
53
|
+
unsubscribe: () => void;
|
|
54
|
+
};
|
|
55
|
+
/** Get the status of all chains. */
|
|
56
|
+
getStatus: () => Promise<Status>;
|
|
21
57
|
};
|
|
22
58
|
|
|
59
|
+
const getUrl = (
|
|
60
|
+
baseUrl: string,
|
|
61
|
+
method: "live" | "db" | "status",
|
|
62
|
+
query?: QueryWithTypings,
|
|
63
|
+
) => {
|
|
64
|
+
const url = new URL(`${baseUrl}/${method}`);
|
|
65
|
+
if (query) {
|
|
66
|
+
url.searchParams.set("sql", superjson.stringify(query));
|
|
67
|
+
}
|
|
68
|
+
return url;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const noopDatabase = drizzle(() => Promise.resolve({ rows: [] }), {
|
|
72
|
+
casing: "snake_case",
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// @ts-ignore
|
|
76
|
+
const dialect: PgDialect = noopDatabase.dialect;
|
|
77
|
+
|
|
78
|
+
export const compileQuery = (query: SQLWrapper) => {
|
|
79
|
+
return dialect.sqlToQuery(query.getSQL());
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Create a client for querying Ponder apps.
|
|
84
|
+
*
|
|
85
|
+
* @param baseUrl - The URL of the Ponder app.
|
|
86
|
+
* @param schema - The schema of the Ponder app.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```ts
|
|
90
|
+
* import { createClient } from "@ponder/client";
|
|
91
|
+
* import * as schema from "../ponder.schema";
|
|
92
|
+
*
|
|
93
|
+
* const client = createClient("https://.../sql", { schema });
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
23
96
|
export const createClient = <schema extends Schema>(
|
|
24
|
-
|
|
97
|
+
baseUrl: string,
|
|
25
98
|
{ schema }: { schema: schema },
|
|
26
99
|
): Client<schema> => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
100
|
+
let sse: EventSource | undefined;
|
|
101
|
+
let liveCount = 0;
|
|
102
|
+
|
|
103
|
+
const client: Client<schema> = {
|
|
104
|
+
db: drizzle(
|
|
105
|
+
async (sql, params, _, typings) => {
|
|
106
|
+
const builtQuery = { sql, params, typings };
|
|
107
|
+
const response = await fetch(getUrl(baseUrl, "db", builtQuery), {
|
|
108
|
+
method: "POST",
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
if (response.ok === false) {
|
|
112
|
+
const error = new Error(await response.text());
|
|
113
|
+
error.stack = undefined;
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const result = await response.json();
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
...result,
|
|
121
|
+
rows: result.rows.map((row: object) => Object.values(row)),
|
|
122
|
+
};
|
|
123
|
+
},
|
|
124
|
+
{ schema, casing: "snake_case" },
|
|
125
|
+
),
|
|
126
|
+
live: (queryFn, onData, onError) => {
|
|
127
|
+
const addEventListeners = () => {
|
|
128
|
+
sse!.addEventListener("message", () => {
|
|
129
|
+
queryFn(client.db).then(onData).catch(onError);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
sse!.addEventListener("error", () => {
|
|
133
|
+
onError?.(new Error("server disconnected"));
|
|
134
|
+
});
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
liveCount++;
|
|
138
|
+
if (sse === undefined) {
|
|
139
|
+
getEventSource().then((SSE) => {
|
|
140
|
+
sse = new SSE(getUrl(baseUrl, "live"));
|
|
141
|
+
addEventListeners();
|
|
142
|
+
});
|
|
143
|
+
} else {
|
|
144
|
+
addEventListeners();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
unsubscribe: () => {
|
|
149
|
+
if (--liveCount === 0) sse?.close();
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
},
|
|
153
|
+
getStatus: async () => {
|
|
154
|
+
const response = await fetch(getUrl(baseUrl, "status"), {
|
|
30
155
|
method: "POST",
|
|
31
|
-
body: JSON.stringify({ sql, params, method, typings }),
|
|
32
156
|
});
|
|
33
157
|
|
|
34
|
-
return
|
|
158
|
+
return response.json();
|
|
35
159
|
},
|
|
36
|
-
|
|
37
|
-
);
|
|
160
|
+
};
|
|
38
161
|
|
|
39
|
-
return
|
|
162
|
+
return client;
|
|
40
163
|
};
|
|
41
164
|
|
|
42
165
|
export {
|
|
@@ -56,6 +179,8 @@ export {
|
|
|
56
179
|
between,
|
|
57
180
|
notBetween,
|
|
58
181
|
like,
|
|
182
|
+
notLike,
|
|
183
|
+
ilike,
|
|
59
184
|
notIlike,
|
|
60
185
|
not,
|
|
61
186
|
asc,
|
|
@@ -82,5 +207,3 @@ export {
|
|
|
82
207
|
except,
|
|
83
208
|
exceptAll,
|
|
84
209
|
} from "drizzle-orm/pg-core";
|
|
85
|
-
|
|
86
|
-
export { setDatabaseSchema } from "./setDatabaseSchema.js";
|
package/src/setDatabaseSchema.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { Table, is } from "drizzle-orm";
|
|
2
|
-
|
|
3
|
-
const Schema = Symbol.for("drizzle:Schema");
|
|
4
|
-
|
|
5
|
-
export const setDatabaseSchema = <T extends { [name: string]: unknown }>(
|
|
6
|
-
schema: T,
|
|
7
|
-
schemaName: string,
|
|
8
|
-
): T => {
|
|
9
|
-
for (const table of Object.values(schema)) {
|
|
10
|
-
if (is(table, Table)) {
|
|
11
|
-
// @ts-ignore
|
|
12
|
-
table[Schema] = schemaName;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
return schema;
|
|
16
|
-
};
|