@loomcore/api 0.0.58 → 0.1.0

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 (271) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +50 -0
  3. package/dist/__tests__/common-test.utils.d.ts +29 -60
  4. package/dist/__tests__/common-test.utils.js +88 -166
  5. package/dist/__tests__/index.d.ts +6 -0
  6. package/dist/__tests__/index.js +6 -0
  7. package/dist/__tests__/models/category.model.d.ts +8 -0
  8. package/dist/__tests__/models/category.model.js +6 -0
  9. package/dist/__tests__/models/mongo-test-entity.model.d.ts +11 -0
  10. package/dist/__tests__/models/mongo-test-entity.model.js +13 -0
  11. package/dist/__tests__/models/product.model.d.ts +17 -0
  12. package/dist/__tests__/models/product.model.js +10 -0
  13. package/dist/__tests__/models/test-entity.model.d.ts +11 -0
  14. package/dist/__tests__/models/test-entity.model.js +10 -0
  15. package/dist/__tests__/models/test-item.model.d.ts +12 -0
  16. package/dist/__tests__/models/test-item.model.js +9 -0
  17. package/dist/__tests__/mongo-db.test-database.d.ts +15 -0
  18. package/dist/__tests__/mongo-db.test-database.js +74 -0
  19. package/dist/__tests__/postgres-test-migrations/001-create-test-entities-table.migration.d.ts +11 -0
  20. package/dist/__tests__/postgres-test-migrations/001-create-test-entities-table.migration.js +59 -0
  21. package/dist/__tests__/postgres-test-migrations/002-create-categories-table.migration.d.ts +11 -0
  22. package/dist/__tests__/postgres-test-migrations/002-create-categories-table.migration.js +52 -0
  23. package/dist/__tests__/postgres-test-migrations/003-create-products-table.migration.d.ts +11 -0
  24. package/dist/__tests__/postgres-test-migrations/003-create-products-table.migration.js +62 -0
  25. package/dist/__tests__/postgres-test-migrations/004-create-test-users-table.migration.d.ts +11 -0
  26. package/dist/__tests__/postgres-test-migrations/004-create-test-users-table.migration.js +66 -0
  27. package/dist/__tests__/postgres-test-migrations/005-create-test-items-table.migration.d.ts +11 -0
  28. package/dist/__tests__/postgres-test-migrations/005-create-test-items-table.migration.js +50 -0
  29. package/dist/__tests__/postgres-test-migrations/run-test-migrations.d.ts +2 -0
  30. package/dist/__tests__/postgres-test-migrations/run-test-migrations.js +22 -0
  31. package/dist/__tests__/postgres.test-database.d.ts +13 -0
  32. package/dist/__tests__/postgres.test-database.js +85 -0
  33. package/dist/__tests__/test-database.interface.d.ts +7 -0
  34. package/dist/__tests__/test-express-app.d.ts +9 -7
  35. package/dist/__tests__/test-express-app.js +38 -48
  36. package/dist/__tests__/test-mongo-db.d.ts +14 -0
  37. package/dist/__tests__/test-mongo-db.js +81 -0
  38. package/dist/__tests__/test-objects.d.ts +23 -0
  39. package/dist/__tests__/test-objects.js +45 -0
  40. package/dist/__tests__/test-user.d.ts +3 -0
  41. package/dist/__tests__/test-user.js +16 -0
  42. package/dist/config/base-api-config.d.ts +2 -2
  43. package/dist/config/base-api-config.js +2 -2
  44. package/dist/controllers/api.controller.d.ts +1 -5
  45. package/dist/controllers/api.controller.js +4 -11
  46. package/dist/controllers/auth.controller.d.ts +2 -2
  47. package/dist/controllers/auth.controller.js +4 -5
  48. package/dist/controllers/organizations.controller.d.ts +2 -2
  49. package/dist/controllers/organizations.controller.js +4 -4
  50. package/dist/controllers/users.controller.d.ts +2 -2
  51. package/dist/controllers/users.controller.js +2 -2
  52. package/dist/databases/index.d.ts +1 -0
  53. package/dist/databases/index.js +1 -0
  54. package/dist/databases/models/constants.d.ts +1 -0
  55. package/dist/databases/models/constants.js +1 -0
  56. package/dist/databases/models/database.d.ts +3 -0
  57. package/dist/databases/models/database.interface.d.ts +28 -0
  58. package/dist/databases/models/delete-result.d.ts +5 -0
  59. package/dist/databases/models/delete-result.js +8 -0
  60. package/dist/databases/models/index.d.ts +5 -0
  61. package/dist/databases/models/index.js +5 -0
  62. package/dist/databases/models/update-result.d.ts +5 -0
  63. package/dist/databases/models/update-result.js +8 -0
  64. package/dist/databases/mongo-db/commands/batch-update.command.d.ts +3 -0
  65. package/dist/databases/mongo-db/commands/batch-update.command.js +41 -0
  66. package/dist/databases/mongo-db/commands/create-many.command.d.ts +5 -0
  67. package/dist/databases/mongo-db/commands/create-many.command.js +17 -0
  68. package/dist/databases/mongo-db/commands/create.command.d.ts +5 -0
  69. package/dist/databases/mongo-db/commands/create.command.js +17 -0
  70. package/dist/databases/mongo-db/commands/delete-by-id.command.d.ts +3 -0
  71. package/dist/databases/mongo-db/commands/delete-by-id.command.js +9 -0
  72. package/dist/databases/mongo-db/commands/delete-many.command.d.ts +4 -0
  73. package/dist/databases/mongo-db/commands/delete-many.command.js +9 -0
  74. package/dist/databases/mongo-db/commands/full-updateby-id.command.d.ts +3 -0
  75. package/dist/databases/mongo-db/commands/full-updateby-id.command.js +21 -0
  76. package/dist/databases/mongo-db/commands/index.d.ts +8 -0
  77. package/dist/databases/mongo-db/commands/index.js +8 -0
  78. package/dist/databases/mongo-db/commands/mongo-batch-update.command.d.ts +4 -0
  79. package/dist/databases/mongo-db/commands/mongo-batch-update.command.js +41 -0
  80. package/dist/databases/mongo-db/commands/mongo-create-many.command.d.ts +5 -0
  81. package/dist/databases/mongo-db/commands/mongo-create-many.command.js +17 -0
  82. package/dist/databases/mongo-db/commands/mongo-create.command.d.ts +5 -0
  83. package/dist/databases/mongo-db/commands/mongo-create.command.js +17 -0
  84. package/dist/databases/mongo-db/commands/mongo-delete-by-id.command.d.ts +3 -0
  85. package/dist/databases/mongo-db/commands/mongo-delete-by-id.command.js +14 -0
  86. package/dist/databases/mongo-db/commands/mongo-delete-many.command.d.ts +4 -0
  87. package/dist/databases/mongo-db/commands/mongo-delete-many.command.js +9 -0
  88. package/dist/databases/mongo-db/commands/mongo-full-updateby-id.command.d.ts +3 -0
  89. package/dist/databases/mongo-db/commands/mongo-full-updateby-id.command.js +25 -0
  90. package/dist/databases/mongo-db/commands/mongo-partial-update-by-id.command.d.ts +3 -0
  91. package/dist/databases/mongo-db/commands/mongo-partial-update-by-id.command.js +25 -0
  92. package/dist/databases/mongo-db/commands/mongo-update.command.d.ts +4 -0
  93. package/dist/databases/mongo-db/commands/mongo-update.command.js +19 -0
  94. package/dist/databases/mongo-db/commands/partial-update-by-id.command.d.ts +3 -0
  95. package/dist/databases/mongo-db/commands/partial-update-by-id.command.js +21 -0
  96. package/dist/databases/mongo-db/commands/update.command.d.ts +4 -0
  97. package/dist/databases/mongo-db/commands/update.command.js +19 -0
  98. package/dist/databases/mongo-db/index.d.ts +4 -0
  99. package/dist/databases/mongo-db/index.js +4 -0
  100. package/dist/databases/mongo-db/models/no-sql-pipeline.d.ts +15 -0
  101. package/dist/databases/mongo-db/models/no-sql-pipeline.interface.d.ts +11 -0
  102. package/dist/databases/mongo-db/models/no-sql-pipeline.js +43 -0
  103. package/dist/databases/mongo-db/mongo-db.database.d.ts +32 -0
  104. package/dist/databases/mongo-db/mongo-db.database.js +65 -0
  105. package/dist/databases/mongo-db/queries/find-one.query.d.ts +3 -0
  106. package/dist/databases/mongo-db/queries/find-one.query.js +9 -0
  107. package/dist/databases/mongo-db/queries/find.query.d.ts +3 -0
  108. package/dist/databases/mongo-db/queries/find.query.js +9 -0
  109. package/dist/databases/mongo-db/queries/get-all.query.d.ts +3 -0
  110. package/dist/databases/mongo-db/queries/get-all.query.js +17 -0
  111. package/dist/databases/mongo-db/queries/get-by-id.query.d.ts +3 -0
  112. package/dist/databases/mongo-db/queries/get-by-id.query.js +20 -0
  113. package/dist/databases/mongo-db/queries/get-count.query.d.ts +2 -0
  114. package/dist/databases/mongo-db/queries/get-count.query.js +5 -0
  115. package/dist/databases/mongo-db/queries/get.query.d.ts +4 -0
  116. package/dist/databases/mongo-db/queries/get.query.js +14 -0
  117. package/dist/databases/mongo-db/queries/index.d.ts +6 -0
  118. package/dist/databases/mongo-db/queries/index.js +6 -0
  119. package/dist/databases/mongo-db/queries/mongo-find-one.query.d.ts +3 -0
  120. package/dist/databases/mongo-db/queries/mongo-find-one.query.js +9 -0
  121. package/dist/databases/mongo-db/queries/mongo-find.query.d.ts +3 -0
  122. package/dist/databases/mongo-db/queries/mongo-find.query.js +9 -0
  123. package/dist/databases/mongo-db/queries/mongo-get-all.query.d.ts +3 -0
  124. package/dist/databases/mongo-db/queries/mongo-get-all.query.js +17 -0
  125. package/dist/databases/mongo-db/queries/mongo-get-by-id.query.d.ts +4 -0
  126. package/dist/databases/mongo-db/queries/mongo-get-by-id.query.js +17 -0
  127. package/dist/databases/mongo-db/queries/mongo-get-count.query.d.ts +2 -0
  128. package/dist/databases/mongo-db/queries/mongo-get-count.query.js +5 -0
  129. package/dist/databases/mongo-db/queries/mongo-get.query.d.ts +4 -0
  130. package/dist/databases/mongo-db/queries/mongo-get.query.js +14 -0
  131. package/dist/databases/mongo-db/utils/build-find-options.util.d.ts +3 -0
  132. package/dist/databases/mongo-db/utils/build-find-options.util.js +15 -0
  133. package/dist/databases/mongo-db/utils/build-no-sql-match.util.d.ts +3 -0
  134. package/dist/databases/mongo-db/utils/build-no-sql-match.util.js +59 -0
  135. package/dist/databases/mongo-db/utils/convert-object-ids-to-strings.util.d.ts +1 -0
  136. package/dist/databases/mongo-db/utils/convert-object-ids-to-strings.util.js +32 -0
  137. package/dist/databases/mongo-db/utils/convert-operations-to-pipeline.util.d.ts +3 -0
  138. package/dist/databases/mongo-db/utils/convert-operations-to-pipeline.util.js +68 -0
  139. package/dist/databases/mongo-db/utils/convert-query-options-to-pipeline.util.d.ts +3 -0
  140. package/dist/databases/mongo-db/utils/convert-query-options-to-pipeline.util.js +31 -0
  141. package/dist/databases/mongo-db/utils/convert-strings-to-object-ids.util.d.ts +3 -0
  142. package/dist/databases/mongo-db/utils/convert-strings-to-object-ids.util.js +72 -0
  143. package/dist/databases/mongo-db/utils/index.d.ts +7 -0
  144. package/dist/databases/mongo-db/utils/index.js +7 -0
  145. package/dist/databases/operations/join.operation.d.ts +7 -0
  146. package/dist/databases/operations/join.operation.js +12 -0
  147. package/dist/databases/operations/operation.d.ts +2 -0
  148. package/dist/databases/postgres/commands/postgres-batch-update.command.d.ts +4 -0
  149. package/dist/databases/postgres/commands/postgres-batch-update.command.js +56 -0
  150. package/dist/databases/postgres/commands/postgres-create-many.command.d.ts +6 -0
  151. package/dist/databases/postgres/commands/postgres-create-many.command.js +63 -0
  152. package/dist/databases/postgres/commands/postgres-create.command.d.ts +6 -0
  153. package/dist/databases/postgres/commands/postgres-create.command.js +29 -0
  154. package/dist/databases/postgres/commands/postgres-delete-by-id.command.d.ts +3 -0
  155. package/dist/databases/postgres/commands/postgres-delete-by-id.command.js +6 -0
  156. package/dist/databases/postgres/commands/postgres-delete-many.command.d.ts +4 -0
  157. package/dist/databases/postgres/commands/postgres-delete-many.command.js +13 -0
  158. package/dist/databases/postgres/commands/postgres-full-update-by-id.command.d.ts +4 -0
  159. package/dist/databases/postgres/commands/postgres-full-update-by-id.command.js +72 -0
  160. package/dist/databases/postgres/commands/postgres-partial-update-by-id.command.d.ts +4 -0
  161. package/dist/databases/postgres/commands/postgres-partial-update-by-id.command.js +42 -0
  162. package/dist/databases/postgres/commands/postgres-update.command.d.ts +5 -0
  163. package/dist/databases/postgres/commands/postgres-update.command.js +48 -0
  164. package/dist/databases/postgres/migrations/001-create-migrations-table.migration.d.ts +11 -0
  165. package/dist/databases/postgres/migrations/001-create-migrations-table.migration.js +52 -0
  166. package/dist/databases/postgres/migrations/002-create-organizations-table.migration.d.ts +11 -0
  167. package/dist/databases/postgres/migrations/002-create-organizations-table.migration.js +55 -0
  168. package/dist/databases/postgres/migrations/003-create-users-table.migration.d.ts +11 -0
  169. package/dist/databases/postgres/migrations/003-create-users-table.migration.js +65 -0
  170. package/dist/databases/postgres/migrations/004-create-refresh-token-table.migration.d.ts +11 -0
  171. package/dist/databases/postgres/migrations/004-create-refresh-token-table.migration.js +57 -0
  172. package/dist/databases/postgres/migrations/index.d.ts +3 -0
  173. package/dist/databases/postgres/migrations/index.js +3 -0
  174. package/dist/databases/postgres/migrations/migration.d.ts +6 -0
  175. package/dist/databases/postgres/migrations/migration.interface.d.ts +6 -0
  176. package/dist/databases/postgres/migrations/migration.interface.js +1 -0
  177. package/dist/databases/postgres/migrations/migration.js +14 -0
  178. package/dist/databases/postgres/migrations/runMigrations.d.ts +2 -0
  179. package/dist/databases/postgres/migrations/runMigrations.js +20 -0
  180. package/dist/databases/postgres/migrations/setup-for-auth.migration.d.ts +2 -0
  181. package/dist/databases/postgres/migrations/setup-for-auth.migration.js +18 -0
  182. package/dist/databases/postgres/migrations/setup-for-multitenant.migration.d.ts +2 -0
  183. package/dist/databases/postgres/migrations/setup-for-multitenant.migration.js +16 -0
  184. package/dist/databases/postgres/postgres.database.d.ts +31 -0
  185. package/dist/databases/postgres/postgres.database.js +69 -0
  186. package/dist/databases/postgres/queries/postgres-find-one.query.d.ts +3 -0
  187. package/dist/databases/postgres/queries/postgres-find-one.query.js +13 -0
  188. package/dist/databases/postgres/queries/postgres-find.query.d.ts +3 -0
  189. package/dist/databases/postgres/queries/postgres-find.query.js +11 -0
  190. package/dist/databases/postgres/queries/postgres-get-all.query.d.ts +3 -0
  191. package/dist/databases/postgres/queries/postgres-get-all.query.js +14 -0
  192. package/dist/databases/postgres/queries/postgres-get-by-id.query.d.ts +4 -0
  193. package/dist/databases/postgres/queries/postgres-get-by-id.query.js +26 -0
  194. package/dist/databases/postgres/queries/postgres-get-count.query.d.ts +2 -0
  195. package/dist/databases/postgres/queries/postgres-get-count.query.js +4 -0
  196. package/dist/databases/postgres/queries/postgres-get.query.d.ts +4 -0
  197. package/dist/databases/postgres/queries/postgres-get.query.js +26 -0
  198. package/dist/databases/postgres/utils/build-count-query.d.ts +3 -0
  199. package/dist/databases/postgres/utils/build-count-query.js +7 -0
  200. package/dist/databases/postgres/utils/build-join-clauses.d.ts +2 -0
  201. package/dist/databases/postgres/utils/build-join-clauses.js +12 -0
  202. package/dist/databases/postgres/utils/build-order-by-clause.d.ts +2 -0
  203. package/dist/databases/postgres/utils/build-order-by-clause.js +8 -0
  204. package/dist/databases/postgres/utils/build-pagination-clause.d.ts +2 -0
  205. package/dist/databases/postgres/utils/build-pagination-clause.js +9 -0
  206. package/dist/databases/postgres/utils/build-select-clause.d.ts +3 -0
  207. package/dist/databases/postgres/utils/build-select-clause.js +28 -0
  208. package/dist/databases/postgres/utils/build-where-clause.d.ts +5 -0
  209. package/dist/databases/postgres/utils/build-where-clause.js +50 -0
  210. package/dist/databases/postgres/utils/columns-and-values-from-entity.d.ts +5 -0
  211. package/dist/databases/postgres/utils/columns-and-values-from-entity.js +9 -0
  212. package/dist/databases/postgres/utils/convert-null-to-undefined.util.d.ts +2 -0
  213. package/dist/databases/postgres/utils/convert-null-to-undefined.util.js +70 -0
  214. package/dist/databases/postgres/utils/transform-join-results.d.ts +2 -0
  215. package/dist/databases/postgres/utils/transform-join-results.js +33 -0
  216. package/dist/databases/utils/database-to-idatabase.util.d.ts +3 -0
  217. package/dist/databases/utils/database-to-idatabase.util.js +14 -0
  218. package/dist/databases/utils/get-property-schema.util.d.ts +2 -0
  219. package/dist/databases/utils/get-property-schema.util.js +15 -0
  220. package/dist/databases/utils/index.d.ts +1 -0
  221. package/dist/databases/utils/index.js +1 -0
  222. package/dist/models/base-api-config.interface.d.ts +3 -2
  223. package/dist/models/index.d.ts +1 -1
  224. package/dist/models/index.js +1 -1
  225. package/dist/models/refresh-token.d.ts +9 -0
  226. package/dist/models/refresh-token.js +2 -0
  227. package/dist/models/refresh-token.model.d.ts +18 -0
  228. package/dist/models/refresh-token.model.js +13 -0
  229. package/dist/models/refresh-token.spec.d.ts +1 -0
  230. package/dist/models/refresh-token.spec.js +12 -0
  231. package/dist/services/auth.service.d.ts +11 -18
  232. package/dist/services/auth.service.js +29 -50
  233. package/dist/services/generic-api-service/generic-api-service.interface.d.ts +29 -0
  234. package/dist/services/generic-api-service/generic-api-service.interface.js +1 -0
  235. package/dist/services/generic-api-service/generic-api.service.d.ts +37 -0
  236. package/dist/services/generic-api-service/generic-api.service.js +178 -0
  237. package/dist/services/index.d.ts +2 -2
  238. package/dist/services/index.js +2 -2
  239. package/dist/services/multi-tenant-api.service.d.ts +9 -6
  240. package/dist/services/multi-tenant-api.service.js +10 -23
  241. package/dist/services/organization.service.d.ts +5 -5
  242. package/dist/services/organization.service.js +9 -6
  243. package/dist/services/password-reset-token.service.d.ts +3 -3
  244. package/dist/services/password-reset-token.service.js +5 -5
  245. package/dist/services/tenant-query-decorator.d.ts +1 -1
  246. package/dist/services/tenant-query-decorator.js +1 -1
  247. package/dist/services/user.service.d.ts +4 -6
  248. package/dist/services/user.service.js +4 -10
  249. package/dist/services/utils/audit-for-create.util.d.ts +2 -0
  250. package/dist/services/utils/audit-for-create.util.js +9 -0
  251. package/dist/services/utils/audit-for-update.util.d.ts +2 -0
  252. package/dist/services/utils/audit-for-update.util.js +7 -0
  253. package/dist/services/utils/strip-sender-provided-system-properties.util.d.ts +2 -0
  254. package/dist/services/utils/strip-sender-provided-system-properties.util.js +15 -0
  255. package/dist/tsconfig.tsbuildinfo +1 -0
  256. package/dist/utils/api.utils.js +2 -1
  257. package/dist/utils/index.d.ts +0 -1
  258. package/dist/utils/index.js +0 -1
  259. package/dist/utils/sql.db.utils.d.ts +14 -0
  260. package/dist/utils/sql.db.utils.js +94 -0
  261. package/package.json +4 -2
  262. package/dist/services/generic-api-service.interface.d.ts +0 -27
  263. package/dist/services/generic-api.service.d.ts +0 -50
  264. package/dist/services/generic-api.service.js +0 -424
  265. package/dist/utils/db.utils.d.ts +0 -27
  266. package/dist/utils/db.utils.js +0 -323
  267. /package/dist/{controllers/api-controller.utils.d.ts → __tests__/test-database.interface.js} +0 -0
  268. /package/dist/{controllers/api-controller.utils.js → databases/models/database.interface.js} +0 -0
  269. /package/dist/{models/types/index.d.ts → databases/models/database.js} +0 -0
  270. /package/dist/{models/types/index.js → databases/mongo-db/models/no-sql-pipeline.interface.js} +0 -0
  271. /package/dist/{services/generic-api-service.interface.js → databases/operations/operation.js} +0 -0
