bradb 1.2.0 → 1.2.2

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 CHANGED
@@ -2,5 +2,5 @@ export * from './src/types';
2
2
  export * from './src/controller';
3
3
  export * from './src/standard';
4
4
  export * from './src/relational';
5
- export * from './src/utils';
5
+ export * from './src/filters';
6
6
  export * from './src/errors';
package/dist/index.js CHANGED
@@ -18,5 +18,5 @@ __exportStar(require("./src/types"), exports);
18
18
  __exportStar(require("./src/controller"), exports);
19
19
  __exportStar(require("./src/standard"), exports);
20
20
  __exportStar(require("./src/relational"), exports);
21
- __exportStar(require("./src/utils"), exports);
21
+ __exportStar(require("./src/filters"), exports);
22
22
  __exportStar(require("./src/errors"), exports);
@@ -2,12 +2,12 @@ import { PgTable } from "drizzle-orm/pg-core";
2
2
  import { Request, Response } from "express";
3
3
  import { z } from "zod";
4
4
  import { CRUDService } from "./types";
5
- export declare class BaseController<T extends PgTable> {
6
- protected service: CRUDService;
7
- private schema;
5
+ export declare class BaseController<T extends PgTable, FSchema extends z.ZodObject> {
6
+ protected service: CRUDService<FSchema>;
7
+ private filterSchema;
8
8
  private createSchema;
9
9
  private updateSchema;
10
- constructor(service: CRUDService, base: z.ZodObject, filter: z.ZodSchema<Partial<T["$inferSelect"]>>);
10
+ constructor(service: CRUDService<FSchema>, base: z.ZodObject, filter: FSchema);
11
11
  getAll: (req: Request, res: Response) => Promise<void>;
12
12
  getById: (req: Request, res: Response) => Promise<void>;
13
13
  create: (req: Request, res: Response) => Promise<void>;
@@ -4,10 +4,10 @@ exports.BaseController = void 0;
4
4
  class BaseController {
5
5
  constructor(service, base, filter) {
6
6
  this.getAll = async (req, res) => {
7
- const filters = getFilters(req, this.schema.filter);
7
+ const filters = getFilters(req, this.filterSchema);
8
8
  const pagination = getPagination(req);
9
9
  const [items, total] = await Promise.all([
10
- this.service.findAll({ pagination, filters }),
10
+ this.service.findAll(filters, pagination.page, pagination.pageSize),
11
11
  this.service.count(filters)
12
12
  ]);
13
13
  res.status(200).json({
@@ -42,7 +42,7 @@ class BaseController {
42
42
  });
43
43
  // @ts-expect-error infer schema
44
44
  this.updateSchema = base.partial();
45
- this.schema = { base, filter };
45
+ this.filterSchema = filter;
46
46
  }
47
47
  }
48
48
  exports.BaseController = BaseController;
@@ -0,0 +1,4 @@
1
+ import { SQL } from "drizzle-orm";
2
+ import { Filter, FilterMap } from "./types";
3
+ import { ZodObject } from "zod";
4
+ export declare function buildFilters<FSchema extends ZodObject>(map: FilterMap<FSchema>, filters?: Filter<FSchema>): SQL<unknown> | undefined;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildFilters = buildFilters;
4
+ const drizzle_orm_1 = require("drizzle-orm");
5
+ function buildFilters(map, filters) {
6
+ const conditions = [];
7
+ if (!filters)
8
+ return undefined;
9
+ for (const f of Object.keys(filters)) {
10
+ if (f in map) {
11
+ const func = map[f];
12
+ const value = filters[f];
13
+ if (value !== undefined && value !== null) {
14
+ conditions.push(func(value));
15
+ }
16
+ }
17
+ }
18
+ return conditions.length ? (0, drizzle_orm_1.and)(...conditions) : undefined;
19
+ }
@@ -1,5 +1,8 @@
1
- import { FilterMap, FindAllOptions } from "../src/types";
2
- import { DBQueryConfig, TableRelationalConfig, TablesRelationalConfig } from "drizzle-orm";
1
+ import { Filter, FilterMap } from "../src/types";
2
+ import { BuildQueryResult, DBQueryConfig, TableRelationalConfig, TablesRelationalConfig } from "drizzle-orm";
3
3
  import { RelationalQueryBuilder } from "drizzle-orm/pg-core/query-builders/query";
4
- export declare function findAllRelational<TSchema extends TablesRelationalConfig, TFields extends TableRelationalConfig, TTableConfig extends TableRelationalConfig = TableRelationalConfig>(map: FilterMap<any>, q: RelationalQueryBuilder<TSchema, TFields>, config: DBQueryConfig<any, true, TSchema, TTableConfig>): (options: FindAllOptions<any>) => Promise<(({ [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; } | undefined extends Record<string, unknown> ? { [Key in (import("drizzle-orm").Equal<Exclude<(Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; })[(string | keyof TTableConfig["columns"]) & keyof TFields["columns"]], undefined>, false> extends true ? Exclude<keyof TFields["columns"], import("drizzle-orm").NonUndefinedKeysOnly<Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; }>> : { [K_3 in keyof (Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; })]: import("drizzle-orm").Equal<(Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; })[K_3], true> extends true ? K_3 : never; }[string | keyof TTableConfig["columns"]] & keyof TFields["columns"]) & string as Key]: { [K_4 in import("drizzle-orm").Equal<Exclude<(Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; })[(string | keyof TTableConfig["columns"]) & keyof TFields["columns"]], undefined>, false> extends true ? Exclude<keyof TFields["columns"], import("drizzle-orm").NonUndefinedKeysOnly<Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; }>> : { [K_3 in keyof (Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; })]: import("drizzle-orm").Equal<(Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; })[K_3], true> extends true ? K_3 : never; }[string | keyof TTableConfig["columns"]] & keyof TFields["columns"]]: TFields["columns"][K_4]; }[Key]["_"]["notNull"] extends true ? { [K_4 in import("drizzle-orm").Equal<Exclude<(Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; })[(string | keyof TTableConfig["columns"]) & keyof TFields["columns"]], undefined>, false> extends true ? Exclude<keyof TFields["columns"], import("drizzle-orm").NonUndefinedKeysOnly<Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; }>> : { [K_3 in keyof (Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; })]: import("drizzle-orm").Equal<(Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; })[K_3], true> extends true ? K_3 : never; }[string | keyof TTableConfig["columns"]] & keyof TFields["columns"]]: TFields["columns"][K_4]; }[Key]["_"]["data"] : { [K_4 in import("drizzle-orm").Equal<Exclude<(Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; })[(string | keyof TTableConfig["columns"]) & keyof TFields["columns"]], undefined>, false> extends true ? Exclude<keyof TFields["columns"], import("drizzle-orm").NonUndefinedKeysOnly<Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; }>> : { [K_3 in keyof (Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; })]: import("drizzle-orm").Equal<(Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; })[K_3], true> extends true ? K_3 : never; }[string | keyof TTableConfig["columns"]] & keyof TFields["columns"]]: TFields["columns"][K_4]; }[Key]["_"]["data"] | null; } extends infer T_1 ? { [K_2 in keyof T_1]: T_1[K_2]; } : never : { [Key_1 in keyof TFields["columns"] & string as Key_1]: TFields["columns"][Key_1]["_"]["notNull"] extends true ? TFields["columns"][Key_1]["_"]["data"] : TFields["columns"][Key_1]["_"]["data"] | null; } extends infer T_2 ? { [K_4 in keyof T_2]: T_2[K_4]; } : never) & {} & ({ [K_5 in keyof TTableConfig["relations"]]?: true | DBQueryConfig<TTableConfig["relations"][K_5] extends import("drizzle-orm").One<string, boolean> ? "one" : "many", false, TSchema, import("drizzle-orm").FindTableByDBName<TSchema, TTableConfig["relations"][K_5]["referencedTableName"]>> | undefined; } | undefined extends Record<string, unknown> ? import("drizzle-orm").BuildRelationResult<TSchema, Record<string, unknown> & { [K_5 in keyof TTableConfig["relations"]]?: true | DBQueryConfig<TTableConfig["relations"][K_5] extends import("drizzle-orm").One<string, boolean> ? "one" : "many", false, TSchema, import("drizzle-orm").FindTableByDBName<TSchema, TTableConfig["relations"][K_5]["referencedTableName"]>> | undefined; }, TFields["relations"]> : {}) extends infer T ? { [K in keyof T]: T[K]; } : never)[]>;
5
- export declare function findOneRelational<TSchema extends TablesRelationalConfig, TFields extends TableRelationalConfig, TTableConfig extends TableRelationalConfig = TableRelationalConfig>(q: RelationalQueryBuilder<TSchema, TFields>, config: DBQueryConfig<any, true, TSchema, TTableConfig>): (id: number) => Promise<({ [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; } | undefined extends Record<string, unknown> ? { [Key in (import("drizzle-orm").Equal<Exclude<(Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; })[(string | keyof TTableConfig["columns"]) & keyof TFields["columns"]], undefined>, false> extends true ? Exclude<keyof TFields["columns"], import("drizzle-orm").NonUndefinedKeysOnly<Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; }>> : { [K_3 in keyof (Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; })]: import("drizzle-orm").Equal<(Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; })[K_3], true> extends true ? K_3 : never; }[string | keyof TTableConfig["columns"]] & keyof TFields["columns"]) & string as Key]: { [K_4 in import("drizzle-orm").Equal<Exclude<(Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; })[(string | keyof TTableConfig["columns"]) & keyof TFields["columns"]], undefined>, false> extends true ? Exclude<keyof TFields["columns"], import("drizzle-orm").NonUndefinedKeysOnly<Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; }>> : { [K_3 in keyof (Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; })]: import("drizzle-orm").Equal<(Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; })[K_3], true> extends true ? K_3 : never; }[string | keyof TTableConfig["columns"]] & keyof TFields["columns"]]: TFields["columns"][K_4]; }[Key]["_"]["notNull"] extends true ? { [K_4 in import("drizzle-orm").Equal<Exclude<(Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; })[(string | keyof TTableConfig["columns"]) & keyof TFields["columns"]], undefined>, false> extends true ? Exclude<keyof TFields["columns"], import("drizzle-orm").NonUndefinedKeysOnly<Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; }>> : { [K_3 in keyof (Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; })]: import("drizzle-orm").Equal<(Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; })[K_3], true> extends true ? K_3 : never; }[string | keyof TTableConfig["columns"]] & keyof TFields["columns"]]: TFields["columns"][K_4]; }[Key]["_"]["data"] : { [K_4 in import("drizzle-orm").Equal<Exclude<(Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; })[(string | keyof TTableConfig["columns"]) & keyof TFields["columns"]], undefined>, false> extends true ? Exclude<keyof TFields["columns"], import("drizzle-orm").NonUndefinedKeysOnly<Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; }>> : { [K_3 in keyof (Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; })]: import("drizzle-orm").Equal<(Record<string, unknown> & { [K_1 in keyof TTableConfig["columns"]]?: boolean | undefined; })[K_3], true> extends true ? K_3 : never; }[string | keyof TTableConfig["columns"]] & keyof TFields["columns"]]: TFields["columns"][K_4]; }[Key]["_"]["data"] | null; } extends infer T_1 ? { [K_2 in keyof T_1]: T_1[K_2]; } : never : { [Key_1 in keyof TFields["columns"] & string as Key_1]: TFields["columns"][Key_1]["_"]["notNull"] extends true ? TFields["columns"][Key_1]["_"]["data"] : TFields["columns"][Key_1]["_"]["data"] | null; } extends infer T_2 ? { [K_4 in keyof T_2]: T_2[K_4]; } : never) & {} & ({ [K_5 in keyof TTableConfig["relations"]]?: true | DBQueryConfig<TTableConfig["relations"][K_5] extends import("drizzle-orm").One<string, boolean> ? "one" : "many", false, TSchema, import("drizzle-orm").FindTableByDBName<TSchema, TTableConfig["relations"][K_5]["referencedTableName"]>> | undefined; } | undefined extends Record<string, unknown> ? import("drizzle-orm").BuildRelationResult<TSchema, Record<string, unknown> & { [K_5 in keyof TTableConfig["relations"]]?: true | DBQueryConfig<TTableConfig["relations"][K_5] extends import("drizzle-orm").One<string, boolean> ? "one" : "many", false, TSchema, import("drizzle-orm").FindTableByDBName<TSchema, TTableConfig["relations"][K_5]["referencedTableName"]>> | undefined; }, TFields["relations"]> : {}) extends infer T ? { [K in keyof T]: T[K]; } : never>;
4
+ import { ZodObject } from "zod";
5
+ export declare function RelationalBuilder<TSchema extends TablesRelationalConfig, TFields extends TableRelationalConfig, FSchema extends ZodObject>(q: RelationalQueryBuilder<TSchema, TFields>, filterMap: FilterMap<FSchema>): {
6
+ findAll<TConfig extends DBQueryConfig<"many", true, TSchema, TFields>>(config?: TConfig): (filters?: Filter<FSchema>, page?: number, pageSize?: number) => Promise<BuildQueryResult<TSchema, TFields, TConfig>[]>;
7
+ findOne<TSelection extends Omit<DBQueryConfig<"many", true, TSchema, TFields>, "limit">>(config?: DBQueryConfig<any, true, TSchema, TFields>): (id: number) => Promise<BuildQueryResult<TSchema, TFields, TSelection>>;
8
+ };
@@ -1,34 +1,53 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.findAllRelational = findAllRelational;
4
- exports.findOneRelational = findOneRelational;
3
+ exports.RelationalBuilder = RelationalBuilder;
5
4
  const drizzle_orm_1 = require("drizzle-orm");
