mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-16 04:27:21 +00:00
various fixes: refactored imports, introduced fromDriver/toDriver to improve compat
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
"bin": "./dist/cli/index.js",
|
||||
"version": "0.14.0",
|
||||
"version": "0.15.0-rc.0",
|
||||
"description": "Lightweight Firebase/Supabase alternative built to run anywhere — incl. Next.js, React Router, Astro, Cloudflare, Bun, Node, AWS Lambda & more.",
|
||||
"homepage": "https://bknd.io",
|
||||
"repository": {
|
||||
@@ -201,11 +201,11 @@
|
||||
},
|
||||
"require": "./dist/adapter/sqlite/node.js"
|
||||
},
|
||||
"./plugins": {
|
||||
"types": "./dist/types/plugins/index.d.ts",
|
||||
"import": "./dist/plugins/index.js",
|
||||
"require": "./dist/plugins/index.js"
|
||||
},
|
||||
"./plugins": {
|
||||
"types": "./dist/types/plugins/index.d.ts",
|
||||
"import": "./dist/plugins/index.js",
|
||||
"require": "./dist/plugins/index.js"
|
||||
},
|
||||
"./adapter/cloudflare": {
|
||||
"types": "./dist/types/adapter/cloudflare/index.d.ts",
|
||||
"import": "./dist/adapter/cloudflare/index.js",
|
||||
|
||||
@@ -69,8 +69,9 @@ export async function createAdapterApp<Config extends BkndConfig = BkndConfig, A
|
||||
connection = config.connection;
|
||||
} else {
|
||||
const sqlite = (await import("bknd/adapter/sqlite")).sqlite;
|
||||
connection = sqlite(config.connection ?? { url: ":memory:" });
|
||||
$console.info(`Using ${connection.name} connection`);
|
||||
const conf = config.connection ?? { url: ":memory:" };
|
||||
connection = sqlite(conf);
|
||||
$console.info(`Using ${connection.name} connection`, conf.url);
|
||||
}
|
||||
appConfig.connection = connection;
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ type MakeAppConfig = {
|
||||
async function makeApp(config: MakeAppConfig) {
|
||||
return await createRuntimeApp({
|
||||
serveStatic: await serveStatic(config.server?.platform ?? "node"),
|
||||
...config,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -99,7 +100,7 @@ export async function makeAppFromEnv(options: Partial<RunOptions> = {}) {
|
||||
let app: App | undefined = undefined;
|
||||
// first start from arguments if given
|
||||
if (options.dbUrl) {
|
||||
console.info("Using connection from", c.cyan("--db-url"));
|
||||
console.info("Using connection from", c.cyan("--db-url"), c.cyan(options.dbUrl));
|
||||
const connection = options.dbUrl ? { url: options.dbUrl } : undefined;
|
||||
app = await makeApp({ connection, server: { platform: options.server } });
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
import type { BaseIntrospector, BaseIntrospectorConfig } from "./BaseIntrospector";
|
||||
import type { Constructor, DB } from "core";
|
||||
import { KyselyPluginRunner } from "data/plugins/KyselyPluginRunner";
|
||||
import type { Field } from "data/fields/Field";
|
||||
|
||||
export type QB = SelectQueryBuilder<any, any, any>;
|
||||
|
||||
@@ -200,6 +201,14 @@ export abstract class Connection<Client = unknown> {
|
||||
|
||||
abstract getFieldSchema(spec: FieldSpec, strict?: boolean): SchemaResponse;
|
||||
|
||||
toDriver(value: unknown, field: Field): unknown {
|
||||
return value;
|
||||
}
|
||||
|
||||
fromDriver(value: any, field: Field): unknown {
|
||||
return value;
|
||||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
// no-op by default
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import type { TestRunner } from "core/test";
|
||||
import { Connection, type FieldSpec } from "./Connection";
|
||||
|
||||
// @todo: add various datatypes: string, number, boolean, object, array, null, undefined, date, etc.
|
||||
|
||||
export function connectionTestSuite(
|
||||
testRunner: TestRunner,
|
||||
{
|
||||
|
||||
@@ -57,6 +57,6 @@ export class LibsqlConnection extends SqliteConnection<Client> {
|
||||
}
|
||||
}
|
||||
|
||||
export function libsql(credentials: LibSqlCredentials): LibsqlConnection {
|
||||
export function libsql(credentials: Client | LibSqlCredentials): LibsqlConnection {
|
||||
return new LibsqlConnection(credentials);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,9 @@ import { Connection, type DbFunctions, type FieldSpec, type SchemaResponse } fro
|
||||
import type { Constructor } from "core";
|
||||
import { customIntrospector } from "../Connection";
|
||||
import { SqliteIntrospector } from "./SqliteIntrospector";
|
||||
import type { Field } from "data/fields/Field";
|
||||
|
||||
// @todo: add pragmas
|
||||
export type SqliteConnectionConfig<
|
||||
CustomDialect extends Constructor<Dialect> = Constructor<Dialect>,
|
||||
> = {
|
||||
@@ -80,4 +82,24 @@ export abstract class SqliteConnection<Client = unknown> extends Connection<Clie
|
||||
},
|
||||
] as const;
|
||||
}
|
||||
|
||||
override toDriver(value: unknown, field: Field): unknown {
|
||||
if (field.type === "boolean") {
|
||||
return value ? 1 : 0;
|
||||
}
|
||||
if (typeof value === "undefined") {
|
||||
return null;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
override fromDriver(value: any, field: Field): unknown {
|
||||
if (field.type === "boolean" && typeof value === "number") {
|
||||
return value === 1;
|
||||
}
|
||||
if (value === null) {
|
||||
return undefined;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
import { type Static, StringEnum, StringRecord, objectTransform } from "core/utils";
|
||||
import * as tb from "@sinclair/typebox";
|
||||
import {
|
||||
FieldClassMap,
|
||||
RelationClassMap,
|
||||
RelationFieldClassMap,
|
||||
entityConfigSchema,
|
||||
entityTypes,
|
||||
} from "data";
|
||||
import { MediaField, mediaFieldConfigSchema } from "../media/MediaField";
|
||||
import { FieldClassMap } from "data/fields";
|
||||
import { RelationClassMap, RelationFieldClassMap } from "data/relations";
|
||||
import { entityConfigSchema, entityTypes } from "data/entities";
|
||||
import { primaryFieldTypes } from "./fields";
|
||||
|
||||
export const FIELDS = {
|
||||
|
||||
@@ -278,6 +278,10 @@ export class EntityManager<TBD extends object = DefaultDB> {
|
||||
row[key] = field.getDefault();
|
||||
}
|
||||
|
||||
// transform from driver
|
||||
value = this.connection.fromDriver(value, field);
|
||||
|
||||
// transform from field
|
||||
row[key] = field.transformRetrieve(value as any);
|
||||
} catch (e: any) {
|
||||
throw new TransformRetrieveFailedException(
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import { $console, type DB as DefaultDB, type PrimaryFieldType } from "core";
|
||||
import type { DB as DefaultDB, PrimaryFieldType } from "core";
|
||||
import { type EmitsEvents, EventManager } from "core/events";
|
||||
import type { DeleteQueryBuilder, InsertQueryBuilder, UpdateQueryBuilder } from "kysely";
|
||||
import { type TActionContext, WhereBuilder } from "../..";
|
||||
import type { TActionContext } from "../..";
|
||||
import { WhereBuilder } from "../query/WhereBuilder";
|
||||
import type { Entity, EntityData, EntityManager } from "../../entities";
|
||||
import { InvalidSearchParamsException } from "../../errors";
|
||||
import { MutatorEvents } from "../../events";
|
||||
import { RelationMutator } from "../../relations";
|
||||
import type { RepoQuery } from "../../server/query";
|
||||
import { MutatorResult, type MutatorResultOptions } from "./MutatorResult";
|
||||
import { transformObject } from "core/utils";
|
||||
|
||||
type MutatorQB =
|
||||
| InsertQueryBuilder<any, any, any>
|
||||
@@ -86,7 +88,11 @@ export class Mutator<
|
||||
throw new Error(`Field "${key}" is not fillable on entity "${entity.name}"`);
|
||||
}
|
||||
|
||||
// transform from field
|
||||
validatedData[key] = await field.transformPersist(data[key], this.em, context);
|
||||
|
||||
// transform to driver
|
||||
validatedData[key] = this.em.connection.toDriver(validatedData[key], field);
|
||||
}
|
||||
|
||||
if (Object.keys(validatedData).length === 0) {
|
||||
@@ -283,6 +289,10 @@ export class Mutator<
|
||||
): Promise<MutatorResult<Output[]>> {
|
||||
const entity = this.entity;
|
||||
const validatedData = await this.getValidatedData(data, "update");
|
||||
console.log("updateWhere", {
|
||||
entity,
|
||||
validatedData,
|
||||
});
|
||||
|
||||
// @todo: add a way to delete all by adding force?
|
||||
if (!where || typeof where !== "object" || Object.keys(where).length === 0) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Result, type ResultJSON, type ResultOptions } from "../Result";
|
||||
|
||||
export type MutatorResultOptions = ResultOptions & {
|
||||
silent?: boolean;
|
||||
logParams?: boolean;
|
||||
};
|
||||
|
||||
export type MutatorResultJSON<T = EntityData[]> = ResultJSON<T>;
|
||||
@@ -19,7 +20,10 @@ export class MutatorResult<T = EntityData[]> extends Result<T> {
|
||||
hydrator: (rows) => em.hydrate(entity.name, rows as any),
|
||||
beforeExecute: (compiled) => {
|
||||
if (!options?.silent) {
|
||||
$console.debug(`[Mutation]\n${compiled.sql}\n`);
|
||||
$console.debug(
|
||||
`[Mutation]\n${compiled.sql}\n`,
|
||||
options?.logParams ? compiled.parameters : undefined,
|
||||
);
|
||||
}
|
||||
},
|
||||
onError: (error) => {
|
||||
|
||||
@@ -246,8 +246,10 @@ export class Repository<TBD extends object = DefaultDB, TB extends keyof TBD = a
|
||||
qb = WhereBuilder.addClause(qb, options.where);
|
||||
}
|
||||
|
||||
if (!ignore.includes("limit")) qb = qb.limit(options.limit ?? defaults.limit);
|
||||
if (!ignore.includes("offset")) qb = qb.offset(options.offset ?? defaults.offset);
|
||||
if (!ignore.includes("limit")) {
|
||||
qb = qb.limit(options.limit ?? defaults.limit);
|
||||
if (!ignore.includes("offset")) qb = qb.offset(options.offset ?? defaults.offset);
|
||||
}
|
||||
|
||||
// sorting
|
||||
if (!ignore.includes("sort")) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { s } from "core/object/schema";
|
||||
import { WhereBuilder, type WhereQuery } from "data";
|
||||
import { WhereBuilder, type WhereQuery } from "data/entities/query/WhereBuilder";
|
||||
import { $console } from "core";
|
||||
import { isObject } from "core/utils";
|
||||
import type { CoercionOptions, TAnyOf } from "jsonv-ts";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Static } from "core/utils";
|
||||
import { Field, baseFieldConfigSchema } from "data";
|
||||
import { Field, baseFieldConfigSchema } from "data/fields";
|
||||
import * as tbbox from "@sinclair/typebox";
|
||||
const { Type } = tbbox;
|
||||
|
||||
|
||||
@@ -8,25 +8,39 @@ import { __bknd } from "modules/ModuleManager";
|
||||
import { nodeSqlite } from "./src/adapter/node/connection/NodeSqliteConnection";
|
||||
import { libsql } from "./src/data/connection/sqlite/LibsqlConnection";
|
||||
import { $console } from "core";
|
||||
import { createClient } from "@libsql/client";
|
||||
|
||||
registries.media.register("local", StorageLocalAdapter);
|
||||
|
||||
const example = import.meta.env.VITE_EXAMPLE;
|
||||
const dbUrl = example ? `file:.configs/${example}.db` : import.meta.env.VITE_DB_URL;
|
||||
|
||||
let connection: Connection;
|
||||
if (dbUrl) {
|
||||
connection = nodeSqlite({ url: dbUrl });
|
||||
$console.debug("Using node-sqlite connection", dbUrl);
|
||||
} else if (import.meta.env.VITE_DB_LIBSQL_URL) {
|
||||
connection = libsql({
|
||||
url: import.meta.env.VITE_DB_LIBSQL_URL!,
|
||||
authToken: import.meta.env.VITE_DB_LIBSQL_TOKEN!,
|
||||
});
|
||||
|
||||
if (import.meta.env.VITE_DB_LIBSQL_URL) {
|
||||
connection = libsql(
|
||||
createClient({
|
||||
url: import.meta.env.VITE_DB_LIBSQL_URL!,
|
||||
authToken: import.meta.env.VITE_DB_LIBSQL_TOKEN!,
|
||||
}),
|
||||
);
|
||||
$console.debug("Using libsql connection", import.meta.env.VITE_DB_URL);
|
||||
} else {
|
||||
connection = nodeSqlite();
|
||||
$console.debug("No connection provided, using in-memory database");
|
||||
const dbUrl = example ? `file:.configs/${example}.db` : import.meta.env.VITE_DB_URL;
|
||||
if (dbUrl) {
|
||||
connection = nodeSqlite({ url: dbUrl });
|
||||
$console.debug("Using node-sqlite connection", dbUrl);
|
||||
} else if (import.meta.env.VITE_DB_LIBSQL_URL) {
|
||||
connection = libsql(
|
||||
createClient({
|
||||
url: import.meta.env.VITE_DB_LIBSQL_URL!,
|
||||
authToken: import.meta.env.VITE_DB_LIBSQL_TOKEN!,
|
||||
}),
|
||||
);
|
||||
$console.debug("Using libsql connection", import.meta.env.VITE_DB_URL);
|
||||
} else {
|
||||
connection = nodeSqlite();
|
||||
$console.debug("No connection provided, using in-memory database");
|
||||
}
|
||||
}
|
||||
|
||||
/* if (example) {
|
||||
|
||||
Reference in New Issue
Block a user