@entity-access/entity-access 1.0.1

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 (70) hide show
  1. package/.eslintrc.cjs +234 -0
  2. package/.github/workflows/node.yml +44 -0
  3. package/.github/workflows/npm-publish.yml +33 -0
  4. package/.vscode/launch.json +20 -0
  5. package/.vscode/settings.json +39 -0
  6. package/LICENSE +201 -0
  7. package/README.md +247 -0
  8. package/package.json +39 -0
  9. package/src/TestRunner.ts +2 -0
  10. package/src/common/cache/InstanceCache.ts +14 -0
  11. package/src/common/cache/TimedCache.ts +74 -0
  12. package/src/common/symbols/symbols.ts +2 -0
  13. package/src/common/usingAsync.ts +24 -0
  14. package/src/compiler/ISqlHelpers.ts +30 -0
  15. package/src/compiler/QueryCompiler.ts +88 -0
  16. package/src/compiler/postgres/PostgreSqlMethodTransformer.ts +83 -0
  17. package/src/compiler/sql-server/SqlServerSqlMethodTransformer.ts +83 -0
  18. package/src/decorators/Column.ts +46 -0
  19. package/src/decorators/ForeignKey.ts +42 -0
  20. package/src/decorators/IClassOf.ts +1 -0
  21. package/src/decorators/IColumn.ts +70 -0
  22. package/src/decorators/ISqlType.ts +70 -0
  23. package/src/decorators/SchemaRegistry.ts +19 -0
  24. package/src/decorators/Table.ts +18 -0
  25. package/src/decorators/parser/MemberParser.ts +8 -0
  26. package/src/drivers/base/BaseDriver.ts +134 -0
  27. package/src/drivers/postgres/PostgreSqlDriver.ts +178 -0
  28. package/src/drivers/sql-server/ExpressionToSqlServer.ts +78 -0
  29. package/src/drivers/sql-server/SqlServerDriver.ts +215 -0
  30. package/src/drivers/sql-server/SqlServerLiteral.ts +12 -0
  31. package/src/drivers/sql-server/SqlServerQueryCompiler.ts +25 -0
  32. package/src/entity-query/EntityType.ts +116 -0
  33. package/src/migrations/Migrations.ts +17 -0
  34. package/src/migrations/postgres/PostgresAutomaticMigrations.ts +97 -0
  35. package/src/migrations/postgres/PostgresMigrations.ts +56 -0
  36. package/src/migrations/sql-server/SqlServerAutomaticMigrations.ts +102 -0
  37. package/src/migrations/sql-server/SqlServerMigrations.ts +60 -0
  38. package/src/model/ChangeEntry.ts +154 -0
  39. package/src/model/ChangeSet.ts +88 -0
  40. package/src/model/EntityContext.ts +48 -0
  41. package/src/model/EntityModel.ts +27 -0
  42. package/src/model/EntityQuery.ts +152 -0
  43. package/src/model/EntitySchema.ts +21 -0
  44. package/src/model/EntitySource.ts +98 -0
  45. package/src/model/IFilterWithParameter.ts +38 -0
  46. package/src/model/IdentityService.ts +23 -0
  47. package/src/model/SourceExpression.ts +137 -0
  48. package/src/query/Query.ts +158 -0
  49. package/src/query/ast/ExpressionToSql.ts +348 -0
  50. package/src/query/ast/Expressions.ts +294 -0
  51. package/src/query/ast/IStringTransformer.ts +74 -0
  52. package/src/query/ast/SqlLiteral.ts +25 -0
  53. package/src/query/ast/Visitor.ts +159 -0
  54. package/src/query/parser/ArrowToExpression.ts +160 -0
  55. package/src/query/parser/BabelVisitor.ts +86 -0
  56. package/src/sql/ISql.ts +31 -0
  57. package/src/sql/Sql.ts +4 -0
  58. package/src/tests/TestConfig.ts +6 -0
  59. package/src/tests/db-tests/tests/select-items.ts +37 -0
  60. package/src/tests/db-tests/tests/update-items.ts +17 -0
  61. package/src/tests/drivers/postgres/connection-test.ts +29 -0
  62. package/src/tests/drivers/sql-server/sql-server-test.ts +9 -0
  63. package/src/tests/expressions/left-joins/child-joins.ts +71 -0
  64. package/src/tests/expressions/simple/parse-arrow.ts +46 -0
  65. package/src/tests/expressions/trimInternal.ts +23 -0
  66. package/src/tests/model/ShoppingContext.ts +203 -0
  67. package/src/tests/model/createContext.ts +294 -0
  68. package/src/tests/query/combine.ts +28 -0
  69. package/test.js +107 -0
  70. package/tsconfig.json +22 -0