6
- const utils_1 = require("./utils");
7
- function findAllRelational(map, q, config) {
8
- return async (options) => {
9
- const { offset, limit } = (0, utils_1.getPagination)(options);
10
- const conditions = (0, utils_1.getConditions)(options, map);
11
- const items = q.findMany({
12
- ...config,
13
- where: (0, drizzle_orm_1.and)(...conditions),
14
- limit: limit,
15
- offset: offset
16
- });
17
- return items;
5
+ const filters_1 = require("./filters");
6
+ const errors_1 = require("./errors");
7
+ const pg_core_1 = require("drizzle-orm/pg-core");
8
+ function RelationalBuilder(q, filterMap) {
9
+ const baseWhere = (table) => (0, drizzle_orm_1.isNull)(table.deletedAt);
10
+ return {
11
+ findAll(config) {
12
+ return async (filters, page = 1, pageSize = 10) => {
13
+ const offset = (page - 1) * pageSize;
14
+ const items = q.findMany({
15
+ ...config,
16
+ where: (table) => (0, drizzle_orm_1.and)(baseWhere(table), (0, filters_1.buildFilters)(filterMap, filters)),
17
+ limit: pageSize,
18
+ offset
19
+ });
20
+ return items;
21
+ };
22
+ },
23
+ findOne(config) {
24
+ return async (id) => {
25
+ const result = await q.findFirst({
26
+ ...config,
27
+ // TODO: Validate table contains 'id' field
28
+ where: (table, { eq }) => (0, drizzle_orm_1.and)(baseWhere(table), eq(table.id, id))
29
+ });
30
+ if (!result) {
31
+ // TODO: proper name
32
+ const t = "record";
33
+ throw new errors_1.NotFound(`${t} with id ${id} not found`);
34
+ }
35
+ return result;
36
+ };
37
+ }
18
38
  };
19
39
  }
20
- function findOneRelational(q, config) {
21
- return async (id) => {
22
- const result = await q.findFirst({
23
- ...config,
24
- // TODO: Validate table contains 'id' field
25
- where: (table, { eq }) => eq(table.id, id),
26
- });
27
- if (!result) {
28
- // TODO: proper name
29
- const t = "tabla";
30
- throw new Error(`${t} with id ${id} not found`);
40
+ function findByPkConditions(table, data) {
41
+ const { primaryKeys } = (0, pg_core_1.getTableConfig)(table);
42
+ const conditions = [];
43
+ for (const pk of primaryKeys) {
44
+ for (const column of pk.columns) {
45
+ const name = column.name;
46
+ // if (data[name] === undefined || data[name] === null) {
47
+ // throw new Error(`Missing value for pk column: ${column.name}`);
48
+ // }
49
+ conditions.push((0, drizzle_orm_1.eq)(table[name], data[name]));
31
50
  }
32
- return result;
33
- };
51
+ }
52
+ return conditions;
34
53
  }
@@ -1,32 +1,19 @@
1
- import { Filter, FilterMap, FindAllOptions, PrimaryKeyType, Table } from "./types";
1
+ import { Filter, FilterMap, PrimaryKeyType, Table } from "./types";
2
2
  import { PgSelect } from "drizzle-orm/pg-core";
3
3
  import { NodePgDatabase } from "drizzle-orm/node-postgres";
4
4
  import { InferInsertModel } from "drizzle-orm";
5
- export declare class ServiceBuilder<T extends Table, TSchema extends Record<string, unknown>> {
5
+ import { ZodObject } from "zod";
6
+ export declare class ServiceBuilder<T extends Table, TSchema extends Record<string, unknown>, FSchema extends ZodObject> {
6
7
  private readonly db;
7
8
  private readonly table;
8
9
  private readonly map;
9
10
  readonly tableName: string;
10
- constructor(db: NodePgDatabase<TSchema>, table: T, map: FilterMap<T>);
11
- findOne<S extends PgSelect>(select: S): (id: number) => Promise<{
12
- [x: string]: any;
13
- } | {
14
- [x: string]: any;
15
- } | {
16
- [x: string]: any;
17
- }>;
18
- findAll<S extends PgSelect<T["_"]["name"]>>(select: S): (options: FindAllOptions<T>) => Promise<({ [Key in keyof T["_"]["columns"] & string as Key]: T["_"]["columns"][Key]["_"]["notNull"] extends true ? T["_"]["columns"][Key]["_"]["data"] : T["_"]["columns"][Key]["_"]["data"] | null; } extends infer T_1 ? { [K in keyof T_1]: T_1[K]; } : never)[]>;
11
+ constructor(db: NodePgDatabase<TSchema>, table: T, map: FilterMap<FSchema>);
12
+ findOne<S extends PgSelect>(select: S): (id: number) => Promise<S>;
13
+ findAll<S extends PgSelect>(select: S): (filters?: Filter<FSchema>, page?: number, pageSize?: number) => Promise<S>;
19
14
  create(): (data: InferInsertModel<T>) => Promise<{ [Key in keyof T["_"]["columns"] & string as Key]: T["_"]["columns"][Key]["_"]["notNull"] extends true ? T["_"]["columns"][Key]["_"]["data"] : T["_"]["columns"][Key]["_"]["data"] | null; } extends infer T_1 ? { [K in keyof T_1]: T_1[K]; } : never>;
20
- update(): (id: PrimaryKeyType<T>, data: Partial<InferInsertModel<T>>) => Promise<(Record<T["_"]["name"], "not-null"> extends infer T_1 ? T_1 extends Record<T["_"]["name"], "not-null"> ? T_1 extends T_1 ? import("drizzle-orm/query-builders/select.types").GetSelectTableSelection<T> extends infer T_2 ? { [Key in keyof T_2]: T_2[Key] extends infer TField ? TField extends import("drizzle-orm").Table<import("drizzle-orm").TableConfig<import("drizzle-orm").Column<any, object, object>>> ? TField["_"]["name"] extends keyof TNullability ? import("drizzle-orm/query-builders/select.types").ApplyNullability<(TField["_"]["columns"] extends infer T_4 ? { [Key_2 in keyof T_4]: import("drizzle-orm/query-builders/select.types").SelectResultField<T_4[Key_2], TDeep>; } : never) extends infer T_3 ? { [K in keyof T_3]: T_3[K]; } : never, TNullability[TField["_"]["name"]]> : never : TField extends import("drizzle-orm").Column<import("drizzle-orm").ColumnBaseConfig<import("drizzle-orm").ColumnDataType, string>, object, object> ? TField["_"]["tableName"] extends keyof TNullability ? import("drizzle-orm/query-builders/select.types").ApplyNullability<import("drizzle-orm/query-builders/select.types").SelectResultField<TField, true>, TNullability[TField["_"]["tableName"]]> : never : TField extends import("drizzle-orm").SQL<unknown> | import("drizzle-orm").SQL.Aliased<unknown> ? import("drizzle-orm/query-builders/select.types").SelectResultField<TField, true> : TField extends Record<string, any> ? TField[keyof TField] extends import("drizzle-orm").SQL<unknown> | import("drizzle-orm").SQL.Aliased<unknown> | import("drizzle-orm").AnyColumn<{
21
- tableName: infer TTableName extends string;
22
- }> ? (((TTableName extends any ? TTableName extends TTableName ? false : true : never) extends false ? false : true) extends infer T_5 ? T_5 extends ((TTableName extends any ? TTableName extends TTableName ? false : true : never) extends false ? false : true) ? T_5 extends true ? false : true : never : never) extends true ? import("drizzle-orm/query-builders/select.types").ApplyNullability<{ [K_1 in keyof { [Key_3 in keyof TField]: import("drizzle-orm/query-builders/select.types").SelectResultField<TField[Key_3], true>; }]: { [Key_3 in keyof TField]: import("drizzle-orm/query-builders/select.types").SelectResultField<TField[Key_3], true>; }[K_1]; }, TNullability[TTableName]> : TNullability extends TNullability ? { [Key_4 in keyof TField]: TField[Key_4] extends infer TField ? TField extends import("drizzle-orm").Table<import("drizzle-orm").TableConfig<import("drizzle-orm").Column<any, object, object>>> ? TField["_"]["name"] extends keyof TNullability ? import("drizzle-orm/query-builders/select.types").ApplyNullability<(TField["_"]["columns"] extends infer T_7 ? { [Key_2 in keyof T_7]: import("drizzle-orm/query-builders/select.types").SelectResultField<T_7[Key_2], TDeep>; } : never) extends infer T_6 ? { [K in keyof T_6]: T_6[K]; } : never, TNullability[TField["_"]["name"]]> : never : TField extends import("drizzle-orm").Column<import("drizzle-orm").ColumnBaseConfig<import("drizzle-orm").ColumnDataType, string>, object, object> ? TField["_"]["tableName"] extends keyof TNullability ? import("drizzle-orm/query-builders/select.types").ApplyNullability<import("drizzle-orm/query-builders/select.types").SelectResultField<TField, true>, TNullability[TField["_"]["tableName"]]> : never : TField extends import("drizzle-orm").SQL<unknown> | import("drizzle-orm").SQL.Aliased<unknown> ? import("drizzle-orm/query-builders/select.types").SelectResultField<TField, true> : TField extends Record<string, any> ? TField[keyof TField] extends import("drizzle-orm").SQL<unknown> | import("drizzle-orm").SQL.Aliased<unknown> | import("drizzle-orm").AnyColumn<{
23
- tableName: infer TTableName extends string;
24
- }> ? (((TTableName extends any ? TTableName extends TTableName ? false : true : never) extends false ? false : true) extends infer T_8 ? T_8 extends ((TTableName extends any ? TTableName extends TTableName ? false : true : never) extends false ? false : true) ? T_8 extends true ? false : true : never : never) extends true ? import("drizzle-orm/query-builders/select.types").ApplyNullability<{ [K_1 in keyof { [Key_3 in keyof TField]: import("drizzle-orm/query-builders/select.types").SelectResultField<TField[Key_3], true>; }]: { [Key_3 in keyof TField]: import("drizzle-orm/query-builders/select.types").SelectResultField<TField[Key_3], true>; }[K_1]; }, TNullability[TTableName]> : TNullability extends TNullability ? /*elided*/ any : never : never : never : never; } : never : never : never : never; } : never : never : never : never) extends infer T_3 ? T_3 extends (Record<T["_"]["name"], "not-null"> extends infer T_4 ? T_4 extends Record<T["_"]["name"], "not-null"> ? T_4 extends T_4 ? import("drizzle-orm/query-builders/select.types").GetSelectTableSelection<T> extends infer T_5 ? { [Key_1 in keyof T_5]: T_5[Key_1] extends infer TField ? TField extends import("drizzle-orm").Table<import("drizzle-orm").TableConfig<import("drizzle-orm").Column<any, object, object>>> ? TField["_"]["name"] extends keyof TNullability ? import("drizzle-orm/query-builders/select.types").ApplyNullability<(TField["_"]["columns"] extends infer T_7 ? { [Key_3 in keyof T_7]: import("drizzle-orm/query-builders/select.types").SelectResultField<T_7[Key_3], TDeep>; } : never) extends infer T_6 ? { [K in keyof T_6]: T_6[K]; } : never, TNullability[TField["_"]["name"]]> : never : TField extends import("drizzle-orm").Column<import("drizzle-orm").ColumnBaseConfig<import("drizzle-orm").ColumnDataType, string>, object, object> ? TField["_"]["tableName"] extends keyof TNullability ? import("drizzle-orm/query-builders/select.types").ApplyNullability<import("drizzle-orm/query-builders/select.types").SelectResultField<TField, true>, TNullability[TField["_"]["tableName"]]> : never : TField extends import("drizzle-orm").SQL<unknown> | import("drizzle-orm").SQL.Aliased<unknown> ? import("drizzle-orm/query-builders/select.types").SelectResultField<TField, true> : TField extends Record<string, any> ? TField[keyof TField] extends import("drizzle-orm").SQL<unknown> | import("drizzle-orm").SQL.Aliased<unknown> | import("drizzle-orm").AnyColumn<{
25
- tableName: infer TTableName extends string;
26
- }> ? (((TTableName extends any ? TTableName extends TTableName ? false : true : never) extends false ? false : true) extends infer T_8 ? T_8 extends ((TTableName extends any ? TTableName extends TTableName ? false : true : never) extends false ? false : true) ? T_8 extends true ? false : true : never : never) extends true ? import("drizzle-orm/query-builders/select.types").ApplyNullability<{ [K_1 in keyof { [Key_4 in keyof TField]: import("drizzle-orm/query-builders/select.types").SelectResultField<TField[Key_4], true>; }]: { [Key_4 in keyof TField]: import("drizzle-orm/query-builders/select.types").SelectResultField<TField[Key_4], true>; }[K_1]; }, TNullability[TTableName]> : TNullability extends TNullability ? { [Key_5 in keyof TField]: TField[Key_5] extends infer TField ? TField extends import("drizzle-orm").Table<import("drizzle-orm").TableConfig<import("drizzle-orm").Column<any, object, object>>> ? TField["_"]["name"] extends keyof TNullability ? import("drizzle-orm/query-builders/select.types").ApplyNullability<(TField["_"]["columns"] extends infer T_10 ? { [Key_3 in keyof T_10]: import("drizzle-orm/query-builders/select.types").SelectResultField<T_10[Key_3], TDeep>; } : never) extends infer T_9 ? { [K in keyof T_9]: T_9[K]; } : never, TNullability[TField["_"]["name"]]> : never : TField extends import("drizzle-orm").Column<import("drizzle-orm").ColumnBaseConfig<import("drizzle-orm").ColumnDataType, string>, object, object> ? TField["_"]["tableName"] extends keyof TNullability ? import("drizzle-orm/query-builders/select.types").ApplyNullability<import("drizzle-orm/query-builders/select.types").SelectResultField<TField, true>, TNullability[TField["_"]["tableName"]]> : never : TField extends import("drizzle-orm").SQL<unknown> | import("drizzle-orm").SQL.Aliased<unknown> ? import("drizzle-orm/query-builders/select.types").SelectResultField<TField, true> : TField extends Record<string, any> ? TField[keyof TField] extends import("drizzle-orm").SQL<unknown> | import("drizzle-orm").SQL.Aliased<unknown> | import("drizzle-orm").AnyColumn<{
27
- tableName: infer TTableName extends string;
28
- }> ? (((TTableName extends any ? TTableName extends TTableName ? false : true : never) extends false ? false : true) extends infer T_11 ? T_11 extends ((TTableName extends any ? TTableName extends TTableName ? false : true : never) extends false ? false : true) ? T_11 extends true ? false : true : never : never) extends true ? import("drizzle-orm/query-builders/select.types").ApplyNullability<{ [K_1 in keyof { [Key_4 in keyof TField]: import("drizzle-orm/query-builders/select.types").SelectResultField<TField[Key_4], true>; }]: { [Key_4 in keyof TField]: import("drizzle-orm/query-builders/select.types").SelectResultField<TField[Key_4], true>; }[K_1]; }, TNullability[TTableName]> : TNullability extends TNullability ? /*elided*/ any : never : never : never : never; } : never : never : never : never; } : never : never : never : never) ? T_3 extends undefined ? import("pg").QueryResult<never> : T_3[] : never : never>;
15
+ update(): (id: PrimaryKeyType<T>, data: Partial<InferInsertModel<T>>) => Promise<{ [Key in keyof T["_"]["columns"] & string as Key]: T["_"]["columns"][Key]["_"]["notNull"] extends true ? T["_"]["columns"][Key]["_"]["data"] : T["_"]["columns"][Key]["_"]["data"] | null; } extends infer T_1 ? { [K in keyof T_1]: T_1[K]; } : never>;
29
16
  softDelete(): (id: PrimaryKeyType<T>) => Promise<void>;
30
17
  hardDelete(): (id: PrimaryKeyType<T>) => Promise<void>;
31
- count(): (filters: Filter<T>) => Promise<number>;
18
+ count(): (filters?: Filter<FSchema>) => Promise<number>;
32
19
  }
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ServiceBuilder = void 0;
4
4
  const drizzle_orm_1 = require("drizzle-orm");
5
- const utils_1 = require("./utils");
5
+ const filters_1 = require("./filters");
6
6
  const errors_1 = require("./errors");
7
7
  class ServiceBuilder {
8
8
  constructor(db, table, map) {
@@ -14,22 +14,18 @@ class ServiceBuilder {
14
14
  findOne(select) {
15
15
  return async (id) => {
16
16
  const result = await select.where((0, drizzle_orm_1.eq)(this.table.id, id));
17
- if (result.length == 0) {
18
- throw new Error(`${this.tableName} with id ${id} not found`);
19
- }
20
- return result[0];
17
+ if (!result)
18
+ throw notFoundWithId(this.tableName, id);
19
+ return result;
21
20
  };
22
21
  }
23
22
  findAll(select) {
24
- return async (options) => {
25
- const { offset, limit } = (0, utils_1.getPagination)(options);
26
- const conditions = (0, utils_1.getConditions)(options, this.map);
27
- const items = select
28
- .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNull)(this.table.deletedAt), ...conditions))
29
- .limit(limit)
30
- .offset(offset)
31
- .execute();
32
- return items;
23
+ return async (filters, page = 1, pageSize = 10) => {
24
+ const offset = (page - 1) * pageSize;
25
+ return await select
26
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNull)(this.table.deletedAt), (0, filters_1.buildFilters)(this.map, filters)))
27
+ .limit(pageSize)
28
+ .offset(offset);
33
29
  };
34
30
  }
35
31
  create() {
@@ -47,14 +43,14 @@ class ServiceBuilder {
47
43
  if (Object.keys(data).length == 0) {
48
44
  throw new errors_1.BadRequest("update needs at least one field");
49
45
  }
50
- const result = await this.db
46
+ const [result] = await this.db
51
47
  .update(this.table)
52
48
  .set(data)
53
49
  .where((0, drizzle_orm_1.eq)(this.table.id, id))
54
50
  .returning()
55
51
  .catch((e) => (0, errors_1.handleSqlError)(e));
56
52
  if (!result) {
57
- throw new errors_1.NotFound(`${this.tableName} with id ${id} not found`);
53
+ throw notFoundWithId(this.tableName, id);
58
54
  }
59
55
  return result;
60
56
  };
@@ -66,7 +62,7 @@ class ServiceBuilder {
66
62
  .set({ deletedAt: new Date() })
67
63
  .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.table.id, id), (0, drizzle_orm_1.isNull)(this.table.deletedAt)));
68
64
  if (rowCount == 0) {
69
- throw new errors_1.NotFound(`${this.tableName} with id ${id} not found`);
65
+ throw notFoundWithId(this.tableName, id);
70
66
  }
71
67
  };
72
68
  }
