feat: adding env aware endpoint to obtain sqlite connection, remove libsql hard dependency

This commit is contained in:
dswbx
2025-06-13 11:09:47 +02:00
parent 046c1d21b1
commit bbb7bfb7a1
28 changed files with 288 additions and 159 deletions

View File

@@ -1,5 +1,5 @@
import type { DB } from "core";
import type { EntityData, RepoQueryIn, RepositoryResponse } from "data";
import type { EntityData, RepoQueryIn, RepositoryResultJSON } from "data";
import type { Insertable, Selectable, Updateable } from "kysely";
import { type BaseModuleApiOptions, ModuleApi, type PrimaryFieldType } from "modules";
import type { FetchPromise, ResponseObject } from "modules/ModuleApi";
@@ -32,10 +32,7 @@ export class DataApi extends ModuleApi<DataApiOptions> {
query: Omit<RepoQueryIn, "where" | "limit" | "offset"> = {},
) {
type Data = E extends keyof DB ? Selectable<DB[E]> : EntityData;
return this.get<Pick<RepositoryResponse<Data>, "meta" | "data">>(
["entity", entity as any, id],
query,
);
return this.get<RepositoryResultJSON<Data>>(["entity", entity as any, id], query);
}
readOneBy<E extends keyof DB | string>(
@@ -43,7 +40,7 @@ export class DataApi extends ModuleApi<DataApiOptions> {
query: Omit<RepoQueryIn, "limit" | "offset" | "sort"> = {},
) {
type Data = E extends keyof DB ? Selectable<DB[E]> : EntityData;
type T = Pick<RepositoryResponse<Data>, "meta" | "data">;
type T = RepositoryResultJSON<Data>;
return this.readMany(entity, {
...query,
limit: 1,
@@ -53,7 +50,7 @@ export class DataApi extends ModuleApi<DataApiOptions> {
readMany<E extends keyof DB | string>(entity: E, query: RepoQueryIn = {}) {
type Data = E extends keyof DB ? Selectable<DB[E]> : EntityData;
type T = Pick<RepositoryResponse<Data[]>, "meta" | "data">;
type T = RepositoryResultJSON<Data[]>;
const input = query ?? this.options.defaultQuery;
const req = this.get<T>(["entity", entity as any], input);
@@ -72,7 +69,7 @@ export class DataApi extends ModuleApi<DataApiOptions> {
query: RepoQueryIn = {},
) {
type Data = R extends keyof DB ? Selectable<DB[R]> : EntityData;
return this.get<Pick<RepositoryResponse<Data[]>, "meta" | "data">>(
return this.get<RepositoryResultJSON<Data[]>>(
["entity", entity as any, id, reference],
query ?? this.options.defaultQuery,
);
@@ -83,7 +80,7 @@ export class DataApi extends ModuleApi<DataApiOptions> {
input: Insertable<Input>,
) {
type Data = E extends keyof DB ? Selectable<DB[E]> : EntityData;
return this.post<RepositoryResponse<Data>>(["entity", entity as any], input);
return this.post<RepositoryResultJSON<Data>>(["entity", entity as any], input);
}
createMany<E extends keyof DB | string, Input = E extends keyof DB ? DB[E] : EntityData>(
@@ -94,7 +91,7 @@ export class DataApi extends ModuleApi<DataApiOptions> {
throw new Error("input is required");
}
type Data = E extends keyof DB ? Selectable<DB[E]> : EntityData;
return this.post<RepositoryResponse<Data[]>>(["entity", entity as any], input);
return this.post<RepositoryResultJSON<Data[]>>(["entity", entity as any], input);
}
updateOne<E extends keyof DB | string, Input = E extends keyof DB ? DB[E] : EntityData>(
@@ -104,7 +101,7 @@ export class DataApi extends ModuleApi<DataApiOptions> {
) {
if (!id) throw new Error("ID is required");
type Data = E extends keyof DB ? Selectable<DB[E]> : EntityData;
return this.patch<RepositoryResponse<Data>>(["entity", entity as any, id], input);
return this.patch<RepositoryResultJSON<Data>>(["entity", entity as any, id], input);
}
updateMany<E extends keyof DB | string, Input = E extends keyof DB ? DB[E] : EntityData>(
@@ -114,7 +111,7 @@ export class DataApi extends ModuleApi<DataApiOptions> {
) {
this.requireObjectSet(where);
type Data = E extends keyof DB ? Selectable<DB[E]> : EntityData;
return this.patch<RepositoryResponse<Data[]>>(["entity", entity as any], {
return this.patch<RepositoryResultJSON<Data[]>>(["entity", entity as any], {
update,
where,
});
@@ -123,24 +120,24 @@ export class DataApi extends ModuleApi<DataApiOptions> {
deleteOne<E extends keyof DB | string>(entity: E, id: PrimaryFieldType) {
if (!id) throw new Error("ID is required");
type Data = E extends keyof DB ? Selectable<DB[E]> : EntityData;
return this.delete<RepositoryResponse<Data>>(["entity", entity as any, id]);
return this.delete<RepositoryResultJSON<Data>>(["entity", entity as any, id]);
}
deleteMany<E extends keyof DB | string>(entity: E, where: RepoQueryIn["where"]) {
this.requireObjectSet(where);
type Data = E extends keyof DB ? Selectable<DB[E]> : EntityData;
return this.delete<RepositoryResponse<Data>>(["entity", entity as any], where);
return this.delete<RepositoryResultJSON<Data>>(["entity", entity as any], where);
}
count<E extends keyof DB | string>(entity: E, where: RepoQueryIn["where"] = {}) {
return this.post<RepositoryResponse<{ entity: E; count: number }>>(
return this.post<RepositoryResultJSON<{ entity: E; count: number }>>(
["entity", entity as any, "fn", "count"],
where,
);
}
exists<E extends keyof DB | string>(entity: E, where: RepoQueryIn["where"] = {}) {
return this.post<RepositoryResponse<{ entity: E; exists: boolean }>>(
return this.post<RepositoryResultJSON<{ entity: E; exists: boolean }>>(
["entity", entity as any, "fn", "exists"],
where,
);

View File

@@ -1,6 +1,8 @@
import { Connection, type FieldSpec, type SchemaResponse } from "./Connection";
export class DummyConnection extends Connection {
override name: string = "dummy";
protected override readonly supported = {
batching: true,
};

View File

@@ -5,11 +5,13 @@ export {
type IndexSpec,
type DbFunctions,
type SchemaResponse,
type ConnQuery,
type ConnQueryResults,
customIntrospector,
} from "./Connection";
// sqlite
export { LibsqlConnection, type LibSqlCredentials } from "./sqlite/LibsqlConnection";
//export { libsql, LibsqlConnection, type LibSqlCredentials } from "./sqlite/LibsqlConnection";
export { SqliteConnection } from "./sqlite/SqliteConnection";
export { SqliteIntrospector } from "./sqlite/SqliteIntrospector";
export { SqliteLocalConnection } from "./sqlite/SqliteLocalConnection";

View File

@@ -1,15 +1,29 @@
import { createClient, type Client, type Config, type InStatement } from "@libsql/client";
import type { Client, Config, InStatement } from "@libsql/client";
import { createClient } from "libsql-stateless-easy";
import { LibsqlDialect } from "@libsql/kysely-libsql";
import { $console } from "core";
import { FilterNumericKeysPlugin } from "data/plugins/FilterNumericKeysPlugin";
import type { ConnQuery, ConnQueryResults } from "../Connection";
import { SqliteConnection } from "./SqliteConnection";
import { type ConnQuery, type ConnQueryResults, SqliteConnection } from "bknd/data";
export const LIBSQL_PROTOCOLS = ["wss", "https", "libsql"] as const;
export type LibSqlCredentials = Config & {
protocol?: (typeof LIBSQL_PROTOCOLS)[number];
};
function getClient(clientOrCredentials: Client | LibSqlCredentials): Client {
if (clientOrCredentials && "url" in clientOrCredentials) {
let { url, authToken, protocol } = clientOrCredentials;
if (protocol && LIBSQL_PROTOCOLS.includes(protocol)) {
console.info("changing protocol to", protocol);
const [, rest] = url.split("://");
url = `${protocol}://${rest}`;
}
return createClient({ url, authToken });
}
return clientOrCredentials as Client;
}
export class LibsqlConnection extends SqliteConnection<Client> {
override name = "libsql";
protected override readonly supported = {
@@ -17,22 +31,8 @@ export class LibsqlConnection extends SqliteConnection<Client> {
softscans: true,
};
constructor(client: Client);
constructor(credentials: LibSqlCredentials);
constructor(clientOrCredentials: Client | LibSqlCredentials) {
let client: Client;
if (clientOrCredentials && "url" in clientOrCredentials) {
let { url, authToken, protocol } = clientOrCredentials;
if (protocol && LIBSQL_PROTOCOLS.includes(protocol)) {
$console.log("changing protocol to", protocol);
const [, rest] = url.split("://");
url = `${protocol}://${rest}`;
}
client = createClient({ url, authToken });
} else {
client = clientOrCredentials;
}
const client = getClient(clientOrCredentials);
super({
excludeTables: ["libsql_wasm_func_table"],
@@ -56,3 +56,7 @@ export class LibsqlConnection extends SqliteConnection<Client> {
return this.withTransformedRows(await this.client.batch(stms)) as any;
}
}
export function libsql(credentials: LibSqlCredentials): LibsqlConnection {
return new LibsqlConnection(credentials);
}

View File

@@ -4,3 +4,5 @@ export * from "./mutation/Mutator";
export * from "./query/Repository";
export * from "./query/WhereBuilder";
export * from "./query/WithBuilder";
export * from "./query/RepositoryResult";
export * from "./mutation/MutatorResult";

View File

@@ -19,7 +19,7 @@ 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`, compiled.parameters);
$console.debug(`[Mutation]\n${compiled.sql}\n`);
}
},
onError: (error) => {