@tstdl/base 0.92.75 → 0.92.77

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.
@@ -1,5 +1,5 @@
1
1
  import { toCamelCase, toSnakeCase } from 'drizzle-orm/casing';
2
- import { boolean, doublePrecision, index, integer, jsonb, pgSchema, text, unique, uniqueIndex, uuid } from 'drizzle-orm/pg-core';
2
+ import { boolean, doublePrecision, index, integer, jsonb, pgSchema, primaryKey, text, unique, uniqueIndex, uuid } from 'drizzle-orm/pg-core';
3
3
  import { MultiKeyMap } from '../../../data-structures/multi-key-map.js';
4
4
  import { tryGetEnumName } from '../../../enumeration/enumeration.js';
5
5
  import { NotSupportedError } from '../../../errors/not-supported.error.js';
@@ -54,8 +54,13 @@ export function _getDrizzleTableFromType(type, schemaName) {
54
54
  const indexFn = (data.options?.unique == true) ? uniqueIndex : index;
55
55
  return indexFn(data.name).using(data.options?.using ?? 'btree', ...columns);
56
56
  }
57
- const columnEntries = columnDefinitions.map((entry) => [entry.name, entry.type]);
57
+ const primaryKeyColumns = columnDefinitions.filter((columnDefinition) => columnDefinition.reflectionData?.primaryKey == true);
58
+ const skipPrimaryKey = primaryKeyColumns.length > 1;
59
+ const columnEntries = columnDefinitions.map((entry) => [entry.name, entry.buildType({ skipPrimaryKey })]);
58
60
  const drizzleSchema = dbSchema.table(tableName, fromEntries(columnEntries), (table) => [
61
+ ...((primaryKeyColumns.length > 1)
62
+ ? [primaryKey({ columns: primaryKeyColumns.map((columnDefinition) => getColumn(table, columnDefinition.name)) })]
63
+ : []),
59
64
  ...(columnDefinitions.map((columnDefinition) => {
60
65
  const indexData = columnDefinition.reflectionData?.index;
61
66
  if (isUndefined(indexData)) {
@@ -105,21 +110,19 @@ function getPostgresColumnEntries(type, tableName, dbSchema, path = new JsonPath
105
110
  }
106
111
  : (value) => value;
107
112
  const prefixedColumnName = [prefix, columnName].join('');
108
- return [
109
- {
113
+ return [{
110
114
  name: toCamelCase(prefixedColumnName),
111
115
  objectPath,
112
- type: getPostgresColumn(toSnakeCase(prefixedColumnName), dbSchema, schema, columnReflectionData ?? {}, { type, property }),
113
116
  reflectionData: columnReflectionData,
117
+ buildType: (options) => getPostgresColumn(toSnakeCase(prefixedColumnName), dbSchema, schema, columnReflectionData ?? {}, options, { type, property }),
114
118
  dereferenceObjectPath: compileDereferencer(objectPath, { optional: true }),
115
119
  toDatabase,
116
120
  fromDatabase
117
- }
118
- ];
121
+ }];
119
122
  });
120
123
  return entries;
121
124
  }
122
- function getPostgresColumn(columnName, dbSchema, propertySchema, reflectionData, context) {
125
+ function getPostgresColumn(columnName, dbSchema, propertySchema, reflectionData, options, context) {
123
126
  let nullable = false;
124
127
  let array = false;
125
128
  let baseSchema = propertySchema;
@@ -146,7 +149,7 @@ function getPostgresColumn(columnName, dbSchema, propertySchema, reflectionData,
146
149
  if (isDefined(reflectionData.unique)) {
147
150
  column = column.unique(reflectionData.unique.name, isString(reflectionData.unique.options?.nulls) ? { nulls: reflectionData.unique.options.nulls } : undefined);
148
151
  }
149
- if (reflectionData.primaryKey == true) {
152
+ if ((reflectionData.primaryKey == true) && (options.skipPrimaryKey != true)) {
150
153
  column = column.primaryKey();
151
154
  }
152
155
  if (isDefined(reflectionData.references)) {
@@ -60,6 +60,12 @@ export declare class EntityRepository<T extends Entity = Entity> implements Reso
60
60
  has(id: string): Promise<boolean>;
61
61
  hasByQuery(query: Query<T>): Promise<boolean>;
62
62
  hasAll(ids: string[]): Promise<boolean>;
63
+ /**
64
+ * Tries to insert using ON CONFLICT DO NOTHING
65
+ * @param entity entity to insert
66
+ * @returns entity if inserted, undefined on conflict
67
+ */
68
+ tryInsert(entity: NewEntity<T>): Promise<T | undefined>;
63
69
  insert(entity: NewEntity<T>): Promise<T>;
64
70
  insertMany(entities: NewEntity<T>[]): Promise<T[]>;
65
71
  upsert(target: OneOrMany<Paths<UntaggedDeep<T>>>, entity: NewEntity<T>, update?: EntityUpdate<T>): Promise<T>;
@@ -78,7 +84,8 @@ export declare class EntityRepository<T extends Entity = Entity> implements Reso
78
84
  deleteManyByQuery(query: Query<T>, metadataUpdate?: EntityMetadataUpdate): Promise<T[]>;
79
85
  hardDelete(id: string): Promise<void>;
80
86
  tryHardDelete(id: string): Promise<boolean>;
81
- hardDeleteByQuery(query: Query<T>): Promise<boolean>;
87
+ hardDeleteByQuery(query: Query<T>): Promise<void>;
88
+ tryHardDeleteByQuery(query: Query<T>): Promise<boolean>;
82
89
  hardDeleteMany(ids: string[]): Promise<number>;
83
90
  hardDeleteManyByQuery(query: Query<T>): Promise<number>;
84
91
  protected convertQuery(query: Query<T>): SQL;
@@ -185,6 +185,24 @@ let EntityRepository = class EntityRepository {
185
185
  .from(this.table);
186
186
  return assertDefinedPass(result[0]).contains;
187
187
  }
188
+ /**
189
+ * Tries to insert using ON CONFLICT DO NOTHING
190
+ * @param entity entity to insert
191
+ * @returns entity if inserted, undefined on conflict
192
+ */
193
+ async tryInsert(entity) {
194
+ const transformContext = await this.getTransformContext();
195
+ const columns = await this.mapToInsertColumns(entity, transformContext);
196
+ const [row] = await this.session
197
+ .insert(this.table)
198
+ .values(columns)
199
+ .onConflictDoNothing()
200
+ .returning();
201
+ if (isUndefined(row)) {
202
+ return undefined;
203
+ }
204
+ return this.mapToEntity(row, transformContext);
205
+ }
188
206
  async insert(entity) {
189
207
  const transformContext = await this.getTransformContext();
190
208
  const columns = await this.mapToInsertColumns(entity, transformContext);
@@ -359,16 +377,22 @@ let EntityRepository = class EntityRepository {
359
377
  }
360
378
  }
361
379
  async tryHardDelete(id) {
362
- const result = await this.session.delete(this.table).where(eq(this.table.id, id));
363
- console.log({ deleteResult: result });
380
+ const result = await this.session
381
+ .delete(this.table)
382
+ .where(eq(this.table.id, id));
364
383
  return isNotNull(result.rowCount) && (result.rowCount > 0);
365
384
  }
366
385
  async hardDeleteByQuery(query) {
386
+ const result = await this.tryHardDeleteByQuery(query);
387
+ if (!result) {
388
+ throw new NotFoundError(`${this.type.entityName} not found.`);
389
+ }
390
+ }
391
+ async tryHardDeleteByQuery(query) {
367
392
  const idQuery = this.getIdLimitQuery(query);
368
393
  const result = await this.session
369
394
  .delete(this.table)
370
395
  .where(inArray(this.table.id, idQuery));
371
- console.log({ deleteResult: result });
372
396
  return isNotNull(result.rowCount) && (result.rowCount > 0);
373
397
  }
374
398
  async hardDeleteMany(ids) {
@@ -376,8 +400,9 @@ let EntityRepository = class EntityRepository {
376
400
  }
377
401
  async hardDeleteManyByQuery(query) {
378
402
  const sqlQuery = this.convertQuery(query);
379
- const result = await this.session.delete(this.table).where(sqlQuery);
380
- console.log({ deleteResult: result });
403
+ const result = await this.session
404
+ .delete(this.table)
405
+ .where(sqlQuery);
381
406
  return assertNotNullPass(result.rowCount);
382
407
  }
383
408
  convertQuery(query) {
@@ -8,11 +8,14 @@ import type { Tagged } from '../../types/index.js';
8
8
  import type { OrmColumnReflectionData } from '../decorators.js';
9
9
  import type { EntityType } from '../entity.js';
10
10
  import type { ColumnBuilder, EmbeddedConfigTag } from '../types.js';
11
+ export type BuildTypeOptions = {
12
+ skipPrimaryKey?: boolean;
13
+ };
11
14
  export type ColumnDefinition = {
12
15
  name: string;
13
16
  objectPath: JsonPath;
14
- type: PgColumnBuilder<any, any, any, any>;
15
17
  reflectionData: OrmColumnReflectionData | undefined;
18
+ buildType: (options: BuildTypeOptions) => PgColumnBuilder<any, any, any, any>;
16
19
  dereferenceObjectPath: (obj: Record) => any;
17
20
  toDatabase: (value: unknown, context: TransformContext) => any;
18
21
  fromDatabase: (value: unknown, context: TransformContext) => any;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tstdl/base",
3
- "version": "0.92.75",
3
+ "version": "0.92.77",
4
4
  "author": "Patrick Hein",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -148,14 +148,14 @@
148
148
  "@typescript-eslint/eslint-plugin": "8.24",
149
149
  "concurrently": "9.1",
150
150
  "drizzle-kit": "0.30",
151
- "eslint": "9.20",
151
+ "eslint": "9.21",
152
152
  "globals": "16.0",
153
153
  "tsc-alias": "1.8",
154
154
  "typescript": "5.7"
155
155
  },
156
156
  "peerDependencies": {
157
157
  "@elastic/elasticsearch": "^8.17",
158
- "@google/generative-ai": "^0.21",
158
+ "@google/generative-ai": "^0.22",
159
159
  "@tstdl/angular": "^0.92",
160
160
  "@zxcvbn-ts/core": "^3.0",
161
161
  "@zxcvbn-ts/language-common": "^3.0",