@tstdl/base 0.93.8 → 0.93.10

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.
Files changed (42) hide show
  1. package/audit/module.d.ts +3 -3
  2. package/audit/module.js +3 -3
  3. package/document-management/api/document-management.api.d.ts +6 -6
  4. package/document-management/service-models/document.service-model.d.ts +3 -3
  5. package/orm/decorators.d.ts +35 -3
  6. package/orm/decorators.js +6 -0
  7. package/orm/query.d.ts +49 -30
  8. package/orm/query.js +2 -6
  9. package/orm/repository.types.d.ts +58 -0
  10. package/orm/server/database.js +2 -1
  11. package/orm/server/drizzle/schema-converter.js +31 -2
  12. package/orm/server/query-converter.d.ts +5 -7
  13. package/orm/server/query-converter.js +69 -15
  14. package/orm/server/repository.d.ts +13 -5
  15. package/orm/server/repository.js +106 -4
  16. package/orm/sqls.d.ts +143 -8
  17. package/orm/sqls.js +143 -8
  18. package/package.json +3 -3
  19. package/schema/schemas/object.js +1 -1
  20. package/test/drizzle/0000_sudden_sphinx.sql +9 -0
  21. package/test/drizzle/meta/0000_snapshot.json +79 -0
  22. package/test/drizzle/meta/_journal.json +13 -0
  23. package/test/drizzle.config.d.ts +2 -0
  24. package/test/drizzle.config.js +11 -0
  25. package/test/index.d.ts +3 -0
  26. package/test/index.js +3 -0
  27. package/test/module.d.ts +6 -0
  28. package/test/module.js +17 -0
  29. package/test/schemas.d.ts +3 -0
  30. package/test/schemas.js +4 -0
  31. package/test/test.model.d.ts +8 -0
  32. package/test/test.model.js +345 -0
  33. package/test1.d.ts +1 -0
  34. package/test1.js +56 -0
  35. package/test3.d.ts +1 -0
  36. package/test3.js +47 -0
  37. package/test4.d.ts +23 -0
  38. package/test4.js +168 -0
  39. package/test5.d.ts +1 -0
  40. package/test5.js +22 -0
  41. package/test6.d.ts +1 -0
  42. package/test6.js +53 -0
package/orm/sqls.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * simplifying common SQL operations like generating UUIDs, working with intervals,
5
5
  * and aggregating data.
6
6
  */
7
- import { isNumber } from '../utils/type-guards.js';
7
+ import { isDefined, isNumber, isString } from '../utils/type-guards.js';
8
8
  import { sql, Table } from 'drizzle-orm';
9
9
  /** Drizzle SQL helper for getting the current transaction's timestamp. Returns a Date object. */
10
10
  export const TRANSACTION_TIMESTAMP = sql `transaction_timestamp()`;
@@ -14,7 +14,7 @@ export function autoAlias(column) {
14
14
  return sql `${column}`.as(`${column.table[Table['Symbol']['Name']]}_${column.name}`);
15
15
  }
16
16
  /**
17
- * Creates a Drizzle SQL interval expression.
17
+ * Creates a PostgreSQL interval expression.
18
18
  * @param value - The numeric value of the interval.
19
19
  * @param unit - The unit of the interval (e.g., 'day', 'hour').
20
20
  * @returns A Drizzle SQL object representing the interval.
@@ -23,7 +23,7 @@ export function interval(value, unit) {
23
23
  return sql `(${value} ||' ${sql.raw(unit)}')::interval`;
24
24
  }
25
25
  /**
26
- * Creates a Drizzle SQL `array_agg` aggregate function call.
26
+ * Creates a PostgreSQL `array_agg` aggregate function call.
27
27
  * Aggregates values from a column into a PostgreSQL array.
28
28
  * @template T - The Drizzle column type.
29
29
  * @param column - The column to aggregate.
@@ -33,7 +33,7 @@ export function arrayAgg(column) {
33
33
  return sql `array_agg(${column})`;
34
34
  }
35
35
  /**
36
- * Creates a Drizzle SQL `json_agg` aggregate function call.
36
+ * Creates a PostgreSQL `json_agg` aggregate function call.
37
37
  * Aggregates rows or column values into a JSON array.
38
38
  * @template T - The Drizzle table or column type.
39
39
  * @param tableOrColumn - The table or column to aggregate into JSON.
@@ -50,7 +50,7 @@ export function jsonAgg(tableOrColumn) {
50
50
  */
51
51
  jsonAgg.withNull = jsonAgg;
