mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-17 21:06:04 +00:00
postgres: added pg and postgres, and examples for xata and neon
This commit is contained in:
@@ -23,6 +23,12 @@ function hasColors() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const __consoles = {
|
const __consoles = {
|
||||||
|
critical: {
|
||||||
|
prefix: "CRT",
|
||||||
|
color: colors.red,
|
||||||
|
args_color: colors.red,
|
||||||
|
original: console.error,
|
||||||
|
},
|
||||||
error: {
|
error: {
|
||||||
prefix: "ERR",
|
prefix: "ERR",
|
||||||
color: colors.red,
|
color: colors.red,
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export function disableConsoleLog(severities: ConsoleSeverity[] = ["log", "warn"
|
|||||||
severities.forEach((severity) => {
|
severities.forEach((severity) => {
|
||||||
console[severity] = () => null;
|
console[severity] = () => null;
|
||||||
});
|
});
|
||||||
$console.setLevel("error");
|
$console.setLevel("critical");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function enableConsoleLog() {
|
export function enableConsoleLog() {
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import {
|
|||||||
type AliasableExpression,
|
type AliasableExpression,
|
||||||
type ColumnBuilderCallback,
|
type ColumnBuilderCallback,
|
||||||
type ColumnDataType,
|
type ColumnDataType,
|
||||||
|
type DatabaseIntrospector,
|
||||||
|
type Dialect,
|
||||||
type Expression,
|
type Expression,
|
||||||
type Kysely,
|
type Kysely,
|
||||||
type KyselyPlugin,
|
type KyselyPlugin,
|
||||||
@@ -12,7 +14,8 @@ import {
|
|||||||
type Simplify,
|
type Simplify,
|
||||||
sql,
|
sql,
|
||||||
} from "kysely";
|
} from "kysely";
|
||||||
import type { BaseIntrospector } from "./BaseIntrospector";
|
import type { BaseIntrospector, BaseIntrospectorConfig } from "./BaseIntrospector";
|
||||||
|
import type { Constructor } from "core";
|
||||||
|
|
||||||
export type QB = SelectQueryBuilder<any, any, any>;
|
export type QB = SelectQueryBuilder<any, any, any>;
|
||||||
|
|
||||||
@@ -159,3 +162,19 @@ export abstract class Connection<DB = any> {
|
|||||||
// no-op by default
|
// no-op by default
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function customIntrospector<T extends Constructor<Dialect>>(
|
||||||
|
dialect: T,
|
||||||
|
introspector: Constructor<DatabaseIntrospector>,
|
||||||
|
options: BaseIntrospectorConfig = {},
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
create(...args: ConstructorParameters<T>) {
|
||||||
|
return new (class extends dialect {
|
||||||
|
override createIntrospector(db: Kysely<any>): DatabaseIntrospector {
|
||||||
|
return new introspector(db, options);
|
||||||
|
}
|
||||||
|
})(...args);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ export {
|
|||||||
type IndexSpec,
|
type IndexSpec,
|
||||||
type DbFunctions,
|
type DbFunctions,
|
||||||
type SchemaResponse,
|
type SchemaResponse,
|
||||||
|
customIntrospector,
|
||||||
} from "./Connection";
|
} from "./Connection";
|
||||||
|
|
||||||
// sqlite
|
// sqlite
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ export class ModuleManager {
|
|||||||
const context = this.ctx(true);
|
const context = this.ctx(true);
|
||||||
|
|
||||||
for (const key in MODULES) {
|
for (const key in MODULES) {
|
||||||
const moduleConfig = key in initial ? initial[key] : {};
|
const moduleConfig = initial && key in initial ? initial[key] : {};
|
||||||
const module = new MODULES[key](moduleConfig, context) as Module;
|
const module = new MODULES[key](moduleConfig, context) as Module;
|
||||||
module.setListener(async (c) => {
|
module.setListener(async (c) => {
|
||||||
await this.onModuleConfigUpdated(key, c);
|
await this.onModuleConfigUpdated(key, c);
|
||||||
|
|||||||
65
bun.lock
65
bun.lock
@@ -27,7 +27,7 @@
|
|||||||
},
|
},
|
||||||
"app": {
|
"app": {
|
||||||
"name": "bknd",
|
"name": "bknd",
|
||||||
"version": "0.12.0",
|
"version": "0.13.0",
|
||||||
"bin": "./dist/cli/index.js",
|
"bin": "./dist/cli/index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cfworker/json-schema": "^4.1.1",
|
"@cfworker/json-schema": "^4.1.1",
|
||||||
@@ -149,19 +149,24 @@
|
|||||||
},
|
},
|
||||||
"packages/postgres": {
|
"packages/postgres": {
|
||||||
"name": "@bknd/postgres",
|
"name": "@bknd/postgres",
|
||||||
"version": "0.0.1",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
|
||||||
"kysely": "^0.27.6",
|
|
||||||
"pg": "^8.14.0",
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bun": "^1.2.5",
|
"@types/bun": "^1.2.5",
|
||||||
"@types/node": "^22.13.10",
|
"@types/node": "^22.13.10",
|
||||||
"@types/pg": "^8.11.11",
|
"@types/pg": "^8.11.11",
|
||||||
|
"@xata.io/client": "^0.0.0-next.v93343b9646f57a1e5c51c35eccf0767c2bb80baa",
|
||||||
|
"@xata.io/kysely": "^0.2.1",
|
||||||
"bknd": "workspace:*",
|
"bknd": "workspace:*",
|
||||||
|
"kysely-neon": "^1.3.0",
|
||||||
"tsup": "^8.4.0",
|
"tsup": "^8.4.0",
|
||||||
"typescript": "^5.8.2",
|
"typescript": "^5.8.2",
|
||||||
},
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"kysely": "^0.27.6",
|
||||||
|
"kysely-postgres-js": "^2.0.0",
|
||||||
|
"pg": "^8.14.0",
|
||||||
|
"postgres": "^3.4.7",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"packages/sqlocal": {
|
"packages/sqlocal": {
|
||||||
"name": "@bknd/sqlocal",
|
"name": "@bknd/sqlocal",
|
||||||
@@ -791,6 +796,8 @@
|
|||||||
|
|
||||||
"@neon-rs/load": ["@neon-rs/load@0.0.4", "", {}, "sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw=="],
|
"@neon-rs/load": ["@neon-rs/load@0.0.4", "", {}, "sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw=="],
|
||||||
|
|
||||||
|
"@neondatabase/serverless": ["@neondatabase/serverless@0.4.26", "", { "dependencies": { "@types/pg": "8.6.6" } }, "sha512-6DYEKos2GYn8NTgcJf33BLAx//LcgqzHVavQWe6ZkaDqmEq0I0Xtub6pzwFdq9iayNdCj7e2b0QKr5a8QKB8kQ=="],
|
||||||
|
|
||||||
"@next/env": ["@next/env@15.2.1", "", {}, "sha512-JmY0qvnPuS2NCWOz2bbby3Pe0VzdAQ7XpEB6uLIHmtXNfAsAO0KLQLkuAoc42Bxbo3/jMC3dcn9cdf+piCcG2Q=="],
|
"@next/env": ["@next/env@15.2.1", "", {}, "sha512-JmY0qvnPuS2NCWOz2bbby3Pe0VzdAQ7XpEB6uLIHmtXNfAsAO0KLQLkuAoc42Bxbo3/jMC3dcn9cdf+piCcG2Q=="],
|
||||||
|
|
||||||
"@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@15.2.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-aWXT+5KEREoy3K5AKtiKwioeblmOvFFjd+F3dVleLvvLiQ/mD//jOOuUcx5hzcO9ISSw4lrqtUPntTpK32uXXQ=="],
|
"@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@15.2.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-aWXT+5KEREoy3K5AKtiKwioeblmOvFFjd+F3dVleLvvLiQ/mD//jOOuUcx5hzcO9ISSw4lrqtUPntTpK32uXXQ=="],
|
||||||
@@ -1395,6 +1402,10 @@
|
|||||||
|
|
||||||
"@web3-storage/multipart-parser": ["@web3-storage/multipart-parser@1.0.0", "", {}, "sha512-BEO6al7BYqcnfX15W2cnGR+Q566ACXAT9UQykORCWW80lmkpWsnEob6zJS1ZVBKsSJC8+7vJkHwlp+lXG1UCdw=="],
|
"@web3-storage/multipart-parser": ["@web3-storage/multipart-parser@1.0.0", "", {}, "sha512-BEO6al7BYqcnfX15W2cnGR+Q566ACXAT9UQykORCWW80lmkpWsnEob6zJS1ZVBKsSJC8+7vJkHwlp+lXG1UCdw=="],
|
||||||
|
|
||||||
|
"@xata.io/client": ["@xata.io/client@0.0.0-next.v93343b9646f57a1e5c51c35eccf0767c2bb80baa", "", { "peerDependencies": { "typescript": ">=4.5" } }, "sha512-4Js4SAKwmmOPmZVIS1l2K8XVGGkUOi8L1jXuagDfeUX56n95wfA4xYMSmsVS0RLMmRWI4UM4bp5UcFJxwbFYGw=="],
|
||||||
|
|
||||||
|
"@xata.io/kysely": ["@xata.io/kysely@0.2.1", "", { "dependencies": { "@xata.io/client": "0.30.1" }, "peerDependencies": { "kysely": "*" } }, "sha512-0+WBcFkBSNEu11wVTyJyeNMOPUuolDKJMjXQr1nheHTNZLfsL0qKshTZOKIC/bGInjepGA7DQ/HFeKDHe5CDpA=="],
|
||||||
|
|
||||||
"@xyflow/react": ["@xyflow/react@12.4.4", "", { "dependencies": { "@xyflow/system": "0.0.52", "classcat": "^5.0.3", "zustand": "^4.4.0" }, "peerDependencies": { "react": ">=17", "react-dom": ">=17" } }, "sha512-9RZ9dgKZNJOlbrXXST5HPb5TcXPOIDGondjwcjDro44OQRPl1E0ZRPTeWPGaQtVjbg4WpR4BUYwOeshNI2TuVg=="],
|
"@xyflow/react": ["@xyflow/react@12.4.4", "", { "dependencies": { "@xyflow/system": "0.0.52", "classcat": "^5.0.3", "zustand": "^4.4.0" }, "peerDependencies": { "react": ">=17", "react-dom": ">=17" } }, "sha512-9RZ9dgKZNJOlbrXXST5HPb5TcXPOIDGondjwcjDro44OQRPl1E0ZRPTeWPGaQtVjbg4WpR4BUYwOeshNI2TuVg=="],
|
||||||
|
|
||||||
"@xyflow/system": ["@xyflow/system@0.0.52", "", { "dependencies": { "@types/d3-drag": "^3.0.7", "@types/d3-selection": "^3.0.10", "@types/d3-transition": "^3.0.8", "@types/d3-zoom": "^3.0.8", "d3-drag": "^3.0.0", "d3-selection": "^3.0.0", "d3-zoom": "^3.0.0" } }, "sha512-pJBMaoh/GEebIABWEIxAai0yf57dm+kH7J/Br+LnLFPuJL87Fhcmm4KFWd/bCUy/kCWUg+2/yFAGY0AUHRPOnQ=="],
|
"@xyflow/system": ["@xyflow/system@0.0.52", "", { "dependencies": { "@types/d3-drag": "^3.0.7", "@types/d3-selection": "^3.0.10", "@types/d3-transition": "^3.0.8", "@types/d3-zoom": "^3.0.8", "d3-drag": "^3.0.0", "d3-selection": "^3.0.0", "d3-zoom": "^3.0.0" } }, "sha512-pJBMaoh/GEebIABWEIxAai0yf57dm+kH7J/Br+LnLFPuJL87Fhcmm4KFWd/bCUy/kCWUg+2/yFAGY0AUHRPOnQ=="],
|
||||||
@@ -2543,6 +2554,10 @@
|
|||||||
|
|
||||||
"kysely-d1": ["kysely-d1@0.3.0", "", { "peerDependencies": { "kysely": "*" } }, "sha512-9wTbE6ooLiYtBa4wPg9e4fjfcmvRtgE/2j9pAjYrIq+iz+EsH/Hj9YbtxpEXA6JoRgfulVQ1EtGj6aycGGRpYw=="],
|
"kysely-d1": ["kysely-d1@0.3.0", "", { "peerDependencies": { "kysely": "*" } }, "sha512-9wTbE6ooLiYtBa4wPg9e4fjfcmvRtgE/2j9pAjYrIq+iz+EsH/Hj9YbtxpEXA6JoRgfulVQ1EtGj6aycGGRpYw=="],
|
||||||
|
|
||||||
|
"kysely-neon": ["kysely-neon@1.3.0", "", { "peerDependencies": { "@neondatabase/serverless": "^0.4.3", "kysely": "0.x.x", "ws": "^8.13.0" }, "optionalPeers": ["ws"] }, "sha512-CIIlbmqpIXVJDdBEYtEOwbmALag0jmqYrGfBeM4cHKb9AgBGs+X1SvXUZ8TqkDacQEqEZN2XtsDoUkcMIISjHw=="],
|
||||||
|
|
||||||
|
"kysely-postgres-js": ["kysely-postgres-js@2.0.0", "", { "peerDependencies": { "kysely": ">= 0.24.0 < 1", "postgres": ">= 3.4.0 < 4" } }, "sha512-R1tWx6/x3tSatWvsmbHJxpBZYhNNxcnMw52QzZaHKg7ZOWtHib4iZyEaw4gb2hNKVctWQ3jfMxZT/ZaEMK6kBQ=="],
|
||||||
|
|
||||||
"language-subtag-registry": ["language-subtag-registry@0.3.23", "", {}, "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ=="],
|
"language-subtag-registry": ["language-subtag-registry@0.3.23", "", {}, "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ=="],
|
||||||
|
|
||||||
"language-tags": ["language-tags@1.0.9", "", { "dependencies": { "language-subtag-registry": "^0.3.20" } }, "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA=="],
|
"language-tags": ["language-tags@1.0.9", "", { "dependencies": { "language-subtag-registry": "^0.3.20" } }, "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA=="],
|
||||||
@@ -2905,7 +2920,7 @@
|
|||||||
|
|
||||||
"pg-protocol": ["pg-protocol@1.8.0", "", {}, "sha512-jvuYlEkL03NRvOoyoRktBK7+qU5kOvlAwvmrH8sr3wbLrOdVWsRxQfz8mMy9sZFsqJ1hEWNfdWKI4SAmoL+j7g=="],
|
"pg-protocol": ["pg-protocol@1.8.0", "", {}, "sha512-jvuYlEkL03NRvOoyoRktBK7+qU5kOvlAwvmrH8sr3wbLrOdVWsRxQfz8mMy9sZFsqJ1hEWNfdWKI4SAmoL+j7g=="],
|
||||||
|
|
||||||
"pg-types": ["pg-types@4.0.2", "", { "dependencies": { "pg-int8": "1.0.1", "pg-numeric": "1.0.2", "postgres-array": "~3.0.1", "postgres-bytea": "~3.0.0", "postgres-date": "~2.1.0", "postgres-interval": "^3.0.0", "postgres-range": "^1.1.1" } }, "sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng=="],
|
"pg-types": ["pg-types@2.2.0", "", { "dependencies": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", "postgres-bytea": "~1.0.0", "postgres-date": "~1.0.4", "postgres-interval": "^1.1.0" } }, "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA=="],
|
||||||
|
|
||||||
"pgpass": ["pgpass@1.0.5", "", { "dependencies": { "split2": "^4.1.0" } }, "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug=="],
|
"pgpass": ["pgpass@1.0.5", "", { "dependencies": { "split2": "^4.1.0" } }, "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug=="],
|
||||||
|
|
||||||
@@ -2961,13 +2976,15 @@
|
|||||||
|
|
||||||
"postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="],
|
"postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="],
|
||||||
|
|
||||||
"postgres-array": ["postgres-array@3.0.4", "", {}, "sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ=="],
|
"postgres": ["postgres@3.4.7", "", {}, "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw=="],
|
||||||
|
|
||||||
"postgres-bytea": ["postgres-bytea@3.0.0", "", { "dependencies": { "obuf": "~1.1.2" } }, "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw=="],
|
"postgres-array": ["postgres-array@2.0.0", "", {}, "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="],
|
||||||
|
|
||||||
"postgres-date": ["postgres-date@2.1.0", "", {}, "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA=="],
|
"postgres-bytea": ["postgres-bytea@1.0.0", "", {}, "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w=="],
|
||||||
|
|
||||||
"postgres-interval": ["postgres-interval@3.0.0", "", {}, "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw=="],
|
"postgres-date": ["postgres-date@1.0.7", "", {}, "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q=="],
|
||||||
|
|
||||||
|
"postgres-interval": ["postgres-interval@1.2.0", "", { "dependencies": { "xtend": "^4.0.0" } }, "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ=="],
|
||||||
|
|
||||||
"postgres-range": ["postgres-range@1.1.4", "", {}, "sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w=="],
|
"postgres-range": ["postgres-range@1.1.4", "", {}, "sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w=="],
|
||||||
|
|
||||||
@@ -3847,8 +3864,6 @@
|
|||||||
|
|
||||||
"@babel/runtime/regenerator-runtime": ["regenerator-runtime@0.14.1", "", {}, "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="],
|
"@babel/runtime/regenerator-runtime": ["regenerator-runtime@0.14.1", "", {}, "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="],
|
||||||
|
|
||||||
"@bknd/postgres/@types/bun": ["@types/bun@1.2.5", "", { "dependencies": { "bun-types": "1.2.5" } }, "sha512-w2OZTzrZTVtbnJew1pdFmgV99H0/L+Pvw+z1P67HaR18MHOzYnTYOi6qzErhK8HyT+DB782ADVPPE92Xu2/Opg=="],
|
|
||||||
|
|
||||||
"@bundled-es-modules/cookie/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
|
"@bundled-es-modules/cookie/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
|
||||||
|
|
||||||
"@bundled-es-modules/tough-cookie/tough-cookie": ["tough-cookie@4.1.4", "", { "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", "universalify": "^0.2.0", "url-parse": "^1.5.3" } }, "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag=="],
|
"@bundled-es-modules/tough-cookie/tough-cookie": ["tough-cookie@4.1.4", "", { "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", "universalify": "^0.2.0", "url-parse": "^1.5.3" } }, "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag=="],
|
||||||
@@ -3909,6 +3924,8 @@
|
|||||||
|
|
||||||
"@libsql/kysely-libsql/@libsql/client": ["@libsql/client@0.8.1", "", { "dependencies": { "@libsql/core": "^0.8.1", "@libsql/hrana-client": "^0.6.2", "js-base64": "^3.7.5", "libsql": "^0.3.10", "promise-limit": "^2.7.0" } }, "sha512-xGg0F4iTDFpeBZ0r4pA6icGsYa5rG6RAG+i/iLDnpCAnSuTqEWMDdPlVseiq4Z/91lWI9jvvKKiKpovqJ1kZWA=="],
|
"@libsql/kysely-libsql/@libsql/client": ["@libsql/client@0.8.1", "", { "dependencies": { "@libsql/core": "^0.8.1", "@libsql/hrana-client": "^0.6.2", "js-base64": "^3.7.5", "libsql": "^0.3.10", "promise-limit": "^2.7.0" } }, "sha512-xGg0F4iTDFpeBZ0r4pA6icGsYa5rG6RAG+i/iLDnpCAnSuTqEWMDdPlVseiq4Z/91lWI9jvvKKiKpovqJ1kZWA=="],
|
||||||
|
|
||||||
|
"@neondatabase/serverless/@types/pg": ["@types/pg@8.6.6", "", { "dependencies": { "@types/node": "*", "pg-protocol": "*", "pg-types": "^2.2.0" } }, "sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw=="],
|
||||||
|
|
||||||
"@plasmicapp/query/swr": ["swr@1.3.0", "", { "peerDependencies": { "react": "^16.11.0 || ^17.0.0 || ^18.0.0" } }, "sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw=="],
|
"@plasmicapp/query/swr": ["swr@1.3.0", "", { "peerDependencies": { "react": "^16.11.0 || ^17.0.0 || ^18.0.0" } }, "sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw=="],
|
||||||
|
|
||||||
"@remix-run/node/cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="],
|
"@remix-run/node/cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="],
|
||||||
@@ -4065,6 +4082,8 @@
|
|||||||
|
|
||||||
"@types/jest/pretty-format": ["pretty-format@25.5.0", "", { "dependencies": { "@jest/types": "^25.5.0", "ansi-regex": "^5.0.0", "ansi-styles": "^4.0.0", "react-is": "^16.12.0" } }, "sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ=="],
|
"@types/jest/pretty-format": ["pretty-format@25.5.0", "", { "dependencies": { "@jest/types": "^25.5.0", "ansi-regex": "^5.0.0", "ansi-styles": "^4.0.0", "react-is": "^16.12.0" } }, "sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ=="],
|
||||||
|
|
||||||
|
"@types/pg/pg-types": ["pg-types@4.0.2", "", { "dependencies": { "pg-int8": "1.0.1", "pg-numeric": "1.0.2", "postgres-array": "~3.0.1", "postgres-bytea": "~3.0.0", "postgres-date": "~2.1.0", "postgres-interval": "^3.0.0", "postgres-range": "^1.1.1" } }, "sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng=="],
|
||||||
|
|
||||||
"@typescript-eslint/experimental-utils/eslint-utils": ["eslint-utils@2.1.0", "", { "dependencies": { "eslint-visitor-keys": "^1.1.0" } }, "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg=="],
|
"@typescript-eslint/experimental-utils/eslint-utils": ["eslint-utils@2.1.0", "", { "dependencies": { "eslint-visitor-keys": "^1.1.0" } }, "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg=="],
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
|
"@typescript-eslint/typescript-estree/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
|
||||||
@@ -4125,6 +4144,8 @@
|
|||||||
|
|
||||||
"@wdio/utils/decamelize": ["decamelize@6.0.0", "", {}, "sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA=="],
|
"@wdio/utils/decamelize": ["decamelize@6.0.0", "", {}, "sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA=="],
|
||||||
|
|
||||||
|
"@xata.io/kysely/@xata.io/client": ["@xata.io/client@0.30.1", "", { "peerDependencies": { "typescript": ">=4.5" } }, "sha512-dAzDPHmIfenVIpF39m1elmW5ngjWu2mO8ZqJBN7dmYdXr98uhPANfLdVZnc3mUNG+NH37LqY1dSO862hIo2oRw=="],
|
||||||
|
|
||||||
"accepts/negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="],
|
"accepts/negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="],
|
||||||
|
|
||||||
"acorn-globals/acorn": ["acorn@6.4.2", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ=="],
|
"acorn-globals/acorn": ["acorn@6.4.2", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ=="],
|
||||||
@@ -4467,8 +4488,6 @@
|
|||||||
|
|
||||||
"peek-stream/duplexify": ["duplexify@3.7.1", "", { "dependencies": { "end-of-stream": "^1.0.0", "inherits": "^2.0.1", "readable-stream": "^2.0.0", "stream-shift": "^1.0.0" } }, "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g=="],
|
"peek-stream/duplexify": ["duplexify@3.7.1", "", { "dependencies": { "end-of-stream": "^1.0.0", "inherits": "^2.0.1", "readable-stream": "^2.0.0", "stream-shift": "^1.0.0" } }, "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g=="],
|
||||||
|
|
||||||
"pg/pg-types": ["pg-types@2.2.0", "", { "dependencies": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", "postgres-bytea": "~1.0.0", "postgres-date": "~1.0.4", "postgres-interval": "^1.1.0" } }, "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA=="],
|
|
||||||
|
|
||||||
"playwright/fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="],
|
"playwright/fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="],
|
||||||
|
|
||||||
"pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],
|
"pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],
|
||||||
@@ -4741,6 +4760,14 @@
|
|||||||
|
|
||||||
"@types/jest/pretty-format/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],
|
"@types/jest/pretty-format/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],
|
||||||
|
|
||||||
|
"@types/pg/pg-types/postgres-array": ["postgres-array@3.0.4", "", {}, "sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ=="],
|
||||||
|
|
||||||
|
"@types/pg/pg-types/postgres-bytea": ["postgres-bytea@3.0.0", "", { "dependencies": { "obuf": "~1.1.2" } }, "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw=="],
|
||||||
|
|
||||||
|
"@types/pg/pg-types/postgres-date": ["postgres-date@2.1.0", "", {}, "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA=="],
|
||||||
|
|
||||||
|
"@types/pg/pg-types/postgres-interval": ["postgres-interval@3.0.0", "", {}, "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw=="],
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
|
"@typescript-eslint/typescript-estree/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
|
||||||
|
|
||||||
"@verdaccio/local-storage-legacy/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
|
"@verdaccio/local-storage-legacy/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
|
||||||
@@ -4929,14 +4956,6 @@
|
|||||||
|
|
||||||
"peek-stream/duplexify/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
|
"peek-stream/duplexify/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
|
||||||
|
|
||||||
"pg/pg-types/postgres-array": ["postgres-array@2.0.0", "", {}, "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="],
|
|
||||||
|
|
||||||
"pg/pg-types/postgres-bytea": ["postgres-bytea@1.0.0", "", {}, "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w=="],
|
|
||||||
|
|
||||||
"pg/pg-types/postgres-date": ["postgres-date@1.0.7", "", {}, "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q=="],
|
|
||||||
|
|
||||||
"pg/pg-types/postgres-interval": ["postgres-interval@1.2.0", "", { "dependencies": { "xtend": "^4.0.0" } }, "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ=="],
|
|
||||||
|
|
||||||
"progress-estimator/chalk/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="],
|
"progress-estimator/chalk/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="],
|
||||||
|
|
||||||
"progress-estimator/chalk/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="],
|
"progress-estimator/chalk/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="],
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
# Postgres adapter for `bknd` (experimental)
|
# Postgres adapter for `bknd` (experimental)
|
||||||
This packages adds an adapter to use a Postgres database with [`bknd`](https://github.com/bknd-io/bknd). It is based on [`pg`](https://github.com/brianc/node-postgres) and the driver included in [`kysely`](https://github.com/kysely-org/kysely).
|
This packages adds an adapter to use a Postgres database with [`bknd`](https://github.com/bknd-io/bknd). It works with both `pg` and `postgres` drivers, and supports custom postgres connections.
|
||||||
|
* works with any Postgres database (tested with Supabase, Neon, Xata, and RDS)
|
||||||
|
* choose between `pg` and `postgres` drivers
|
||||||
|
* create custom postgres connections with any kysely postgres dialect
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
Install the adapter with:
|
Install the adapter with:
|
||||||
@@ -7,44 +10,93 @@ Install the adapter with:
|
|||||||
npm install @bknd/postgres
|
npm install @bknd/postgres
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Using `pg` driver
|
||||||
|
Install the [`pg`](https://github.com/brianc/node-postgres) driver with:
|
||||||
|
```bash
|
||||||
|
npm install pg
|
||||||
|
```
|
||||||
|
|
||||||
Create a connection:
|
Create a connection:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { PostgresConnection } from "@bknd/postgres";
|
import { pg } from "@bknd/postgres";
|
||||||
|
|
||||||
const connection = new PostgresConnection({
|
// accepts `pg` configuration
|
||||||
|
const connection = pg({
|
||||||
host: "localhost",
|
host: "localhost",
|
||||||
port: 5432,
|
port: 5432,
|
||||||
user: "postgres",
|
user: "postgres",
|
||||||
password: "postgres",
|
password: "postgres",
|
||||||
database: "bknd",
|
database: "postgres",
|
||||||
|
});
|
||||||
|
|
||||||
|
// or with a connection string
|
||||||
|
const connection = pg({
|
||||||
|
connectionString: "postgres://postgres:postgres@localhost:5432/postgres",
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
Use the connection depending on which framework or runtime you are using. E.g., when using `createApp`, you can use the connection as follows:
|
## Using `postgres` driver
|
||||||
|
|
||||||
```ts
|
Install the [`postgres`](https://github.com/porsager/postgres) driver with:
|
||||||
import { createApp } from "bknd";
|
```bash
|
||||||
import { PostgresConnection } from "@bknd/postgres";
|
npm install postgres
|
||||||
|
|
||||||
const connection = new PostgresConnection();
|
|
||||||
const app = createApp({ connection });
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Or if you're using it with a framework, say Next.js, you can add the connection object to where you're initializating the app:
|
Create a connection:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
// e.g. in src/app/api/[[...bknd]]/route.ts
|
import { postgresJs } from "@bknd/postgres";
|
||||||
import { serve } from "bknd/adapter/nextjs";
|
|
||||||
import { PostgresConnection } from "@bknd/postgres";
|
|
||||||
|
|
||||||
const connection = new PostgresConnection();
|
// accepts `postgres` configuration
|
||||||
const handler = serve({
|
const connection = postgresJs("postgres://postgres:postgres@localhost:5432/postgres");
|
||||||
connection
|
|
||||||
})
|
|
||||||
|
|
||||||
// ...
|
|
||||||
```
|
```
|
||||||
|
|
||||||
For more information about how to integrate Next.js in general, check out the [Next.js documentation](https://docs.bknd.io/integration/nextjs).
|
## Using custom postgres dialects
|
||||||
|
|
||||||
|
You can create a custom kysely postgres dialect by using the `createCustomPostgresConnection` function.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { createCustomPostgresConnection } from "@bknd/postgres";
|
||||||
|
|
||||||
|
const connection = createCustomPostgresConnection(MyDialect)({
|
||||||
|
// your custom dialect configuration
|
||||||
|
supports: {
|
||||||
|
batching: true
|
||||||
|
},
|
||||||
|
excludeTables: ["my_table"],
|
||||||
|
plugins: [new MyKyselyPlugin()],
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom `neon` connection
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { createCustomPostgresConnection } from "@bknd/postgres";
|
||||||
|
import { NeonDialect } from "kysely-neon";
|
||||||
|
|
||||||
|
const connection = createCustomPostgresConnection(NeonDialect)({
|
||||||
|
connectionString: process.env.NEON,
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom `xata` connection
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { createCustomPostgresConnection } from "@bknd/postgres";
|
||||||
|
import { XataDialect } from "@xata.io/kysely";
|
||||||
|
import { buildClient } from "@xata.io/client";
|
||||||
|
|
||||||
|
const client = buildClient();
|
||||||
|
const xata = new client({
|
||||||
|
databaseURL: process.env.XATA_URL,
|
||||||
|
apiKey: process.env.XATA_API_KEY,
|
||||||
|
branch: process.env.XATA_BRANCH,
|
||||||
|
});
|
||||||
|
|
||||||
|
const connection = createCustomPostgresConnection(XataDialect, {
|
||||||
|
supports: {
|
||||||
|
batching: false,
|
||||||
|
},
|
||||||
|
})({ xata });
|
||||||
|
```
|
||||||
14
packages/postgres/examples/neon.ts
Normal file
14
packages/postgres/examples/neon.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { serve } from "bknd/adapter/bun";
|
||||||
|
import { createCustomPostgresConnection } from "../src";
|
||||||
|
import { NeonDialect } from "kysely-neon";
|
||||||
|
|
||||||
|
const neon = createCustomPostgresConnection(NeonDialect);
|
||||||
|
|
||||||
|
export default serve({
|
||||||
|
connection: neon({
|
||||||
|
connectionString: process.env.NEON,
|
||||||
|
}),
|
||||||
|
// ignore this, it's only required within this repository
|
||||||
|
// because bknd is installed via "workspace:*"
|
||||||
|
distPath: "../../app/dist",
|
||||||
|
});
|
||||||
24
packages/postgres/examples/xata.ts
Normal file
24
packages/postgres/examples/xata.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { serve } from "bknd/adapter/bun";
|
||||||
|
import { createCustomPostgresConnection } from "../src";
|
||||||
|
import { XataDialect } from "@xata.io/kysely";
|
||||||
|
import { buildClient } from "@xata.io/client";
|
||||||
|
|
||||||
|
const client = buildClient();
|
||||||
|
const xata = new client({
|
||||||
|
databaseURL: process.env.XATA_URL,
|
||||||
|
apiKey: process.env.XATA_API_KEY,
|
||||||
|
branch: process.env.XATA_BRANCH,
|
||||||
|
});
|
||||||
|
|
||||||
|
const connection = createCustomPostgresConnection(XataDialect, {
|
||||||
|
supports: {
|
||||||
|
batching: false,
|
||||||
|
},
|
||||||
|
})({ xata });
|
||||||
|
|
||||||
|
export default serve({
|
||||||
|
connection,
|
||||||
|
// ignore this, it's only required within this repository
|
||||||
|
// because bknd is installed via "workspace:*"
|
||||||
|
distPath: "../../../app/dist",
|
||||||
|
});
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@bknd/postgres",
|
"name": "@bknd/postgres",
|
||||||
"version": "0.0.1",
|
"version": "0.1.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"module": "dist/index.js",
|
"module": "dist/index.js",
|
||||||
@@ -17,15 +17,20 @@
|
|||||||
"docker:start": "docker run --rm --name bknd-test-postgres -d -e POSTGRES_PASSWORD=postgres -e POSTGRES_USER=postgres -e POSTGRES_DB=bknd -p 5430:5432 postgres:17",
|
"docker:start": "docker run --rm --name bknd-test-postgres -d -e POSTGRES_PASSWORD=postgres -e POSTGRES_USER=postgres -e POSTGRES_DB=bknd -p 5430:5432 postgres:17",
|
||||||
"docker:stop": "docker stop bknd-test-postgres"
|
"docker:stop": "docker stop bknd-test-postgres"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"optionalDependencies": {
|
||||||
|
"kysely": "^0.27.6",
|
||||||
|
"kysely-postgres-js": "^2.0.0",
|
||||||
"pg": "^8.14.0",
|
"pg": "^8.14.0",
|
||||||
"kysely": "^0.27.6"
|
"postgres": "^3.4.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bun": "^1.2.5",
|
"@types/bun": "^1.2.5",
|
||||||
"@types/node": "^22.13.10",
|
"@types/node": "^22.13.10",
|
||||||
"@types/pg": "^8.11.11",
|
"@types/pg": "^8.11.11",
|
||||||
|
"@xata.io/client": "^0.0.0-next.v93343b9646f57a1e5c51c35eccf0767c2bb80baa",
|
||||||
|
"@xata.io/kysely": "^0.2.1",
|
||||||
"bknd": "workspace:*",
|
"bknd": "workspace:*",
|
||||||
|
"kysely-neon": "^1.3.0",
|
||||||
"tsup": "^8.4.0",
|
"tsup": "^8.4.0",
|
||||||
"typescript": "^5.8.2"
|
"typescript": "^5.8.2"
|
||||||
},
|
},
|
||||||
@@ -36,7 +41,7 @@
|
|||||||
"clean": true,
|
"clean": true,
|
||||||
"minify": true,
|
"minify": true,
|
||||||
"dts": true,
|
"dts": true,
|
||||||
"external": ["bknd", "pg", "kysely"]
|
"external": ["bknd", "pg", "kysely", "kysely-postgres-js"]
|
||||||
},
|
},
|
||||||
"files": ["dist", "README.md", "!*.map", "!metafile*.json"]
|
"files": ["dist", "README.md", "!*.map", "!metafile*.json"]
|
||||||
}
|
}
|
||||||
|
|||||||
32
packages/postgres/src/PgPostgresConnection.ts
Normal file
32
packages/postgres/src/PgPostgresConnection.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { Kysely, PostgresDialect } from "kysely";
|
||||||
|
import { PostgresIntrospector } from "./PostgresIntrospector";
|
||||||
|
import { PostgresConnection, plugins } from "./PostgresConnection";
|
||||||
|
import { customIntrospector } from "bknd/data";
|
||||||
|
import $pg from "pg";
|
||||||
|
|
||||||
|
export type PgPostgresConnectionConfig = $pg.PoolConfig;
|
||||||
|
|
||||||
|
export class PgPostgresConnection extends PostgresConnection {
|
||||||
|
private pool: $pg.Pool;
|
||||||
|
|
||||||
|
constructor(config: PgPostgresConnectionConfig) {
|
||||||
|
const pool = new $pg.Pool(config);
|
||||||
|
const kysely = new Kysely({
|
||||||
|
dialect: customIntrospector(PostgresDialect, PostgresIntrospector, {
|
||||||
|
excludeTables: [],
|
||||||
|
}).create({ pool }),
|
||||||
|
plugins,
|
||||||
|
});
|
||||||
|
|
||||||
|
super(kysely);
|
||||||
|
this.pool = pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
override async close(): Promise<void> {
|
||||||
|
await this.pool.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function pg(config: PgPostgresConnectionConfig): PgPostgresConnection {
|
||||||
|
return new PgPostgresConnection(config);
|
||||||
|
}
|
||||||
@@ -1,56 +1,33 @@
|
|||||||
import { Connection, type FieldSpec, type SchemaResponse } from "bknd/data";
|
import { Connection, type DbFunctions, type FieldSpec, type SchemaResponse } from "bknd/data";
|
||||||
import {
|
import {
|
||||||
|
ParseJSONResultsPlugin,
|
||||||
type ColumnDataType,
|
type ColumnDataType,
|
||||||
type ColumnDefinitionBuilder,
|
type ColumnDefinitionBuilder,
|
||||||
type DatabaseIntrospector,
|
type Kysely,
|
||||||
Kysely,
|
type KyselyPlugin,
|
||||||
ParseJSONResultsPlugin,
|
|
||||||
PostgresDialect,
|
|
||||||
type SelectQueryBuilder,
|
type SelectQueryBuilder,
|
||||||
} from "kysely";
|
} from "kysely";
|
||||||
import { jsonArrayFrom, jsonBuildObject, jsonObjectFrom } from "kysely/helpers/postgres";
|
import { jsonArrayFrom, jsonBuildObject, jsonObjectFrom } from "kysely/helpers/postgres";
|
||||||
import pg from "pg";
|
|
||||||
import { PostgresIntrospector } from "./PostgresIntrospector";
|
|
||||||
|
|
||||||
export type PostgresConnectionConfig = pg.PoolConfig;
|
|
||||||
export type QB = SelectQueryBuilder<any, any, any>;
|
export type QB = SelectQueryBuilder<any, any, any>;
|
||||||
|
|
||||||
const plugins = [new ParseJSONResultsPlugin()];
|
export const plugins = [new ParseJSONResultsPlugin()];
|
||||||
|
|
||||||
class CustomPostgresDialect extends PostgresDialect {
|
export abstract class PostgresConnection<DB = any> extends Connection<DB> {
|
||||||
override createIntrospector(db: Kysely<any>): DatabaseIntrospector {
|
|
||||||
return new PostgresIntrospector(db, {
|
|
||||||
excludeTables: [],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class PostgresConnection extends Connection {
|
|
||||||
protected override readonly supported = {
|
protected override readonly supported = {
|
||||||
batching: true,
|
batching: true,
|
||||||
};
|
};
|
||||||
private pool: pg.Pool;
|
|
||||||
|
|
||||||
constructor(config: PostgresConnectionConfig) {
|
|
||||||
const pool = new pg.Pool(config);
|
|
||||||
const kysely = new Kysely({
|
|
||||||
dialect: new CustomPostgresDialect({
|
|
||||||
pool,
|
|
||||||
}),
|
|
||||||
plugins,
|
|
||||||
//log: ["query", "error"],
|
|
||||||
});
|
|
||||||
|
|
||||||
|
constructor(kysely: Kysely<DB>, fn?: Partial<DbFunctions>, _plugins?: KyselyPlugin[]) {
|
||||||
super(
|
super(
|
||||||
kysely,
|
kysely,
|
||||||
{
|
fn ?? {
|
||||||
jsonArrayFrom,
|
jsonArrayFrom,
|
||||||
jsonBuildObject,
|
jsonBuildObject,
|
||||||
jsonObjectFrom,
|
jsonObjectFrom,
|
||||||
},
|
},
|
||||||
plugins,
|
_plugins ?? plugins,
|
||||||
);
|
);
|
||||||
this.pool = pool;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override getFieldSchema(spec: FieldSpec): SchemaResponse {
|
override getFieldSchema(spec: FieldSpec): SchemaResponse {
|
||||||
@@ -90,10 +67,6 @@ export class PostgresConnection extends Connection {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
override async close(): Promise<void> {
|
|
||||||
await this.pool.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override async batch<Queries extends QB[]>(
|
protected override async batch<Queries extends QB[]>(
|
||||||
queries: [...Queries],
|
queries: [...Queries],
|
||||||
): Promise<{
|
): Promise<{
|
||||||
|
|||||||
41
packages/postgres/src/PostgresJsConnection.ts
Normal file
41
packages/postgres/src/PostgresJsConnection.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { Kysely } from "kysely";
|
||||||
|
import { PostgresIntrospector } from "./PostgresIntrospector";
|
||||||
|
import { PostgresConnection, plugins } from "./PostgresConnection";
|
||||||
|
import { customIntrospector } from "bknd/data";
|
||||||
|
import { PostgresJSDialect } from "kysely-postgres-js";
|
||||||
|
import $postgresJs, { type Sql, type Options, type PostgresType } from "postgres";
|
||||||
|
|
||||||
|
export type PostgresJsConfig = Options<Record<string, PostgresType>>;
|
||||||
|
|
||||||
|
export class PostgresJsConnection extends PostgresConnection {
|
||||||
|
private postgres: Sql;
|
||||||
|
|
||||||
|
constructor(opts: { postgres: Sql }) {
|
||||||
|
const kysely = new Kysely({
|
||||||
|
dialect: customIntrospector(PostgresJSDialect, PostgresIntrospector, {
|
||||||
|
excludeTables: [],
|
||||||
|
}).create({ postgres: opts.postgres }),
|
||||||
|
plugins,
|
||||||
|
});
|
||||||
|
|
||||||
|
super(kysely);
|
||||||
|
this.postgres = opts.postgres;
|
||||||
|
}
|
||||||
|
|
||||||
|
override async close(): Promise<void> {
|
||||||
|
await this.postgres.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function postgresJs(
|
||||||
|
connectionString: string,
|
||||||
|
config?: PostgresJsConfig,
|
||||||
|
): PostgresJsConnection;
|
||||||
|
export function postgresJs(config: PostgresJsConfig): PostgresJsConnection;
|
||||||
|
export function postgresJs(
|
||||||
|
first: PostgresJsConfig | string,
|
||||||
|
second?: PostgresJsConfig,
|
||||||
|
): PostgresJsConnection {
|
||||||
|
const postgres = typeof first === "string" ? $postgresJs(first, second) : $postgresJs(first);
|
||||||
|
return new PostgresJsConnection({ postgres });
|
||||||
|
}
|
||||||
43
packages/postgres/src/custom.ts
Normal file
43
packages/postgres/src/custom.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import type { Constructor } from "bknd/core";
|
||||||
|
import { customIntrospector, type DbFunctions } from "bknd/data";
|
||||||
|
import { Kysely, type Dialect, type KyselyPlugin } from "kysely";
|
||||||
|
import { plugins, PostgresConnection } from "./PostgresConnection";
|
||||||
|
import { PostgresIntrospector } from "./PostgresIntrospector";
|
||||||
|
|
||||||
|
export type CustomPostgresConnection = {
|
||||||
|
supports?: PostgresConnection["supported"];
|
||||||
|
fn?: Partial<DbFunctions>;
|
||||||
|
plugins?: KyselyPlugin[];
|
||||||
|
excludeTables?: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export function createCustomPostgresConnection<
|
||||||
|
T extends Constructor<Dialect>,
|
||||||
|
C extends ConstructorParameters<T>[0],
|
||||||
|
>(
|
||||||
|
dialect: Constructor<Dialect>,
|
||||||
|
options?: CustomPostgresConnection,
|
||||||
|
): (config: C) => PostgresConnection<any> {
|
||||||
|
const supported = {
|
||||||
|
batching: true,
|
||||||
|
...((options?.supports ?? {}) as any),
|
||||||
|
};
|
||||||
|
|
||||||
|
return (config: C) =>
|
||||||
|
new (class extends PostgresConnection<any> {
|
||||||
|
protected override readonly supported = supported;
|
||||||
|
|
||||||
|
constructor(config: C) {
|
||||||
|
super(
|
||||||
|
new Kysely({
|
||||||
|
dialect: customIntrospector(dialect, PostgresIntrospector, {
|
||||||
|
excludeTables: options?.excludeTables ?? [],
|
||||||
|
}).create(config),
|
||||||
|
plugins: options?.plugins ?? plugins,
|
||||||
|
}),
|
||||||
|
options?.fn,
|
||||||
|
options?.plugins,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})(config);
|
||||||
|
}
|
||||||
@@ -1,2 +1,5 @@
|
|||||||
export { PostgresConnection, type PostgresConnectionConfig } from "./PostgresConnection";
|
export { pg, PgPostgresConnection, type PgPostgresConnectionConfig } from "./PgPostgresConnection";
|
||||||
export { PostgresIntrospector } from "./PostgresIntrospector";
|
export { PostgresIntrospector } from "./PostgresIntrospector";
|
||||||
|
export { PostgresConnection, type QB, plugins } from "./PostgresConnection";
|
||||||
|
export { postgresJs, PostgresJsConnection, type PostgresJsConfig } from "./PostgresJsConnection";
|
||||||
|
export { createCustomPostgresConnection } from "./custom";
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
import { describe, it, expect } from "bun:test";
|
|
||||||
|
|
||||||
import { PostgresConnection } from "../src";
|
|
||||||
import { createConnection, cleanDatabase } from "./setup";
|
|
||||||
|
|
||||||
describe(PostgresConnection, () => {
|
|
||||||
it("should connect to the database", async () => {
|
|
||||||
const connection = createConnection();
|
|
||||||
expect(await connection.ping()).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should clean the database", async () => {
|
|
||||||
const connection = createConnection();
|
|
||||||
await cleanDatabase(connection);
|
|
||||||
|
|
||||||
const tables = await connection.getIntrospector().getTables();
|
|
||||||
expect(tables).toEqual([]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
import { describe, it, expect, beforeAll, afterAll, afterEach } from "bun:test";
|
|
||||||
|
|
||||||
import { createApp } from "bknd";
|
|
||||||
import * as proto from "bknd/data";
|
|
||||||
|
|
||||||
import { createConnection, cleanDatabase } from "./setup";
|
|
||||||
import type { PostgresConnection } from "../src";
|
|
||||||
|
|
||||||
let connection: PostgresConnection;
|
|
||||||
beforeAll(async () => {
|
|
||||||
connection = createConnection();
|
|
||||||
await cleanDatabase(connection);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
await cleanDatabase(connection);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async () => {
|
|
||||||
await connection.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("integration", () => {
|
|
||||||
it("should create app and ping", async () => {
|
|
||||||
const app = createApp({
|
|
||||||
connection,
|
|
||||||
});
|
|
||||||
await app.build();
|
|
||||||
|
|
||||||
expect(app.version()).toBeDefined();
|
|
||||||
expect(await app.em.ping()).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should create a basic schema", async () => {
|
|
||||||
const schema = proto.em(
|
|
||||||
{
|
|
||||||
posts: proto.entity("posts", {
|
|
||||||
title: proto.text().required(),
|
|
||||||
content: proto.text(),
|
|
||||||
}),
|
|
||||||
comments: proto.entity("comments", {
|
|
||||||
content: proto.text(),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
(fns, s) => {
|
|
||||||
fns.relation(s.comments).manyToOne(s.posts);
|
|
||||||
fns.index(s.posts).on(["title"], true);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const app = createApp({
|
|
||||||
connection,
|
|
||||||
initialConfig: {
|
|
||||||
data: schema.toJSON(),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
await app.build();
|
|
||||||
|
|
||||||
expect(app.em.entities.length).toBe(2);
|
|
||||||
expect(app.em.entities.map((e) => e.name)).toEqual(["posts", "comments"]);
|
|
||||||
|
|
||||||
const api = app.getApi();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
(
|
|
||||||
await api.data.createMany("posts", [
|
|
||||||
{
|
|
||||||
title: "Hello",
|
|
||||||
content: "World",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Hello 2",
|
|
||||||
content: "World 2",
|
|
||||||
},
|
|
||||||
])
|
|
||||||
).data,
|
|
||||||
).toEqual([
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
title: "Hello",
|
|
||||||
content: "World",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
title: "Hello 2",
|
|
||||||
content: "World 2",
|
|
||||||
},
|
|
||||||
] as any);
|
|
||||||
|
|
||||||
// try to create an existing
|
|
||||||
expect(
|
|
||||||
(
|
|
||||||
await api.data.createOne("posts", {
|
|
||||||
title: "Hello",
|
|
||||||
})
|
|
||||||
).ok,
|
|
||||||
).toBe(false);
|
|
||||||
|
|
||||||
// add a comment to a post
|
|
||||||
await api.data.createOne("comments", {
|
|
||||||
content: "Hello",
|
|
||||||
posts_id: 1,
|
|
||||||
});
|
|
||||||
|
|
||||||
// and then query using a `with` property
|
|
||||||
const result = await api.data.readMany("posts", { with: ["comments"] });
|
|
||||||
expect(result.length).toBe(2);
|
|
||||||
expect(result[0].comments.length).toBe(1);
|
|
||||||
expect(result[0].comments[0].content).toBe("Hello");
|
|
||||||
expect(result[1].comments.length).toBe(0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
16
packages/postgres/test/pg.test.ts
Normal file
16
packages/postgres/test/pg.test.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { describe } from "bun:test";
|
||||||
|
import { pg } from "../src/PgPostgresConnection";
|
||||||
|
import { testSuite } from "./suite";
|
||||||
|
|
||||||
|
describe("pg", () => {
|
||||||
|
testSuite({
|
||||||
|
createConnection: () =>
|
||||||
|
pg({
|
||||||
|
host: "localhost",
|
||||||
|
port: 5430,
|
||||||
|
user: "postgres",
|
||||||
|
password: "postgres",
|
||||||
|
database: "bknd",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
});
|
||||||
16
packages/postgres/test/postgresjs.test.ts
Normal file
16
packages/postgres/test/postgresjs.test.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { describe } from "bun:test";
|
||||||
|
import { postgresJs } from "../src/PostgresJsConnection";
|
||||||
|
import { testSuite } from "./suite";
|
||||||
|
|
||||||
|
describe("postgresjs", () => {
|
||||||
|
testSuite({
|
||||||
|
createConnection: () =>
|
||||||
|
postgresJs({
|
||||||
|
host: "localhost",
|
||||||
|
port: 5430,
|
||||||
|
user: "postgres",
|
||||||
|
password: "postgres",
|
||||||
|
database: "bknd",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import type { Kysely } from "kysely";
|
|
||||||
import { PostgresConnection, PostgresIntrospector, type PostgresConnectionConfig } from "../src";
|
|
||||||
|
|
||||||
export const info = {
|
|
||||||
host: "localhost",
|
|
||||||
port: 5430,
|
|
||||||
user: "postgres",
|
|
||||||
password: "postgres",
|
|
||||||
database: "bknd",
|
|
||||||
};
|
|
||||||
|
|
||||||
export function createConnection(config: PostgresConnectionConfig = {}) {
|
|
||||||
return new PostgresConnection({
|
|
||||||
...info,
|
|
||||||
...config,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function cleanDatabase(connection: PostgresConnection) {
|
|
||||||
const kysely = connection.kysely;
|
|
||||||
|
|
||||||
// drop all tables & create new schema
|
|
||||||
await kysely.schema.dropSchema("public").ifExists().cascade().execute();
|
|
||||||
await kysely.schema.createSchema("public").execute();
|
|
||||||
}
|
|
||||||
155
packages/postgres/test/suite.ts
Normal file
155
packages/postgres/test/suite.ts
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
import { describe, beforeAll, afterAll, expect, it, afterEach } from "bun:test";
|
||||||
|
import type { PostgresConnection } from "../src";
|
||||||
|
import { createApp } from "bknd";
|
||||||
|
import * as proto from "bknd/data";
|
||||||
|
import { disableConsoleLog, enableConsoleLog } from "bknd/utils";
|
||||||
|
|
||||||
|
export type TestSuiteConfig = {
|
||||||
|
createConnection: () => InstanceType<typeof PostgresConnection>;
|
||||||
|
cleanDatabase?: (connection: InstanceType<typeof PostgresConnection>) => Promise<void>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function defaultCleanDatabase(connection: InstanceType<typeof PostgresConnection>) {
|
||||||
|
const kysely = connection.kysely;
|
||||||
|
|
||||||
|
// drop all tables & create new schema
|
||||||
|
await kysely.schema.dropSchema("public").ifExists().cascade().execute();
|
||||||
|
await kysely.schema.createSchema("public").execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function cleanDatabase(
|
||||||
|
connection: InstanceType<typeof PostgresConnection>,
|
||||||
|
config: TestSuiteConfig,
|
||||||
|
) {
|
||||||
|
if (config.cleanDatabase) {
|
||||||
|
await config.cleanDatabase(connection);
|
||||||
|
} else {
|
||||||
|
await defaultCleanDatabase(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function testSuite(config: TestSuiteConfig) {
|
||||||
|
beforeAll(() => disableConsoleLog(["log", "warn", "error"]));
|
||||||
|
afterAll(() => enableConsoleLog());
|
||||||
|
|
||||||
|
describe("base", () => {
|
||||||
|
it("should connect to the database", async () => {
|
||||||
|
const connection = config.createConnection();
|
||||||
|
expect(await connection.ping()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should clean the database", async () => {
|
||||||
|
const connection = config.createConnection();
|
||||||
|
await cleanDatabase(connection, config);
|
||||||
|
|
||||||
|
const tables = await connection.getIntrospector().getTables();
|
||||||
|
expect(tables).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("integration", () => {
|
||||||
|
let connection: PostgresConnection;
|
||||||
|
beforeAll(async () => {
|
||||||
|
connection = config.createConnection();
|
||||||
|
await cleanDatabase(connection, config);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await cleanDatabase(connection, config);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await connection.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create app and ping", async () => {
|
||||||
|
const app = createApp({
|
||||||
|
connection,
|
||||||
|
});
|
||||||
|
await app.build();
|
||||||
|
|
||||||
|
expect(app.version()).toBeDefined();
|
||||||
|
expect(await app.em.ping()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create a basic schema", async () => {
|
||||||
|
const schema = proto.em(
|
||||||
|
{
|
||||||
|
posts: proto.entity("posts", {
|
||||||
|
title: proto.text().required(),
|
||||||
|
content: proto.text(),
|
||||||
|
}),
|
||||||
|
comments: proto.entity("comments", {
|
||||||
|
content: proto.text(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
(fns, s) => {
|
||||||
|
fns.relation(s.comments).manyToOne(s.posts);
|
||||||
|
fns.index(s.posts).on(["title"], true);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const app = createApp({
|
||||||
|
connection,
|
||||||
|
initialConfig: {
|
||||||
|
data: schema.toJSON(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await app.build();
|
||||||
|
|
||||||
|
expect(app.em.entities.length).toBe(2);
|
||||||
|
expect(app.em.entities.map((e) => e.name)).toEqual(["posts", "comments"]);
|
||||||
|
|
||||||
|
const api = app.getApi();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
(
|
||||||
|
await api.data.createMany("posts", [
|
||||||
|
{
|
||||||
|
title: "Hello",
|
||||||
|
content: "World",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Hello 2",
|
||||||
|
content: "World 2",
|
||||||
|
},
|
||||||
|
])
|
||||||
|
).data,
|
||||||
|
).toEqual([
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
title: "Hello",
|
||||||
|
content: "World",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
title: "Hello 2",
|
||||||
|
content: "World 2",
|
||||||
|
},
|
||||||
|
] as any);
|
||||||
|
|
||||||
|
// try to create an existing
|
||||||
|
expect(
|
||||||
|
(
|
||||||
|
await api.data.createOne("posts", {
|
||||||
|
title: "Hello",
|
||||||
|
})
|
||||||
|
).ok,
|
||||||
|
).toBe(false);
|
||||||
|
|
||||||
|
// add a comment to a post
|
||||||
|
await api.data.createOne("comments", {
|
||||||
|
content: "Hello",
|
||||||
|
posts_id: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
// and then query using a `with` property
|
||||||
|
const result = await api.data.readMany("posts", { with: ["comments"] });
|
||||||
|
expect(result.length).toBe(2);
|
||||||
|
expect(result[0].comments.length).toBe(1);
|
||||||
|
expect(result[0].comments[0].content).toBe("Hello");
|
||||||
|
expect(result[1].comments.length).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user