@@ -1,70 +1,41 @@
1
- import { ObjectId } from 'mongodb';
2
1
  import crypto from 'crypto';
3
2
  import jwt from 'jsonwebtoken';
3
+ import { getSystemUserContext } from '@loomcore/common/models';
4
4
  import { Type } from '@sinclair/typebox';
5
- import { TypeboxObjectId } from '@loomcore/common/validation';
6
5
  import { JwtService } from '../services/jwt.service.js';
7
- import { passwordUtils } from '../utils/password.utils.js';
8
- import { AuthService } from '../services/auth.service.js';
9
- import { GenericApiService } from '../services/generic-api.service.js';
10
6
  import { ApiController } from '../controllers/api.controller.js';
11
- import { entityUtils } from '@loomcore/common/utils';
12
7
  import { MultiTenantApiService } from '../services/multi-tenant-api.service.js';
13
- let db;
14
- let collections = {};
8
+ import { Join } from '../databases/operations/join.operation.js';
9
+ import { OrganizationService } from '../services/organization.service.js';
10
+ import { IdNotFoundError } from '../errors/index.js';
11
+ import { AuthService, GenericApiService } from '../services/index.js';
12
+ import { ObjectId } from 'mongodb';
13
+ import { testMetaOrg, testOrg, getTestUser, testUserContext } from './test-objects.js';
14
+ import { CategorySpec } from './models/category.model.js';
15
+ import { ProductSpec } from './models/product.model.js';
15
16
  let deviceIdCookie;