52
52
  /**
53
- * Creates a Drizzle SQL `coalesce` function call.
53
+ * Creates a PostgreSQL `coalesce` function call.
54
54
  * Returns the first non-null value from the provided list of columns or SQL expressions.
55
55
  * @template T - An array type of Drizzle Columns or SQL expressions.
56
56
  * @param columns - The columns or SQL expressions to check.
@@ -60,7 +60,7 @@ export function coalesce(...columns) {
60
60
  return sql `coalesce(${sql.join(columns, sql.raw(', '))})`;
61
61
  }
62
62
  /**
63
- * Creates a Drizzle SQL `to_jsonb` function call.
63
+ * Creates a PostgreSQL `to_jsonb` function call.
64
64
  * Converts the input column or SQL expression to a JSONB value.
65
65
  * @template T - The Drizzle column or SQL expression type.
66
66
  * @param column - The column or SQL expression to convert.
@@ -70,7 +70,7 @@ export function toJsonb(column) {
70
70
  return sql `to_jsonb(${column})`;
71
71
  }
72
72
  /**
73
- * Creates a Drizzle SQL `num_nulls` function call.
73
+ * Creates a PostgreSQL `num_nulls` function call.
74
74
  * Counts the number of null arguments.
75
75
  * @param columns - The columns to check for nulls.
76
76
  * @returns A Drizzle SQL object representing the count of nulls.
@@ -79,7 +79,7 @@ export function numNulls(...columns) {
79
79
  return sql `num_nulls(${sql.join(columns, sql.raw(', '))})`;
80
80
  }
81
81
  /**
82
- * Creates a Drizzle SQL `num_nonnulls` function call.
82
+ * Creates a PostgreSQL `num_nonnulls` function call.
83
83
  * Counts the number of non-null arguments.
84
84
  * @param columns - The columns to check for non-nulls.
85
85
  * @returns A Drizzle SQL object representing the count of non-nulls.
@@ -95,3 +95,138 @@ export function greatest(...values) {
95
95
  const sqlValues = values.map((value) => isNumber(value) ? sql.raw(String(value)) : value);
96
96
  return sql `greatest(${sql.join(sqlValues, sql.raw(', '))})`;
97
97
  }
98
+ function getLanguageSql(language) {
99
+ return isString(language) ? sql `'${sql.raw(language)}'` : sql `${language}`;
100
+ }
101
+ export function toTsVector(language, column) {
102
+ return sql `to_tsvector(${getLanguageSql(language)}, ${column})`;
103
+ }
104
+ /**
105
+ * Creates a PostgreSQL `to_tsquery` function call.
106
+ * This function parses text into a tsquery, respecting operators like & (AND), | (OR), and ! (NOT).
107
+ * @param language The text search configuration (e.g., 'english').
108
+ * @param text The search query text with operators.
109
+ * @returns A Drizzle SQL object representing the tsquery.
110
+ */
111
+ export function toTsQuery(language, text) {
112
+ return sql `to_tsquery(${getLanguageSql(language)}, ${text})`;
113
+ }
114
+ /**
115
+ * Creates a PostgreSQL `plainto_tsquery` function call.
116
+ * This function parses text into tokens and normalizes them, creating a tsquery
117
+ * where tokens are joined by the AND operator. It's useful for raw user input.
118
+ * @param language The text search configuration (e.g., 'english').
119
+ * @param text The search query text.
120
+ * @returns A Drizzle SQL object representing the tsquery.
121
+ */
122
+ export function plainToTsQuery(language, text) {
123
+ return sql `plainto_tsquery(${getLanguageSql(language)}, ${text})`;
124
+ }
125
+ /**
126
+ * Creates a PostgreSQL `phraseto_tsquery` function call.
127
+ * This function is similar to `plainto_tsquery` but creates a tsquery that searches for a phrase.
128
+ * @param language The text search configuration (e.g., 'english').
129
+ * @param text The phrase to search for.
130
+ * @returns A Drizzle SQL object representing the tsquery.
131
+ */
132
+ export function phraseToTsQuery(language, text) {
133
+ return sql `phraseto_tsquery(${getLanguageSql(language)}, ${text})`;
134
+ }
135
+ /**
136
+ * Creates a PostgreSQL `websearch_to_tsquery` function call.
137
+ * This function is similar to `plainto_tsquery` but also handles "quoted phrases"
138
+ * and prefixes terms with `-` or `!` for negation. It's suitable for web search style inputs.
139
+ * @param language The text search configuration (e.g., 'english').
140
+ * @param text The search query text.
141
+ * @returns A Drizzle SQL object representing the tsquery.
142
+ */
143
+ export function websearchToTsQuery(language, text) {
144
+ return sql `websearch_to_tsquery(${getLanguageSql(language)}, ${text})`;
145
+ }
146
+ /**
147
+ * Creates a PostgreSQL `setweight` function call.
148
+ * Assigns a weight ('A', 'B', 'C', 'D') to a tsvector.
149
+ * @param tsvector The tsvector to weight.
150
+ * @param weight The weight to assign.
151
+ * @returns A Drizzle SQL object representing the weighted tsvector.
152
+ */
153
+ export function setweight(tsvector, weight) {
154
+ return sql `setweight(${tsvector}, '${sql.raw(weight)}')`;
155
+ }
156
+ /**
157
+ * Creates a PostgreSQL `ts_rank_cd` function call for relevance ranking.
158
+ * @param tsvector The document's tsvector.
159
+ * @param tsquery The search query's tsquery.
160
+ * @param options Optional configuration for ranking, including weights and normalization.
161
+ * @returns A Drizzle SQL object representing the relevance score.
162
+ */
163
+ export function tsRankCd(tsvector, tsquery, options) {
164
+ const parameters = [];
165
+ if (isDefined(options?.weights)) {
166
+ const weightParts = options.weights.map((w) => sql.raw(String(w)));
167
+ parameters.push(sql `ARRAY[${sql.join(weightParts, sql.raw(', '))}]::real[]`);
168
+ }
169
+ parameters.push(tsvector, tsquery);
170
+ if (isDefined(options?.normalization)) {
171
+ parameters.push(sql `${options.normalization}`);
172
+ }
173
+ return sql `ts_rank_cd(${sql.join(parameters, sql.raw(', '))})`;
174
+ }
175
+ /**
176
+ * Creates a PostgreSQL `ts_headline` function call for highlighting search results.
177
+ *
178
+ * @param language The text search configuration.
179
+ * @param document The original text column.
180
+ * @param tsquery The search query's tsquery.
181
+ * @param options Optional configuration object for ts_headline (e.g., { MaxWords: 10 }).
182
+ * @returns A Drizzle SQL object representing the highlighted text snippet.
183
+ *
184
+ * @warning If using HTML tags for `startSel` and `stopSel` (the default), be aware of
185
+ * Cross-Site Scripting (XSS) vulnerabilities. Ensure the `document` content is
186
+ * properly sanitized before rendering it in a browser if it comes from an untrusted source.
187
+ */
188
+ export function tsHeadline(language, document, tsquery, options) {
189
+ const documentSql = isString(document) ? sql `${document}` : document;
190
+ if (isDefined(options)) {
191
+ const optionsString = Object.entries(options).map(([key, value]) => `${key[0].toUpperCase()}${key.slice(1)}=${String(value)}`).join(', ');
192
+ return sql `ts_headline(${getLanguageSql(language)}, ${documentSql}, ${tsquery}, '${sql.raw(optionsString)}')`;
193
+ }
194
+ return sql `ts_headline(${getLanguageSql(language)}, ${documentSql}, ${tsquery})`;
195
+ }
196
+ /**
197
+ * Creates a PostgreSQL `similarity` function call (from pg_trgm extension).
198
+ * Calculates the similarity between two strings based on trigram matching.
199
+ * @param left The first text column or expression.
200
+ * @param right The second text value or expression to compare against.
201
+ * @returns A Drizzle SQL object representing the similarity score (0 to 1).
202
+ */
203
+ export function similarity(left, right) {
204
+ const leftSql = isString(left) ? sql `${left}` : left;
205
+ const rightSql = isString(right) ? sql `${right}` : right;
206
+ return sql `similarity(${leftSql}, ${rightSql})`;
207
+ }
208
+ /**
209
+ * Creates a PostgreSQL `%` operator call (from pg_trgm extension) for similarity check.
210
+ * Returns true if the similarity between the two arguments is greater than the current similarity threshold.
211
+ * @param left The text column or expression.
212
+ * @param right The text value or expression to compare against.
213
+ * @returns A Drizzle SQL object representing a boolean similarity check.
214
+ */
215
+ export function isSimilar(left, right) {
216
+ const leftSql = isString(left) ? sql `${left}` : left;
217
+ const rightSql = isString(right) ? sql `${right}` : right;
218
+ return sql `(${leftSql}) % (${rightSql})`;
219
+ }
220
+ /**
221
+ * Creates a PostgreSQL `<->` operator call (from pg_trgm extension) for similarity distance.
222
+ * Returns the "distance" between the arguments, that is one minus the similarity() value.
223
+ * This is useful for ordering by similarity with an index.
224
+ * @param left The text column or expression.
225
+ * @param right The text value or expression to compare against.
226
+ * @returns A Drizzle SQL object representing the similarity distance.
227
+ */
228
+ export function similarityDistance(left, right) {
229
+ const leftSql = isString(left) ? sql `${left}` : left;
230
+ const rightSql = isString(right) ? sql `${right}` : right;
231
+ return sql `(${leftSql}) <-> (${rightSql})`;
232
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tstdl/base",
3
- "version": "0.93.8",
3
+ "version": "0.93.10",
4
4
  "author": "Patrick Hein",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -18,7 +18,7 @@
18
18
  "pub": "npm run build:production && npm run cleanup:dist && npm publish dist/",
19
19
  "tsc:watch": "tsc --watch",
20
20
  "tsc-alias:watch": "tsc-alias --watch",
21
- "cleanup:dist": "rm -vf dist/test* && rm -vrf dist/tools/",
21
+ "cleanup:dist": "rm -vrf dist/tools/",
22
22
  "generate:migration": "./scripts/manage-orm.sh generate",
23
23
  "generate:readmes": "deno run --allow-run=code2prompt --allow-read --allow-write=source --allow-net=generativelanguage.googleapis.com --allow-env=GEMINI_API_KEY generate-readmes.ts",
24
24
  "generate:readmes:new-only": "npm run generate:readmes -- --skip-existing",
@@ -136,7 +136,7 @@
136
136
  },