@@ -0,0 +1,294 @@
1
+ import { IClassOf } from "../../decorators/IClassOf.js";
2
+ import { BaseDriver } from "../../drivers/base/BaseDriver.js";
3
+ import { ShoppingContext } from "./ShoppingContext.js";
4
+
5
+ export async function createContext(driver: BaseDriver) {
6
+
7
+ const rn = "d" + Date.now();
8
+ const copy = { ... driver } as BaseDriver;
9
+ (copy as any).connectionString = { ... driver.connectionString };
10
+ copy.connectionString.database = rn;
11
+ Object.setPrototypeOf(copy, Object.getPrototypeOf(driver));
12
+ const context = new ShoppingContext(copy);
13
+
14
+ await context.driver.ensureDatabase();
15
+
16
+ await context.driver.automaticMigrations().migrate(context);
17
+
18
+ await seed(context);
19
+
20
+ return context;
21
+
22
+ }
23
+
24
+ // export default function () {
25
+
26
+ // }
27
+
28
+ async function seed(context: ShoppingContext) {
29
+ const now = new Date();
30
+
31
+ addHeadPhones(context, now);
32
+
33
+ const maleClothes = addMaleClothes(context);
34
+
35
+ const femaleClothes = addFemaleClothes(context);
36
+
37
+ await context.saveChanges();
38
+ }
39
+
40
+ function addFemaleClothes(context: ShoppingContext) {
41
+ const category = context.categories.add({
42
+ name: "Female Clothes",
43
+ categoryID: "clothes/female"
44
+ });
45
+
46
+ const startDate = new Date();
47
+ const active = true;
48
+
49
+ context.products.add({
50
+ name: "White T-Shirt",
51
+ categories: [
52
+ context.productCategories.add({
53
+ category
54
+ })
55
+ ],
56
+ prices: [
57
+ context.productPrices.add({
58
+ amount: 20,
59
+ active,
60
+ startDate
61
+ })
62
+ ]
63
+ });
64
+
65
+ context.products.add({
66
+ name: "Red T-Shirt",
67
+ categories: [
68
+ context.productCategories.add({
69
+ category
70
+ })
71
+ ],
72
+ prices: [
73
+ context.productPrices.add({
74
+ amount: 20,
75
+ active,
76
+ startDate
77
+ })
78
+ ]
79
+ });
80
+
81
+ context.products.add({
82
+ name: "Blue T-Shirt",
83
+ categories: [
84
+ context.productCategories.add({
85
+ category
86
+ })
87
+ ],
88
+ prices: [
89
+ context.productPrices.add({
90
+ amount: 20,
91
+ active,
92
+ startDate
93
+ })
94
+ ]
95
+ });
96
+
97
+ context.products.add({
98
+ name: "Pink T-Shirt",
99
+ categories: [
100
+ context.productCategories.add({
101
+ category
102
+ })
103
+ ],
104
+ prices: [
105
+ context.productPrices.add({
106
+ amount: 20,
107
+ active,
108
+ startDate
109
+ })
110
+ ]
111
+ });
112
+ }
113
+
114
+ function addMaleClothes(context: ShoppingContext) {
115
+ const category = context.categories.add({
116
+ name: "Male Clothes",
117
+ categoryID: "clothes/male"
118
+ });
119
+
120
+ const startDate = new Date();
121
+ const active = true;
122
+
123
+ context.products.add({
124
+ name: "White T-Shirt",
125
+ categories: [
126
+ context.productCategories.add({
127
+ category
128
+ })
129
+ ],
130
+ prices: [
131
+ context.productPrices.add({
132
+ amount: 20,
133
+ active,
134
+ startDate
135
+ })
136
+ ]
137
+ });
138
+
139
+ context.products.add({
140
+ name: "Red T-Shirt",
141
+ categories: [
142
+ context.productCategories.add({
143
+ category
144
+ })
145
+ ],
146
+ prices: [
147
+ context.productPrices.add({
148
+ amount: 20,
149
+ active,
150
+ startDate
151
+ })
152
+ ]
153
+ });
154
+
155
+ context.products.add({
156
+ name: "Blue T-Shirt",
157
+ categories: [
158
+ context.productCategories.add({
159
+ category
160
+ })
161
+ ],
162
+ prices: [
163
+ context.productPrices.add({
164
+ amount: 20,
165
+ active,
166
+ startDate
167
+ })
168
+ ]
169
+ });
170
+
171
+ context.products.add({
172
+ name: "Pink T-Shirt",
173
+ categories: [
174
+ context.productCategories.add({
175
+ category
176
+ })
177
+ ],
178
+ prices: [
179
+ context.productPrices.add({
180
+ amount: 20,
181
+ active,
182
+ startDate
183
+ })
184
+ ]
185
+ });
186
+ }
187
+
188
+ export const headPhoneCategory = "head-phones";
189
+ function addHeadPhones(context: ShoppingContext, now: Date) {
190
+ const category = context.categories.add({
191
+ name: "Headphones",
192
+ categoryID: headPhoneCategory
193
+ });
194
+
195
+ const startDate = new Date();
196
+ const active = true;
197
+
198
+ context.products.add({
199
+ name: "Jabber Head Phones",
200
+ categories: [
201
+ context.productCategories.add({
202
+ category
203
+ })
204
+ ],
205
+ prices: [
206
+ context.productPrices.add({
207
+ active,
208
+ startDate,
209
+ amount: 100
210
+ })
211
+ ]
212
+ });
213
+
214
+ context.products.add({
215
+ name: "Sony Head Phones",
216
+ categories: [
217
+ context.productCategories.add({
218
+ category
219
+ })
220
+ ],
221
+ prices: [
222
+ context.productPrices.add({
223
+ active,
224
+ startDate,
225
+ amount: 120
226
+ })
227
+ ]
228
+ });
229
+
230
+ context.products.add({
231
+ name: "Sony Head Phones Black",
232
+ categories: [
233
+ context.productCategories.add({
234
+ category
235
+ })
236
+ ],
237
+ prices: [
238
+ context.productPrices.add({
239
+ active,
240
+ startDate,
241
+ amount: 140
242
+ })
243
+ ]
244
+ });
245
+
246
+ context.products.add({
247
+ name: "Sony Head Phones Blue",
248
+ categories: [
249
+ context.productCategories.add({
250
+ category
251
+ })
252
+ ],
253
+ prices: [
254
+ context.productPrices.add({
255
+ active,
256
+ startDate,
257
+ amount: 140
258
+ })
259
+ ]
260
+ });
261
+
262
+ context.products.add({
263
+ name: "Jabber Head Phones Black",
264
+ categories: [
265
+ context.productCategories.add({
266
+ category
267
+ })
268
+ ],
269
+ prices: [
270
+ context.productPrices.add({
271
+ active,
272
+ startDate,
273
+ amount: 140
274
+ })
275
+ ]
276
+ });
277
+
278
+ context.products.add({
279
+ name: "Jabber Head Phones Blue",
280
+ categories: [
281
+ context.productCategories.add({
282
+ category
283
+ })
284
+ ],
285
+ prices: [
286
+ context.productPrices.add({
287
+ active,
288
+ startDate,
289
+ amount: 140
290
+ })
291
+ ]
292
+ });
293
+ }
294
+
@@ -0,0 +1,28 @@
1
+ import * as assert from "assert";
2
+ import { IQuery, Query, QueryPart } from "../../query/Query.js";
3
+
4
+ export default function () {
5
+ const id = 1;
6
+ const q = Query.create `SELECT * FROM Accounts WHERE ${id}`;
7
+ assert.equal("SELECT * FROM Accounts WHERE @p0", q.toString());
8
+
9
+ const p = q.parts[1] as QueryPart;
10
+ assert.equal(id, p.value);
11
+
12
+ // lets combine multiple queries...
13
+
14
+ const id2 = 2;
15
+
16
+ const orConstraints = [];
17
+ orConstraints.push(Query.create `ID == ${id}`);
18
+ orConstraints.push(Query.create `ID == ${id2}`);
19
+
20
+ const final = Query.create `SELECT * FROM Accounts WHERE ${Query.join(orConstraints, " OR ")}`;
21
+ assert.equal("SELECT * FROM Accounts WHERE ID == @p0 OR ID == @p1", final.toString());
22
+
23
+ const rn = "D" + Date.now();
24
+ const create = Query.create `CREATE Database ${Query.literal(rn)}`;
25
+ assert.equal(`CREATE Database ${rn}`, create.toString());
26
+
27
+
28
+ }
package/test.js ADDED
@@ -0,0 +1,107 @@
1
+ import { readdir } from "fs/promises";
2
+ import PostgreSqlDriver from "./dist/drivers/postgres/PostgreSqlDriver.js";
3
+ import SqlServerDriver from "./dist/drivers/sql-server/SqlServerDriver.js";
4
+ import * as ports from "tcp-port-used";
5
+
6
+ const host = process.env.POSTGRES_HOST ?? "localhost";
7
+ const postGresPort = Number(process.env.POSTGRES_PORT ?? 5432);
8
+
9
+ // if (process.argv.includes("test-db")) {
10
+ // // wait for ports to open...
11
+ // console.log("Waiting for port to be open");
12
+ // await ports.waitUntilUsedOnHost(port, host, void 0, 15000);
13
+ // }
14
+
15
+ /**
16
+ * @type Array<{ name: string, error: string }>
17
+ */
18
+ const results = [];
19
+
20
+ let start = Date.now();
21
+
22
+ export default class TestRunner {
23
+
24
+ static get drivers() {
25
+ const database = "D" + start++;
26
+ return [
27
+ new PostgreSqlDriver({
28
+ database,
29
+ host,
30
+ user: "postgres",
31
+ password: "abcd123",
32
+ port: postGresPort
33
+ }),
34
+ new SqlServerDriver({
35
+ database,
36
+ host,
37
+ user: "sa",
38
+ password: "$EntityAccess2023",
39
+ port: 1433,
40
+ options: {
41
+ encrypt: true, // for azure
42
+ trustServerCertificate: true // change to true for local dev / self-signed certs
43
+ },
44
+ debug: true
45
+ })
46
+
47
+ ];
48
+ }
49
+
50
+ /**
51
+ *
52
+ * @param {string} name
53
+ */
54
+ static async runTest(name, thisParam) {
55
+ const moduleExports = await import(name);
56
+ const { default: d } = moduleExports;
57
+ if (!d) {
58
+ return;
59
+ }
60
+ try {
61
+
62
+ const r = d.call(thisParam);
63
+ if (r?.then) {
64
+ await r;
65
+ }
66
+ results.push({ name });
67
+ } catch (error) {
68
+ results.unshift({ name, error });
69
+ }
70
+ }
71
+
72
+ static async runAll(dir, db) {
73
+ const items = await readdir(dir, { withFileTypes: true });
74
+ const tasks = [];
75
+ for (const iterator of items) {
76
+ const next = dir + "/" + iterator.name;
77
+ if (iterator.isDirectory()) {
78
+ tasks.push(this.runAll(next, db));
79
+ continue;
80
+ }
81
+ if (iterator.name.endsWith(".js")) {
82
+ for (const driver of this.drivers) {
83
+ tasks.push(this.runTest(next, { driver, db }));
84
+ }
85
+ }
86
+ }
87
+ await Promise.all(tasks);
88
+ }
89
+
90
+ }
91
+
92
+
93
+ await TestRunner.runAll("./dist/tests", true);
94
+
95
+ let exitCode = 0;
96
+
97
+ for (const { error, name } of results) {
98
+ if (error) {
99
+ exitCode = 1;
100
+ console.error(`${name} failed`);
101
+ console.error(error?.stack ?? error);
102
+ continue;
103
+ }
104
+ console.log(`${name} executed.`);
105
+ }
106
+
107
+ process.exit(exitCode);
package/tsconfig.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module":"NodeNext",
5
+ "sourceMap": true,
6
+ "declaration": true,
7
+ "declarationMap": true,
8
+ "outDir": "dist",
9
+ "experimentalDecorators": true,
10
+ "emitDecoratorMetadata": true,
11
+ "lib": [
12
+ "ES2018"
13
+ ]
14
+ },
15
+ "include": [
16
+ "src/**/*"
17
+ ],
18
+ "exclude": [
19
+ "node_modules",
20
+ "tests"
21
+ ]
22
+ }