16
17
  let authService;
17
- let testUser;
18
+ let organizationService;
18
19
  const JWT_SECRET = 'test-secret';
19
20
  const newUser1Email = 'one@test.com';
20
21
  const newUser1Password = 'testone';
21
- const testUserId = '67f33ed5b75090e0dda18a3c';
22
- const testOrgId = '67e8e19b149f740323af93d7';
23
- const testOrgName = 'Test Organization';
24
- const testUserEmail = 'test@example.com';
25
- const testUserEmailCaseInsensitive = 'tesT@example.com';
26
- const testUserPassword = 'testPassword';
27
22
  const constDeviceIdCookie = crypto.randomBytes(16).toString('hex');
28
- const testUserContext = {
29
- user: {
30
- _id: testUserId,
31
- email: testUserEmail,
32
- _created: new Date(),
33
- _createdBy: 'system',
34
- _updated: new Date(),
35
- _updatedBy: 'system'
36
- },
37
- _orgId: testOrgId
38
- };
39
23
  function initialize(database) {
40
- db = database;
41
- collections = {
42
- users: db.collection('users'),
43
- organizations: db.collection('organizations'),
44
- };
45
- authService = new AuthService(db);
24
+ authService = new AuthService(database);
25
+ organizationService = new OrganizationService(database);
26
+ deviceIdCookie = constDeviceIdCookie;
46
27
  }