137
137
  "peerDependencies": {
138
138
  "@google-cloud/storage": "^7.17",
139
- "@google/genai": "^1.24",
139
+ "@google/genai": "^1.25",
140
140
  "@tstdl/angular": "^0.93",
141
141
  "@zxcvbn-ts/core": "^3.0",
142
142
  "@zxcvbn-ts/language-common": "^3.0",
@@ -167,7 +167,7 @@ function getObjectSchemaPropertiesFromReflection(metadata, type) {
167
167
  const properties = {};
168
168
  for (const [key, propertyMetadata] of metadata.properties) {
169
169
  const reflectionData = propertyMetadata.data.tryGet('schema');
170
- const propertySchema = schemaReflectionDataToSchema(reflectionData, type, { type, key });
170
+ const propertySchema = schemaReflectionDataToSchema(reflectionData, propertyMetadata.type, { type, key });
171
171
  properties[key] = propertySchema;
172
172
  }
173
173
  for (const [key] of metadata.methods) {
@@ -0,0 +1,9 @@
1
+ CREATE TABLE "test"."test" (
2
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
3
+ "title" text NOT NULL,
4
+ "content" text NOT NULL,
5
+ "tags" text NOT NULL,
6
+ "language" text NOT NULL
7
+ );
8
+ --> statement-breakpoint
9
+ CREATE INDEX "test_title_content_tags_idx" ON "test"."test" USING gin ((setweight(to_tsvector('simple', "title"), 'A') || setweight(to_tsvector('simple', "content"), 'B') || setweight(to_tsvector('simple', "tags"), 'C')));
@@ -0,0 +1,79 @@
1
+ {
2
+ "id": "5c221821-4273-489d-b533-2f49653ab8d1",
3
+ "prevId": "00000000-0000-0000-0000-000000000000",
4
+ "version": "7",
5
+ "dialect": "postgresql",
6
+ "tables": {
7
+ "test.test": {
8
+ "name": "test",
9
+ "schema": "test",
10
+ "columns": {
11
+ "id": {
12
+ "name": "id",
13
+ "type": "uuid",
14
+ "primaryKey": true,
15
+ "notNull": true,
16
+ "default": "gen_random_uuid()"
17
+ },
18
+ "title": {
19
+ "name": "title",
20
+ "type": "text",
21
+ "primaryKey": false,
22
+ "notNull": true
23
+ },
24
+ "content": {
25
+ "name": "content",
26
+ "type": "text",
27
+ "primaryKey": false,
28
+ "notNull": true
29
+ },
30
+ "tags": {
31
+ "name": "tags",
32
+ "type": "text",
33
+ "primaryKey": false,
34
+ "notNull": true
35
+ },
36
+ "language": {
37
+ "name": "language",
38
+ "type": "text",
39
+ "primaryKey": false,
40
+ "notNull": true
41
+ }
42
+ },
43
+ "indexes": {
44
+ "test_title_content_tags_idx": {
45
+ "name": "test_title_content_tags_idx",
46
+ "columns": [
47
+ {
48
+ "expression": "(setweight(to_tsvector(\"language\"::regconfig, \"title\"), 'A') || setweight(to_tsvector(\"language\"::regconfig, \"content\"), 'B') || setweight(to_tsvector(\"language\"::regconfig, \"tags\"), 'C'))",
49
+ "asc": true,
50
+ "isExpression": true,
51
+ "nulls": "last"
52
+ }
53
+ ],
54
+ "isUnique": false,
55
+ "concurrently": false,
56
+ "method": "gin",
57
+ "with": {}
58
+ }
59
+ },
60
+ "foreignKeys": {},
61
+ "compositePrimaryKeys": {},
62
+ "uniqueConstraints": {},
63
+ "policies": {},
64
+ "checkConstraints": {},
65
+ "isRLSEnabled": false
66
+ }
67
+ },
68
+ "enums": {},
69
+ "schemas": {},
70
+ "sequences": {},
71
+ "roles": {},
72
+ "policies": {},
73
+ "views": {},
74
+ "_meta": {
75
+ "columns": {},
76
+ "schemas": {},
77
+ "tables": {}
78
+ }
79
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "version": "7",
3
+ "dialect": "postgresql",
4
+ "entries": [
5
+ {
6
+ "idx": 0,
7
+ "version": "7",
8
+ "when": 1760697525756,
9
+ "tag": "0000_sudden_sphinx",
10
+ "breakpoints": true
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,2 @@
1
+ declare const _default: import("drizzle-kit").Config;
2
+ export default _default;
@@ -0,0 +1,11 @@
1
+ import { relative, resolve } from 'node:path';
2
+ import { defineConfig } from 'drizzle-kit';
3
+ export default defineConfig({
4
+ dialect: 'postgresql',
5
+ out: relative('./', resolve(__dirname, './drizzle/').replace('dist', 'source')),
6
+ schema: resolve(__dirname, './schemas.js'),
7
+ migrations: {
8
+ schema: 'test',
9
+ table: '_migrations',
10
+ },
11
+ });
@@ -0,0 +1,3 @@
1
+ export * from './module.js';
2
+ export * from './schemas.js';
3
+ export * from './test.model.js';
package/test/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from './module.js';
2
+ export * from './schemas.js';
3
+ export * from './test.model.js';
@@ -0,0 +1,6 @@
1
+ import { type DatabaseConfig } from '../orm/server/index.js';
2
+ export declare class TestModuleConfig {
3
+ database?: DatabaseConfig;
4
+ }
5
+ export declare function configureTest(config: TestModuleConfig): void;
6
+ export declare function migrateTestSchema(): Promise<void>;
package/test/module.js ADDED
@@ -0,0 +1,17 @@
1
+ import { inject, Injector } from '../injector/index.js';
2
+ import { Database, migrate } from '../orm/server/index.js';
3
+ export class TestModuleConfig {
4
+ database;
5
+ }
6
+ export function configureTest(config) {
7
+ Injector.register(TestModuleConfig, { useValue: config });
8
+ }
9
+ export async function migrateTestSchema() {
10
+ const connection = inject(TestModuleConfig, undefined, { optional: true })?.database?.connection;
11
+ const database = inject(Database, connection);
12
+ await migrate(database, {
13
+ migrationsSchema: 'test',
14
+ migrationsTable: '_migrations',
15
+ migrationsFolder: import.meta.resolve('./drizzle').replace('file://', ''),
16
+ });
17
+ }
@@ -0,0 +1,3 @@
1
+ import { Test } from './test.model.js';
2
+ export declare const testSchema: import("../orm/server/index.js").DatabaseSchema<"test">;
3
+ export declare const test: import("../orm/server/types.js").PgTableFromType<typeof Test, "test">;
@@ -0,0 +1,4 @@
1
+ import { databaseSchema } from '../orm/server/index.js';
2
+ import { Test } from './test.model.js';
3
+ export const testSchema = databaseSchema('test');
4
+ export const test = testSchema.getTable(Test);
@@ -0,0 +1,8 @@
1
+ import { EntityWithoutMetadata, type NewEntity } from '../orm/index.js';
2
+ export declare class Test extends EntityWithoutMetadata {
3
+ title: string;
4
+ content: string;
5
+ tags: string;
6
+ language: string;
7
+ }
8
+ export declare const testData: NewEntity<Test>[];