@@ -76,7 +72,7 @@ class ServiceBuilder {
76
72
  .delete(this.table)
77
73
  .where((0, drizzle_orm_1.eq)(this.table.id, id));
78
74
  if (rowCount == 0) {
79
- throw new errors_1.NotFound(`${this.tableName} with id ${id} not found`);
75
+ throw notFoundWithId(this.tableName, id);
80
76
  }
81
77
  };
82
78
  }
@@ -85,9 +81,12 @@ class ServiceBuilder {
85
81
  const [result] = await this.db
86
82
  .select({ count: (0, drizzle_orm_1.count)() })
87
83
  .from(this.table)
88
- .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNull)(this.table.deletedAt), (0, utils_1.buildWhere)(filters, this.map)));
84
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNull)(this.table.deletedAt), (0, filters_1.buildFilters)(this.map, filters)));
89
85
  return result.count;
90
86
  };
91
87
  }
92
88
  }
93
89
  exports.ServiceBuilder = ServiceBuilder;
90
+ function notFoundWithId(tableName, id) {
91
+ return new errors_1.NotFound(`${tableName} with id ${id} not found`);
92
+ }
@@ -1,27 +1,31 @@
1
1
  import { SQL } from "drizzle-orm";
2
- import { PgColumn, PgTable } from "drizzle-orm/pg-core";
3
- export interface CRUDService {
2
+ import { AnyPgTable, PgColumn } from "drizzle-orm/pg-core";
3
+ import z, { ZodObject } from "zod";
4
+ export interface CRUDService<FSchema extends ZodObject> {
4
5
  findOne: (id: any) => Promise<any>;
5
- findAll: (options: FindAllOptions<any>) => Promise<any>;
6
- count: (filters: Filter<any>) => Promise<number>;
6
+ findAll: (filters?: Filter<FSchema>, page?: number, pageSize?: number) => Promise<any>;
7
+ count: (filters: Filter<FSchema>) => Promise<number>;
7
8
  create: (data: any) => Promise<any>;
8
9
  update: (id: any, data: Partial<any>) => Promise<any>;
9
10
  delete: (id: any) => Promise<any>;
10
11
  }
12
+ export type PrimaryKeyData<TTable extends AnyPgTable> = {
13
+ [K in keyof TTable["_"]["columns"] as TTable["_"]["columns"][K] extends {
14
+ _: {
15
+ isPrimaryKey: true;
16
+ };
17
+ } ? K : never]: TTable["_"]["columns"][K]["_"]["data"];
18
+ };
11
19
  export interface PaginationParams {
12
20
  page: number;
13
21
  pageSize: number;
14
22
  }
15
- export interface FindAllOptions<T extends PgTable> {
16
- pagination?: PaginationParams;
17
- filters?: Filter<T>;
18
- }
19
- export type Table = PgTable & {
23
+ export type Table = AnyPgTable & {
20
24
  id: PgColumn;
21
25
  deletedAt: PgColumn;
22
26
  };
23
- export type PrimaryKeyType<T extends PgTable> = T["_"]["columns"]["id"]["_"]["data"];
24
- export type Filter<T extends PgTable> = Partial<T["$inferSelect"]>;
25
- export type FilterMap<T extends PgTable> = {
26
- [K in keyof T["$inferSelect"]]?: (value: T["$inferSelect"][K]) => SQL;
27
+ export type PrimaryKeyType<T extends AnyPgTable> = T["_"]["columns"]["id"]["_"]["data"];
28
+ export type FilterMap<Schema extends z.ZodObject, Out = z.infer<Schema>> = {
29
+ [K in keyof Out]: (value: NonNullable<Out[K]>) => SQL;
27
30
  };
31
+ export type Filter<Schema extends ZodObject> = z.infer<Schema>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bradb",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,9 +0,0 @@
1
- import { PgTable } from "drizzle-orm/pg-core";
2
- import { SQL } from "drizzle-orm";
3
- import { Filter, FilterMap, FindAllOptions } from "./types";
4
- export declare function buildWhere<T extends PgTable>(filters: Filter<T>, map: FilterMap<T>): SQL<unknown> | undefined;
5
- export declare function getPagination<T extends PgTable>(options?: FindAllOptions<T>): {
6
- offset: number;
7
- limit: number;
8
- };
9
- export declare function getConditions<T extends PgTable>(options: FindAllOptions<any> | undefined, map: FilterMap<T>): SQL<unknown>[];
package/dist/src/utils.js DELETED
@@ -1,41 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.buildWhere = buildWhere;
4
- exports.getPagination = getPagination;
5
- exports.getConditions = getConditions;
6
- const drizzle_orm_1 = require("drizzle-orm");
7
- function buildWhere(filters, map) {
8
- const conditions = [];
9
- // iteramos sólo sobre las claves de 'map'
10
- for (const key of Object.keys(map)) {
11
- const value = filters[key];
12
- if (value !== undefined) {
13
- // TS sabe que `value` es M[typeof key]
14
- if (map[key]) {
15
- conditions.push(map[key](value));
16
- }
17
- }
18
- }
19
- return conditions.length ? (0, drizzle_orm_1.and)(...conditions) : undefined;
20
- }
21
- function withPagination(qb, pagination) {
22
- return qb.limit(pagination.pageSize).offset(pagination.page * pagination.pageSize);
23
- }
24
- function withFilters(table, qb, filters, map) {
25
- return qb.where(buildWhere(filters, map));
26
- }
27
- function getPagination(options = {}) {
28
- const page = options.pagination?.page || 1;
29
- const limit = options.pagination?.pageSize || 10;
30
- const offset = (page - 1) * limit;
31
- return { offset, limit };
32
- }
33
- function getConditions(options = {}, map) {
34
- const { filters } = options;
35
- const conditions = [];
36
- if (filters) {
37
- const whereSql = buildWhere(filters, map);
38
- conditions.push(whereSql);
39
- }
40
- return conditions;
41
- }