47
- async function createIndexes(db) {
48
- await db.command({
49
- createIndexes: "users", indexes: [{ key: { email: 1 }, name: 'email_index', unique: true, collation: { locale: 'en', strength: 1 } }]
50
- });
28
+ function getRandomId() {
29
+ return new ObjectId().toString();
51
30
  }
52
31
  async function createMetaOrg() {
53
- if (!db || !collections.organizations) {
54
- throw new Error('Database not initialized. Call initialize() first.');
32
+ if (!organizationService) {
33
+ throw new Error('OrganizationService not initialized. Call initialize() first.');
55
34
  }
56
35
  try {
57
- const existingMetaOrg = await collections.organizations.findOne({ isMetaOrg: true });
36
+ const existingMetaOrg = await organizationService.findOne(testUserContext, { filters: { isMetaOrg: { eq: true } } });
58
37
  if (!existingMetaOrg) {
59
- const metaOrgInsertResult = await collections.organizations.insertOne({
60
- _id: new ObjectId(),
61
- name: 'Meta Organization',
62
- isMetaOrg: true,
63
- _created: new Date(),
64
- _createdBy: 'system',
65
- _updated: new Date(),
66
- _updatedBy: 'system'
67
- });
38
+ const metaOrgInsertResult = await organizationService.create(testUserContext, testMetaOrg);
68
39
  }
69
40
  }
70
41
  catch (error) {
@@ -73,11 +44,11 @@ async function createMetaOrg() {
73
44
  }
74
45
  }
75
46
  async function deleteMetaOrg() {
76
- if (!collections.organizations) {
47
+ if (!organizationService) {
77
48
  return Promise.resolve();
78
49
  }
79
50
  try {
80
- await collections.organizations.deleteOne({ isMetaOrg: true });
51
+ await organizationService.deleteMany(testUserContext, { filters: { isMetaOrg: { eq: true } } });
81
52
  }
82
53
  catch (error) {
83
54
  console.log('Error deleting meta org:', error);
@@ -94,51 +65,44 @@ async function setupTestUser() {
94
65
  }
95
66
  }
96
67
  async function createTestUser() {
97
- if (!db || !collections.users) {
68
+ if (!authService || !organizationService) {
98
69
  throw new Error('Database not initialized. Call initialize() first.');
99
70
  }
100
71
  try {
101
- const hashedAndSaltedTestUserPassword = await passwordUtils.hashPassword(testUserPassword);
102
- const existingOrg = await collections.organizations.findOne({ _id: testOrgId });
72
+ let existingOrg;
73
+ try {
74
+ existingOrg = await organizationService.getById(testUserContext, testOrg._id);
75
+ }
76
+ catch (error) {
77
+ if (error instanceof IdNotFoundError) {
78
+ existingOrg = null;
79
+ }
80
+ else {
81
+ throw error;
82
+ }
83
+ }
103
84
  if (!existingOrg) {
104
- const orgInsertResult = await collections.organizations.insertOne({
105
- _id: new ObjectId(testOrgId),
106
- name: testOrgName,
107
- _created: new Date(),
108
- _createdBy: 'system',
109
- _updated: new Date(),
110
- _updatedBy: 'system'
111
- });
85
+ await organizationService.create(testUserContext, testOrg);
86
+ }
87
+ const systemUserContext = getSystemUserContext();
88
+ const createdUser = await authService.createUser(systemUserContext, getTestUser());
89
+ if (!createdUser) {
90
+ throw new Error('Failed to create test user');
112
91
  }
113
- const localTestUser = {
114
- _id: new ObjectId(testUserId),
115
- email: testUserEmail,
116
- password: hashedAndSaltedTestUserPassword,
117
- _orgId: testOrgId,
118
- _created: new Date(),
119
- _createdBy: 'system',
120
- _updated: new Date(),
121
- _updatedBy: 'system'
122
- };
123
- const insertResult = await collections.users.insertOne(localTestUser);
124
- delete localTestUser['password'];
125
- testUser = { ...localTestUser, _id: localTestUser._id.toString() };
126
- return localTestUser;
92
+ return createdUser;
127
93
  }
128
94
  catch (error) {
129
95
  console.log('Error in createTestUser:', error);
130
96
  throw error;
131
97
  }
132
98
  }
133
- function deleteTestUser() {
134
- let promises = [];
135
- if (testUser) {
136
- promises.push(collections.users.deleteOne({ _id: testUser._id }));
137
- }
138
- if (collections.organizations) {
139
- promises.push(collections.organizations.deleteOne({ _id: new ObjectId(testOrgId) }));
140
- }
141
- return Promise.all(promises);
99
+ async function deleteTestUser() {
100
+ await authService.deleteById(testUserContext, getTestUser()._id).catch((error) => {
101
+ return null;
102
+ });
103
+ await organizationService.deleteById(testUserContext, testOrg._id).catch((error) => {
104
+ return null;
105
+ });
142
106
  }
143
107
  async function simulateloginWithTestUser() {
144
108
  const req = {
@@ -155,7 +119,7 @@ async function simulateloginWithTestUser() {
155
119
  return res;
156
120
  }
157
121
  };
158
- const loginResponse = await authService.attemptLogin(req, res, testUserEmail, testUserPassword);
122
+ const loginResponse = await authService.attemptLogin(req, res, getTestUser().email, getTestUser().password);
159
123
  if (!loginResponse?.tokens?.accessToken) {
160
124
  throw new Error('Failed to login with test user');
161
125
  }
@@ -164,10 +128,10 @@ async function simulateloginWithTestUser() {
164
128
  function getAuthToken() {
165
129
  const payload = {
166
130
  user: {
167
- _id: new ObjectId(testUserId),
168
- email: testUserEmail
131
+ _id: getTestUser()._id,
132
+ email: getTestUser().email
169
133
  },
170
- _orgId: testOrgId
134
+ _orgId: testOrg._id
171
135
  };
172
136
  const token = JwtService.sign(payload, JWT_SECRET, { expiresIn: 3600 });
173
137
  return `Bearer ${token}`;
@@ -175,64 +139,41 @@ function getAuthToken() {
175
139
  function verifyToken(token) {
176
140
  return JwtService.verify(token, JWT_SECRET);
177
141
  }
178
- export const CategorySchema = Type.Object({
179
- _id: Type.Optional(TypeboxObjectId()),
180
- name: Type.String(),
181
- });
182
- export const CategorySpec = entityUtils.getModelSpec(CategorySchema);
183
- export const ProductSchema = Type.Object({
184
- _id: Type.Optional(TypeboxObjectId()),
185
- name: Type.String(),
186
- description: Type.Optional(Type.String()),
187
- internalNumber: Type.Optional(Type.String()),
188
- categoryId: TypeboxObjectId({ title: 'Category ID' }),
189
- });
190
- export const ProductSpec = entityUtils.getModelSpec(ProductSchema, { isAuditable: true });
191
- export const PublicProductSchema = Type.Omit(ProductSpec.fullSchema, ['internalNumber']);
192
142
  export class CategoryService extends GenericApiService {
193
- constructor(db) {
194
- super(db, 'categories', 'category', CategorySpec);
143
+ constructor(database) {
144
+ super(database, 'categories', 'category', CategorySpec);
195
145
  }
196
146
  }
197
147
  export class CategoryController extends ApiController {
198
- constructor(app, db) {
199
- const categoryService = new CategoryService(db);
148
+ constructor(app, database) {
149
+ const categoryService = new CategoryService(database);
200
150
  super('categories', app, categoryService, 'category', CategorySpec);
201
151
  }
202
152
  }
203
153
  export class ProductService extends GenericApiService {
204
- constructor(db) {
205
- super(db, 'products', 'product', ProductSpec);
154
+ db;
155
+ constructor(database) {
156
+ super(database, 'products', 'product', ProductSpec);
157
+ this.db = database;
206
158
  }
207
- getAdditionalPipelineStages() {
208
- return [
209
- {
210
- $lookup: {
211
- from: 'categories',
212
- localField: 'categoryId',
213
- foreignField: '_id',
214
- as: 'category'
215
- }
216
- },
217
- {
218
- $unwind: {
219
- path: '$category',
220
- preserveNullAndEmptyArrays: true
221
- }
222
- }
159
+ prepareQuery(userContext, queryObject, operations) {
160
+ const newOperations = [
161
+ ...operations,
162
+ new Join('categories', 'categoryId', '_id', 'category')
223
163
  ];
164
+ return super.prepareQuery(userContext, queryObject, newOperations);
224
165
  }
225
- transformSingle(single) {
166
+ postprocessEntity(userContext, single) {
226
167
  if (single && single.category) {
227
168
  const categoryService = new CategoryService(this.db);
228
- single.category = categoryService.transformSingle(single.category);
169
+ single.category = categoryService.postprocessEntity(userContext, single.category);
229
170
  }
230
- return super.transformSingle(single);
171
+ return super.postprocessEntity(userContext, single);
231
172
  }
232
173
  }
233
174
  export class ProductsController extends ApiController {
234
- constructor(app, db) {
235
- const productService = new ProductService(db);
175
+ constructor(app, database) {
176
+ const productService = new ProductService(database);
236
177
  const AggregatedProductSchema = Type.Intersect([
237
178
  ProductSpec.fullSchema,
238
179
  Type.Partial(Type.Object({
@@ -244,38 +185,29 @@ export class ProductsController extends ApiController {
244
185
  }
245
186
  }
246
187
  export class MultiTenantProductService extends MultiTenantApiService {
247
- constructor(db) {
248
- super(db, 'products', 'product', ProductSpec);
188
+ db;
189
+ constructor(database) {
190
+ super(database, 'products', 'product', ProductSpec);
191
+ this.db = database;
249
192
  }
250
- getAdditionalPipelineStages() {
251
- return [
252
- {
253
- $lookup: {
254
- from: 'categories',
255
- localField: 'categoryId',
256
- foreignField: '_id',
257
- as: 'category'
258
- }
259
- },
260
- {
261
- $unwind: {
262
- path: '$category',
263
- preserveNullAndEmptyArrays: true
264
- }
265
- }
193
+ prepareQuery(userContext, queryObject, operations) {
194
+ const newOperations = [
195
+ ...operations,
196
+ new Join('categories', 'categoryId', '_id', 'category')
266
197
  ];
198
+ return super.prepareQuery(userContext, queryObject, newOperations);
267
199
  }
268
- transformSingle(single) {
200
+ postprocessEntity(userContext, single) {
269
201
  if (single && single.category) {
270
202
  const categoryService = new CategoryService(this.db);
271
- single.category = categoryService.transformSingle(single.category);
203
+ single.category = categoryService.postprocessEntity(userContext, single.category);
272
204
  }
273
- return super.transformSingle(single);
205
+ return super.postprocessEntity(userContext, single);
274
206
  }
275
207
  }
276
208
  export class MultiTenantProductsController extends ApiController {
277
- constructor(app, db) {
278
- const productService = new MultiTenantProductService(db);
209
+ constructor(app, database) {
210
+ const productService = new MultiTenantProductService(database);
279
211
  const AggregatedProductSchema = Type.Intersect([
280
212
  ProductSpec.fullSchema,
281
213
  Type.Partial(Type.Object({
@@ -286,9 +218,6 @@ export class MultiTenantProductsController extends ApiController {
286
218
  super('multi-tenant-products', app, productService, 'product', ProductSpec, PublicAggregatedProductSchema);
287
219
  }
288
220
  }
289
- function getTestUser() {
290
- return testUser;
291
- }
292
221
  function configureJwtSecret() {
293
222
  const originalJwtVerify = jwt.verify;
294
223
  jwt.verify = function (token, secret, options) {
@@ -297,11 +226,12 @@ function configureJwtSecret() {
297
226
  }
298
227
  async function loginWithTestUser(agent) {
299
228
  agent.set('Cookie', [`deviceId=${deviceIdCookie}`]);
229
+ const testUser = getTestUser();
300
230
  const response = await agent
301
231
  .post('/api/auth/login')
302
232
  .send({
303
- email: testUserEmail,
304
- password: testUserPassword,
233
+ email: testUser.email,
234
+ password: testUser.password,
305
235
  });
306
236
  if (!response.body?.data?.tokens?.accessToken) {
307
237
  console.error('Login failed:', response.body);
@@ -320,28 +250,20 @@ async function cleanup() {
320
250
  }
321
251
  }
322
252
  const testUtils = {
253
+ getRandomId,
323
254
  cleanup,
324
255
  configureJwtSecret,
325
256
  constDeviceIdCookie,
326
- createIndexes,
327
257
  createMetaOrg,
328
258
  deleteMetaOrg,
329
259
  deleteTestUser,
330
260
  getAuthToken,
331
- getTestUser,
332
261
  initialize,
333
262
  loginWithTestUser,
334
263
  newUser1Email,
335
264
  newUser1Password,
336
265
  setupTestUser,
337
266
  simulateloginWithTestUser,
338
- testUserContext,
339
- testUserId,
340
- testUserEmail,
341
- testUserEmailCaseInsensitive,
342
- testUserPassword,
343
- testOrgId,
344
- testOrgName,
345
267
  verifyToken
346
268
  };
347
269
  export default testUtils;
@@ -0,0 +1,6 @@
1
+ export * from './postgres-test-migrations/001-create-test-entities-table.migration.js';
2
+ export * from './models/test-entity.model.js';
3
+ export * from './postgres.test-database.js';
4
+ export * from './mongo-db.test-database.js';
5
+ export * from './test-express-app.js';
6
+ export * from './test-database.interface.js';
@@ -0,0 +1,6 @@
1
+ export * from './postgres-test-migrations/001-create-test-entities-table.migration.js';
2
+ export * from './models/test-entity.model.js';
3
+ export * from './postgres.test-database.js';
4
+ export * from './mongo-db.test-database.js';
5
+ export * from './test-express-app.js';
6
+ export * from './test-database.interface.js';
@@ -0,0 +1,8 @@
1
+ import { IEntity } from "@loomcore/common/models";
2
+ export interface ICategory extends IEntity {
3
+ name: string;
4
+ }
5
+ export declare const CategorySchema: import("@sinclair/typebox").TObject<{
6
+ name: import("@sinclair/typebox").TString;
7
+ }>;
8
+ export declare const CategorySpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
@@ -0,0 +1,6 @@
1
+ import { entityUtils } from "@loomcore/common/utils";
2
+ import { Type } from "@sinclair/typebox";
3
+ export const CategorySchema = Type.Object({
4
+ name: Type.String(),
5
+ });
6
+ export const CategorySpec = entityUtils.getModelSpec(CategorySchema);
@@ -0,0 +1,11 @@
1
+ import { IAuditable, IEntity, IModelSpec } from "@loomcore/common/models";
2
+ import { TSchema } from "@sinclair/typebox";
3
+ export declare const MongoTestEntitySchema: TSchema;
4
+ export interface MongoTestEntity extends IEntity, IAuditable {
5
+ name: string;
6
+ description?: string;
7
+ isActive?: boolean;
8
+ tags?: string[];
9
+ count?: number;
10
+ }
11
+ export declare const mongoTestEntityModelSpec: IModelSpec;
@@ -0,0 +1,13 @@
1
+ import { entityUtils } from "@loomcore/common/utils";
2
+ import { TypeboxObjectId } from "@loomcore/common/validation";
3
+ import { Type } from "@sinclair/typebox";
4
+ export const MongoTestEntitySchema = Type.Object({
5
+ _id: TypeboxObjectId(),
6
+ _orgId: Type.Optional(TypeboxObjectId()),
7
+ name: Type.String({ minLength: 1 }),
8
+ description: Type.Optional(Type.String()),
9
+ isActive: Type.Optional(Type.Boolean()),
10
+ tags: Type.Optional(Type.Array(Type.String())),
11
+ count: Type.Optional(Type.Number())
12
+ });
13
+ export const mongoTestEntityModelSpec = entityUtils.getModelSpec(MongoTestEntitySchema, { isAuditable: true });
@@ -0,0 +1,17 @@
1
+ import { IAuditable, IEntity } from "@loomcore/common/models";
2
+ import { ICategory } from "./category.model.js";
3
+ export interface IProduct extends IEntity, IAuditable {
4
+ name: string;
5
+ description?: string;
6
+ internalNumber?: string;
7
+ categoryId: string;
8
+ category?: ICategory;
9
+ }
10
+ export declare const ProductSchema: import("@sinclair/typebox").TObject<{
11
+ name: import("@sinclair/typebox").TString;
12
+ description: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
13
+ internalNumber: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
14
+ categoryId: import("@sinclair/typebox").TString;
15
+ }>;
16
+ export declare const ProductSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
17
+ export declare const PublicProductSchema: import("@sinclair/typebox").TObject<{}>;
@@ -0,0 +1,10 @@
1
+ import { entityUtils } from "@loomcore/common/utils";
2
+ import { Type } from "@sinclair/typebox";
3
+ export const ProductSchema = Type.Object({
4
+ name: Type.String(),
5
+ description: Type.Optional(Type.String()),
6
+ internalNumber: Type.Optional(Type.String()),
7
+ categoryId: Type.String({ title: 'Category ID' }),
8
+ });
9
+ export const ProductSpec = entityUtils.getModelSpec(ProductSchema, { isAuditable: true });
10
+ export const PublicProductSchema = Type.Omit(ProductSpec.fullSchema, ['internalNumber']);
@@ -0,0 +1,11 @@
1
+ import { IAuditable, IEntity, IModelSpec } from "@loomcore/common/models";
2
+ import { TSchema } from "@sinclair/typebox";
3
+ export declare const TestEntitySchema: TSchema;
4
+ export interface TestEntity extends IEntity, IAuditable {
5
+ name: string;
6
+ description?: string;
7
+ isActive?: boolean;
8
+ tags?: string[];
9
+ count?: number;
10
+ }
11
+ export declare const testModelSpec: IModelSpec;
@@ -0,0 +1,10 @@
1
+ import { entityUtils } from "@loomcore/common/utils";
2
+ import { Type } from "@sinclair/typebox";
3
+ export const TestEntitySchema = Type.Object({
4
+ name: Type.String({ minLength: 1 }),
5
+ description: Type.Optional(Type.String()),
6
+ isActive: Type.Optional(Type.Boolean()),
7
+ tags: Type.Optional(Type.Array(Type.String())),
8
+ count: Type.Optional(Type.Number())
9
+ });
10
+ export const testModelSpec = entityUtils.getModelSpec(TestEntitySchema, { isAuditable: true });
@@ -0,0 +1,12 @@
1
+ import { IAuditable, IEntity } from "@loomcore/common/models";
2
+ export interface ITestItem extends IEntity, IAuditable {
3
+ name: string;
4
+ value?: number;
5
+ eventDate?: Date;
6
+ }
7
+ export declare const TestItemSchema: import("@sinclair/typebox").TObject<{
8
+ name: import("@sinclair/typebox").TString;
9
+ value: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
10
+ eventDate: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TTransform<import("@sinclair/typebox").TString, Date>, import("@sinclair/typebox").TUndefined]>>;
11
+ }>;
12
+ export declare const TestItemSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
@@ -0,0 +1,9 @@
1
+ import { entityUtils } from "@loomcore/common/utils";
2
+ import { TypeboxIsoDate } from "@loomcore/common/validation";
3
+ import { Type } from "@sinclair/typebox";
4
+ export const TestItemSchema = Type.Object({
5
+ name: Type.String(),
6
+ value: Type.Optional(Type.Number()),
7
+ eventDate: Type.Optional(TypeboxIsoDate())
8
+ });
9
+ export const TestItemSpec = entityUtils.getModelSpec(TestItemSchema, { isAuditable: true });
@@ -0,0 +1,15 @@
1
+ import { ITestDatabase } from './test-database.interface.js';
2
+ import { IDatabase } from '../databases/models/index.js';
3
+ export declare class TestMongoDatabase implements ITestDatabase {
4
+ private mongoServer;
5
+ private mongoClient;
6
+ private mongoDb;
7
+ private database;
8
+ private initPromise;
9
+ init(databaseName: string): Promise<IDatabase>;
10
+ getRandomId(): string;
11
+ private _performInit;
12
+ private createIndexes;
13
+ clearCollections(): Promise<void>;
14
+ cleanup(): Promise<void>;
15
+ }
@@ -0,0 +1,74 @@
1
+ import { MongoMemoryServer } from 'mongodb-memory-server';
2
+ import { MongoClient, ObjectId } from 'mongodb';
3
+ import testUtils from './common-test.utils.js';
4
+ import { initSystemUserContext } from '../config/base-api-config.js';
5
+ import { MongoDBDatabase } from '../databases/index.js';
6
+ export class TestMongoDatabase {
7
+ mongoServer = null;
8
+ mongoClient = null;
9
+ mongoDb = null;
10
+ database = null;
11
+ initPromise = null;
12
+ async init(databaseName) {
13
+ if (this.initPromise) {
14
+ return this.initPromise;
15
+ }
16
+ this.initPromise = this._performInit(databaseName);
17
+ return this.initPromise;
18
+ }
19
+ getRandomId() {
20
+ return new ObjectId().toString();
21
+ }
22
+ async _performInit(databaseName) {
23
+ if (!this.database) {
24
+ this.mongoServer = await MongoMemoryServer.create({
25
+ instance: {
26
+ ip: '127.0.0.1',
27
+ port: 0,
28
+ },
29
+ binary: {
30
+ downloadDir: process.env.HOME ? `${process.env.HOME}/.cache/mongodb-binaries` : undefined,
31
+ }
32
+ });
33
+ const uri = this.mongoServer.getUri();
34
+ this.mongoClient = await MongoClient.connect(uri);
35
+ this.mongoDb = this.mongoClient.db();
36
+ const testDatabase = new MongoDBDatabase(this.mongoDb);
37
+ this.database = testDatabase;
38
+ testUtils.initialize(testDatabase);
39
+ await this.createIndexes(this.mongoDb);
40
+ await testUtils.createMetaOrg();
41
+ }
42
+ await initSystemUserContext(this.database);
43
+ return this.database;
44
+ }
45
+ async createIndexes(db) {
46
+ await db.command({
47
+ createIndexes: "users", indexes: [{ key: { email: 1 }, name: 'email_index', unique: true, collation: { locale: 'en', strength: 1 } }]
48
+ });
49
+ }
50
+ async clearCollections() {
51
+ if (!this.mongoDb) {
52
+ throw new Error('Database not initialized');
53
+ }
54
+ const collections = await this.mongoDb.collections();
55
+ for (const collection of collections) {
56
+ await collection.deleteMany({});
57
+ }
58
+ }
59
+ async cleanup() {
60
+ await testUtils.cleanup();
61
+ await this.clearCollections();
62
+ if (this.mongoClient) {
63
+ await this.mongoClient.close();
64
+ }
65
+ if (this.mongoServer) {
66
+ await this.mongoServer.stop();
67
+ }
68
+ this.initPromise = null;
69
+ this.mongoDb = null;
70
+ this.database = null;
71
+ this.mongoClient = null;
72
+ this.mongoServer = null;
73
+ }
74
+ }
@@ -0,0 +1,11 @@
1
+ import { Client } from "pg";
2
+ import { IMigration } from "../../databases/postgres/migrations/migration.interface.js";
3
+ export declare class CreateTestEntitiesTableMigration implements IMigration {
4
+ private readonly client;
5
+ private readonly orgId?;
6
+ constructor(client: Client, orgId?: string | undefined);
7
+ index: number;
8
+ _id: string;
9
+ execute(): Promise<boolean>;
10
+ revert(): Promise<boolean>;
11
+ }