@lossless.org/client 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 (255) hide show
  1. package/.smartconfig.json +37 -0
  2. package/dist_ts/00_commitinfo_data.d.ts +8 -0
  3. package/dist_ts/00_commitinfo_data.js +9 -0
  4. package/dist_ts/classes.losslessorgclient.d.ts +32 -0
  5. package/dist_ts/classes.losslessorgclient.js +103 -0
  6. package/dist_ts/core/classes.error.d.ts +16 -0
  7. package/dist_ts/core/classes.error.js +29 -0
  8. package/dist_ts/core/classes.operation.d.ts +17 -0
  9. package/dist_ts/core/classes.operation.js +70 -0
  10. package/dist_ts/core/interfaces.d.ts +18 -0
  11. package/dist_ts/core/interfaces.js +2 -0
  12. package/dist_ts/index.d.ts +4 -0
  13. package/dist_ts/index.js +3 -0
  14. package/dist_ts/nosqldb/classes.atomicdelete.d.ts +26 -0
  15. package/dist_ts/nosqldb/classes.atomicdelete.js +44 -0
  16. package/dist_ts/nosqldb/classes.atomicfindoneandupdate.d.ts +27 -0
  17. package/dist_ts/nosqldb/classes.atomicfindoneandupdate.js +86 -0
  18. package/dist_ts/nosqldb/classes.atomicupdate.d.ts +26 -0
  19. package/dist_ts/nosqldb/classes.atomicupdate.js +55 -0
  20. package/dist_ts/nosqldb/classes.bootstraprecord.d.ts +14 -0
  21. package/dist_ts/nosqldb/classes.bootstraprecord.js +80 -0
  22. package/dist_ts/nosqldb/classes.bsonassertion.d.ts +2 -0
  23. package/dist_ts/nosqldb/classes.bsonassertion.js +29 -0
  24. package/dist_ts/nosqldb/classes.bsonobjectid.d.ts +2 -0
  25. package/dist_ts/nosqldb/classes.bsonobjectid.js +50 -0
  26. package/dist_ts/nosqldb/classes.bsonsnapshot.d.ts +3 -0
  27. package/dist_ts/nosqldb/classes.bsonsnapshot.js +126 -0
  28. package/dist_ts/nosqldb/classes.cached-document.d.ts +27 -0
  29. package/dist_ts/nosqldb/classes.cached-document.js +112 -0
  30. package/dist_ts/nosqldb/classes.collection.d.ts +302 -0
  31. package/dist_ts/nosqldb/classes.collection.js +1568 -0
  32. package/dist_ts/nosqldb/classes.collectionfactory.d.ts +30 -0
  33. package/dist_ts/nosqldb/classes.collectionfactory.js +65 -0
  34. package/dist_ts/nosqldb/classes.collectionlifecycle.d.ts +4 -0
  35. package/dist_ts/nosqldb/classes.collectionlifecycle.js +15 -0
  36. package/dist_ts/nosqldb/classes.collectionpreparation.d.ts +34 -0
  37. package/dist_ts/nosqldb/classes.collectionpreparation.js +134 -0
  38. package/dist_ts/nosqldb/classes.collectiontopology.d.ts +47 -0
  39. package/dist_ts/nosqldb/classes.collectiontopology.js +388 -0
  40. package/dist_ts/nosqldb/classes.connection.d.ts +18 -0
  41. package/dist_ts/nosqldb/classes.connection.js +23 -0
  42. package/dist_ts/nosqldb/classes.convenience.d.ts +1 -0
  43. package/dist_ts/nosqldb/classes.convenience.js +5 -0
  44. package/dist_ts/nosqldb/classes.cursor.d.ts +15 -0
  45. package/dist_ts/nosqldb/classes.cursor.js +82 -0
  46. package/dist_ts/nosqldb/classes.cursoroperation.d.ts +7 -0
  47. package/dist_ts/nosqldb/classes.cursoroperation.js +36 -0
  48. package/dist_ts/nosqldb/classes.db.d.ts +98 -0
  49. package/dist_ts/nosqldb/classes.db.js +434 -0
  50. package/dist_ts/nosqldb/classes.distributedcoordinator.d.ts +52 -0
  51. package/dist_ts/nosqldb/classes.distributedcoordinator.js +314 -0
  52. package/dist_ts/nosqldb/classes.doc.d.ts +722 -0
  53. package/dist_ts/nosqldb/classes.doc.js +2976 -0
  54. package/dist_ts/nosqldb/classes.easystore.d.ts +42 -0
  55. package/dist_ts/nosqldb/classes.easystore.js +199 -0
  56. package/dist_ts/nosqldb/classes.exactpersistence.d.ts +141 -0
  57. package/dist_ts/nosqldb/classes.exactpersistence.js +1110 -0
  58. package/dist_ts/nosqldb/classes.lucene.adapter.d.ts +173 -0
  59. package/dist_ts/nosqldb/classes.lucene.adapter.js +623 -0
  60. package/dist_ts/nosqldb/classes.mongoadministration.d.ts +73 -0
  61. package/dist_ts/nosqldb/classes.mongoadministration.js +497 -0
  62. package/dist_ts/nosqldb/classes.namespaceinspection.d.ts +42 -0
  63. package/dist_ts/nosqldb/classes.namespaceinspection.js +138 -0
  64. package/dist_ts/nosqldb/classes.operationbudget.d.ts +22 -0
  65. package/dist_ts/nosqldb/classes.operationbudget.js +65 -0
  66. package/dist_ts/nosqldb/classes.ordinarypersistence.d.ts +18 -0
  67. package/dist_ts/nosqldb/classes.ordinarypersistence.js +71 -0
  68. package/dist_ts/nosqldb/classes.persistence.d.ts +14 -0
  69. package/dist_ts/nosqldb/classes.persistence.js +34 -0
  70. package/dist_ts/nosqldb/classes.session.d.ts +28 -0
  71. package/dist_ts/nosqldb/classes.session.js +246 -0
  72. package/dist_ts/nosqldb/classes.storedinspection.d.ts +44 -0
  73. package/dist_ts/nosqldb/classes.storedinspection.js +100 -0
  74. package/dist_ts/nosqldb/classes.testdatabase.d.ts +56 -0
  75. package/dist_ts/nosqldb/classes.testdatabase.js +250 -0
  76. package/dist_ts/nosqldb/classes.watcher.d.ts +37 -0
  77. package/dist_ts/nosqldb/classes.watcher.js +98 -0
  78. package/dist_ts/nosqldb/index.d.ts +27 -0
  79. package/dist_ts/nosqldb/index.js +18 -0
  80. package/dist_ts/nosqldb/logging.d.ts +2 -0
  81. package/dist_ts/nosqldb/logging.js +3 -0
  82. package/dist_ts/nosqldb/plugins.d.ts +17 -0
  83. package/dist_ts/nosqldb/plugins.js +20 -0
  84. package/dist_ts/nosqldb/shim.d.ts +1 -0
  85. package/dist_ts/nosqldb/shim.js +8 -0
  86. package/dist_ts/nosqldb/testsupport.d.ts +3 -0
  87. package/dist_ts/nosqldb/testsupport.js +3 -0
  88. package/dist_ts/objectstorage/classes.bucket.d.ts +227 -0
  89. package/dist_ts/objectstorage/classes.bucket.js +939 -0
  90. package/dist_ts/objectstorage/classes.connection.d.ts +21 -0
  91. package/dist_ts/objectstorage/classes.connection.js +27 -0
  92. package/dist_ts/objectstorage/classes.directory.d.ts +124 -0
  93. package/dist_ts/objectstorage/classes.directory.js +335 -0
  94. package/dist_ts/objectstorage/classes.exactpathpurgeerror.d.ts +5 -0
  95. package/dist_ts/objectstorage/classes.exactpathpurgeerror.js +18 -0
  96. package/dist_ts/objectstorage/classes.exactuploaderror.d.ts +5 -0
  97. package/dist_ts/objectstorage/classes.exactuploaderror.js +19 -0
  98. package/dist_ts/objectstorage/classes.file.d.ts +91 -0
  99. package/dist_ts/objectstorage/classes.file.js +255 -0
  100. package/dist_ts/objectstorage/classes.listcursor.d.ts +41 -0
  101. package/dist_ts/objectstorage/classes.listcursor.js +67 -0
  102. package/dist_ts/objectstorage/classes.metadata.d.ts +57 -0
  103. package/dist_ts/objectstorage/classes.metadata.js +113 -0
  104. package/dist_ts/objectstorage/classes.smartbucket.d.ts +57 -0
  105. package/dist_ts/objectstorage/classes.smartbucket.js +357 -0
  106. package/dist_ts/objectstorage/classes.trash.d.ts +11 -0
  107. package/dist_ts/objectstorage/classes.trash.js +22 -0
  108. package/dist_ts/objectstorage/classes.watcher.d.ts +79 -0
  109. package/dist_ts/objectstorage/classes.watcher.js +249 -0
  110. package/dist_ts/objectstorage/helpers.d.ts +25 -0
  111. package/dist_ts/objectstorage/helpers.js +215 -0
  112. package/dist_ts/objectstorage/index.d.ts +13 -0
  113. package/dist_ts/objectstorage/index.js +13 -0
  114. package/dist_ts/objectstorage/interfaces.d.ts +276 -0
  115. package/dist_ts/objectstorage/interfaces.js +2 -0
  116. package/dist_ts/objectstorage/internal.exactpathpurge.operations.d.ts +11 -0
  117. package/dist_ts/objectstorage/internal.exactpathpurge.operations.js +1069 -0
  118. package/dist_ts/objectstorage/internal.exactupload.capability.d.ts +40 -0
  119. package/dist_ts/objectstorage/internal.exactupload.capability.js +382 -0
  120. package/dist_ts/objectstorage/internal.exactupload.operations.d.ts +11 -0
  121. package/dist_ts/objectstorage/internal.exactupload.operations.js +1104 -0
  122. package/dist_ts/objectstorage/internal.multipart.planner.d.ts +8 -0
  123. package/dist_ts/objectstorage/internal.multipart.planner.js +63 -0
  124. package/dist_ts/objectstorage/internal.multipart.stream.d.ts +17 -0
  125. package/dist_ts/objectstorage/internal.multipart.stream.js +440 -0
  126. package/dist_ts/objectstorage/internal.multipart.types.d.ts +82 -0
  127. package/dist_ts/objectstorage/internal.multipart.types.js +2 -0
  128. package/dist_ts/objectstorage/plugins.d.ts +17 -0
  129. package/dist_ts/objectstorage/plugins.js +23 -0
  130. package/dist_ts/plugins.d.ts +4 -0
  131. package/dist_ts/plugins.js +5 -0
  132. package/dist_ts/sqldb/classes.clickhouseconnection.d.ts +39 -0
  133. package/dist_ts/sqldb/classes.clickhouseconnection.js +225 -0
  134. package/dist_ts/sqldb/classes.sqlconnection.d.ts +50 -0
  135. package/dist_ts/sqldb/classes.sqlconnection.js +376 -0
  136. package/dist_ts/sqldb/classes.sqltable.d.ts +29 -0
  137. package/dist_ts/sqldb/classes.sqltable.js +70 -0
  138. package/dist_ts/sqldb/clickhouse/classes.metricwriter.d.ts +27 -0
  139. package/dist_ts/sqldb/clickhouse/classes.metricwriter.js +89 -0
  140. package/dist_ts/sqldb/clickhouse/index.d.ts +9 -0
  141. package/dist_ts/sqldb/clickhouse/index.js +13 -0
  142. package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.clickhousetable.d.ts +88 -0
  143. package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.clickhousetable.js +304 -0
  144. package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.httpclient.d.ts +28 -0
  145. package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.httpclient.js +46 -0
  146. package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.querybuilder.d.ts +43 -0
  147. package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.querybuilder.js +155 -0
  148. package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.resultset.d.ts +13 -0
  149. package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.resultset.js +36 -0
  150. package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.smartclickhouse.d.ts +49 -0
  151. package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.smartclickhouse.js +106 -0
  152. package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.timedatatable.d.ts +51 -0
  153. package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.timedatatable.js +96 -0
  154. package/dist_ts/sqldb/clickhouse/smartclickhouse.plugins.d.ts +5 -0
  155. package/dist_ts/sqldb/clickhouse/smartclickhouse.plugins.js +6 -0
  156. package/dist_ts/sqldb/clickhouse/smartclickhouse.types.d.ts +53 -0
  157. package/dist_ts/sqldb/clickhouse/smartclickhouse.types.js +41 -0
  158. package/dist_ts/sqldb/index.d.ts +6 -0
  159. package/dist_ts/sqldb/index.js +6 -0
  160. package/dist_ts/sqldb/interfaces.d.ts +53 -0
  161. package/dist_ts/sqldb/interfaces.js +19 -0
  162. package/dist_ts/sqldb/internal.sqlpool.d.ts +51 -0
  163. package/dist_ts/sqldb/internal.sqlpool.js +214 -0
  164. package/dist_ts/sqldb/plugins.clickhouse.d.ts +4 -0
  165. package/dist_ts/sqldb/plugins.clickhouse.js +5 -0
  166. package/dist_ts/sqldb/plugins.mariadb.d.ts +4 -0
  167. package/dist_ts/sqldb/plugins.mariadb.js +5 -0
  168. package/docs/source/smartbucket/license.md +19 -0
  169. package/docs/source/smartclickhouse/license.md +19 -0
  170. package/license.md +21 -0
  171. package/package.json +101 -0
  172. package/readme.md +157 -0
  173. package/ts/00_commitinfo_data.ts +8 -0
  174. package/ts/classes.losslessorgclient.ts +104 -0
  175. package/ts/core/classes.error.ts +31 -0
  176. package/ts/core/classes.operation.ts +60 -0
  177. package/ts/core/interfaces.ts +24 -0
  178. package/ts/index.ts +4 -0
  179. package/ts/nosqldb/classes.atomicdelete.ts +81 -0
  180. package/ts/nosqldb/classes.atomicfindoneandupdate.ts +152 -0
  181. package/ts/nosqldb/classes.atomicupdate.ts +99 -0
  182. package/ts/nosqldb/classes.bootstraprecord.ts +107 -0
  183. package/ts/nosqldb/classes.bsonassertion.ts +25 -0
  184. package/ts/nosqldb/classes.bsonobjectid.ts +45 -0
  185. package/ts/nosqldb/classes.bsonsnapshot.ts +105 -0
  186. package/ts/nosqldb/classes.cached-document.ts +67 -0
  187. package/ts/nosqldb/classes.collection.ts +2399 -0
  188. package/ts/nosqldb/classes.collectionfactory.ts +87 -0
  189. package/ts/nosqldb/classes.collectionlifecycle.ts +24 -0
  190. package/ts/nosqldb/classes.collectionpreparation.ts +164 -0
  191. package/ts/nosqldb/classes.collectiontopology.ts +645 -0
  192. package/ts/nosqldb/classes.connection.ts +31 -0
  193. package/ts/nosqldb/classes.convenience.ts +5 -0
  194. package/ts/nosqldb/classes.cursor.ts +88 -0
  195. package/ts/nosqldb/classes.cursoroperation.ts +38 -0
  196. package/ts/nosqldb/classes.db.ts +637 -0
  197. package/ts/nosqldb/classes.distributedcoordinator.ts +305 -0
  198. package/ts/nosqldb/classes.doc.ts +4928 -0
  199. package/ts/nosqldb/classes.easystore.ts +154 -0
  200. package/ts/nosqldb/classes.exactpersistence.ts +1974 -0
  201. package/ts/nosqldb/classes.lucene.adapter.ts +780 -0
  202. package/ts/nosqldb/classes.mongoadministration.ts +867 -0
  203. package/ts/nosqldb/classes.namespaceinspection.ts +199 -0
  204. package/ts/nosqldb/classes.operationbudget.ts +75 -0
  205. package/ts/nosqldb/classes.ordinarypersistence.ts +84 -0
  206. package/ts/nosqldb/classes.persistence.ts +62 -0
  207. package/ts/nosqldb/classes.session.ts +389 -0
  208. package/ts/nosqldb/classes.storedinspection.ts +151 -0
  209. package/ts/nosqldb/classes.testdatabase.ts +272 -0
  210. package/ts/nosqldb/classes.watcher.ts +96 -0
  211. package/ts/nosqldb/index.ts +51 -0
  212. package/ts/nosqldb/logging.ts +3 -0
  213. package/ts/nosqldb/plugins.ts +37 -0
  214. package/ts/nosqldb/shim.ts +6 -0
  215. package/ts/nosqldb/testsupport.ts +13 -0
  216. package/ts/objectstorage/classes.bucket.ts +1114 -0
  217. package/ts/objectstorage/classes.connection.ts +36 -0
  218. package/ts/objectstorage/classes.directory.ts +425 -0
  219. package/ts/objectstorage/classes.exactpathpurgeerror.ts +24 -0
  220. package/ts/objectstorage/classes.exactuploaderror.ts +25 -0
  221. package/ts/objectstorage/classes.file.ts +303 -0
  222. package/ts/objectstorage/classes.listcursor.ts +89 -0
  223. package/ts/objectstorage/classes.metadata.ts +134 -0
  224. package/ts/objectstorage/classes.smartbucket.ts +445 -0
  225. package/ts/objectstorage/classes.trash.ts +30 -0
  226. package/ts/objectstorage/classes.watcher.ts +289 -0
  227. package/ts/objectstorage/helpers.ts +254 -0
  228. package/ts/objectstorage/index.ts +13 -0
  229. package/ts/objectstorage/interfaces.ts +389 -0
  230. package/ts/objectstorage/internal.exactpathpurge.operations.ts +1936 -0
  231. package/ts/objectstorage/internal.exactupload.capability.ts +580 -0
  232. package/ts/objectstorage/internal.exactupload.operations.ts +1715 -0
  233. package/ts/objectstorage/internal.multipart.planner.ts +90 -0
  234. package/ts/objectstorage/internal.multipart.stream.ts +606 -0
  235. package/ts/objectstorage/internal.multipart.types.ts +106 -0
  236. package/ts/objectstorage/plugins.ts +35 -0
  237. package/ts/plugins.ts +4 -0
  238. package/ts/sqldb/classes.clickhouseconnection.ts +189 -0
  239. package/ts/sqldb/classes.sqlconnection.ts +350 -0
  240. package/ts/sqldb/classes.sqltable.ts +70 -0
  241. package/ts/sqldb/clickhouse/classes.metricwriter.ts +72 -0
  242. package/ts/sqldb/clickhouse/index.ts +16 -0
  243. package/ts/sqldb/clickhouse/smartclickhouse.classes.clickhousetable.ts +372 -0
  244. package/ts/sqldb/clickhouse/smartclickhouse.classes.httpclient.ts +52 -0
  245. package/ts/sqldb/clickhouse/smartclickhouse.classes.querybuilder.ts +120 -0
  246. package/ts/sqldb/clickhouse/smartclickhouse.classes.resultset.ts +44 -0
  247. package/ts/sqldb/clickhouse/smartclickhouse.classes.smartclickhouse.ts +123 -0
  248. package/ts/sqldb/clickhouse/smartclickhouse.classes.timedatatable.ts +114 -0
  249. package/ts/sqldb/clickhouse/smartclickhouse.plugins.ts +5 -0
  250. package/ts/sqldb/clickhouse/smartclickhouse.types.ts +134 -0
  251. package/ts/sqldb/index.ts +6 -0
  252. package/ts/sqldb/interfaces.ts +61 -0
  253. package/ts/sqldb/internal.sqlpool.ts +179 -0
  254. package/ts/sqldb/plugins.clickhouse.ts +4 -0
  255. package/ts/sqldb/plugins.mariadb.ts +4 -0
@@ -0,0 +1,645 @@
1
+ import type * as plugins from './plugins.js';
2
+ import type { INormalizedCollectionModelSchema } from './classes.collection.js';
3
+ import type { SmartdataDb } from './classes.db.js';
4
+ import { SmartdataPersistenceError } from './classes.persistence.js';
5
+
6
+ export type TSmartdataCollectionTopologyStatus =
7
+ | 'absent'
8
+ | 'compatible'
9
+ | 'exact'
10
+ | 'divergent';
11
+
12
+ export type TSmartdataCollectionTopologyReasonCode =
13
+ | 'namespace_not_collection'
14
+ | 'collection_options_present'
15
+ | 'id_index_missing'
16
+ | 'id_index_changed'
17
+ | 'expected_index_missing'
18
+ | 'unexpected_index'
19
+ | 'index_changed'
20
+ | 'unsupported_actual_index';
21
+
22
+ export type TSmartdataCollectionTopologyIndexDirection = 1 | -1 | 'text';
23
+
24
+ export interface ISmartdataCollectionTopologyIndexKey {
25
+ readonly path: string;
26
+ readonly direction: TSmartdataCollectionTopologyIndexDirection;
27
+ readonly weight: number | null;
28
+ }
29
+
30
+ export interface ISmartdataCollectionTopologyIndex {
31
+ readonly name: string;
32
+ readonly keys: readonly ISmartdataCollectionTopologyIndexKey[];
33
+ readonly unique: boolean;
34
+ readonly sparse: boolean;
35
+ readonly expireAfterSeconds: number | null;
36
+ }
37
+
38
+ export interface ISmartdataExpectedCollectionTopology {
39
+ readonly collectionName: string;
40
+ readonly indexes: readonly ISmartdataCollectionTopologyIndex[];
41
+ }
42
+
43
+ export interface ISmartdataCollectionTopologyInspection {
44
+ readonly collectionName: string;
45
+ readonly status: TSmartdataCollectionTopologyStatus;
46
+ readonly reasonCodes: readonly TSmartdataCollectionTopologyReasonCode[];
47
+ readonly expectedIndexes: readonly ISmartdataCollectionTopologyIndex[];
48
+ readonly actualIndexes: readonly ISmartdataCollectionTopologyIndex[];
49
+ }
50
+
51
+ type TCollectionModelSchemaResolver = () => INormalizedCollectionModelSchema;
52
+
53
+ export const collectionModelSchemaResolverSymbol = Symbol(
54
+ '@push.rocks/smartdata.collectionModelSchemaResolver',
55
+ );
56
+
57
+ export const collectionTopologyDbInspectionSymbol = Symbol(
58
+ '@push.rocks/smartdata.collectionTopologyDbInspection',
59
+ );
60
+
61
+ interface ICollectionTopologyModelConstructor {
62
+ readonly name: string;
63
+ readonly [collectionModelSchemaResolverSymbol]?: TCollectionModelSchemaResolver;
64
+ }
65
+
66
+ interface ICollectionTopologyRawSnapshot {
67
+ namespace: Record<string, unknown> | null;
68
+ indexes: unknown[];
69
+ }
70
+
71
+ interface IActualIndexNormalization {
72
+ index?: ISmartdataCollectionTopologyIndex;
73
+ name?: string;
74
+ supported: boolean;
75
+ }
76
+
77
+ const maximumCollectionIndexCount = 64;
78
+ const maximumIndexKeyCount = 32;
79
+ const fixedIdIndex = freezeIndex({
80
+ name: '_id_',
81
+ keys: [{ path: '_id', direction: 1, weight: null }],
82
+ unique: true,
83
+ sparse: false,
84
+ expireAfterSeconds: null,
85
+ });
86
+ const reasonCodeOrder: readonly TSmartdataCollectionTopologyReasonCode[] = [
87
+ 'namespace_not_collection',
88
+ 'collection_options_present',
89
+ 'id_index_missing',
90
+ 'id_index_changed',
91
+ 'expected_index_missing',
92
+ 'unexpected_index',
93
+ 'index_changed',
94
+ 'unsupported_actual_index',
95
+ ];
96
+ const ordinaryActualIndexKeys = new Set([
97
+ 'v',
98
+ 'key',
99
+ 'name',
100
+ 'ns',
101
+ 'background',
102
+ 'unique',
103
+ 'sparse',
104
+ 'expireAfterSeconds',
105
+ ]);
106
+ const textActualIndexKeys = new Set([
107
+ ...ordinaryActualIndexKeys,
108
+ 'weights',
109
+ 'default_language',
110
+ 'language_override',
111
+ 'textIndexVersion',
112
+ ]);
113
+
114
+ export const compareSmartdataTopologyStrings = (
115
+ leftArg: string,
116
+ rightArg: string,
117
+ ): number => {
118
+ const leftCodePoints = Array.from(leftArg, (characterArg) =>
119
+ characterArg.codePointAt(0)!,
120
+ );
121
+ const rightCodePoints = Array.from(rightArg, (characterArg) =>
122
+ characterArg.codePointAt(0)!,
123
+ );
124
+ const sharedLength = Math.min(leftCodePoints.length, rightCodePoints.length);
125
+ for (let index = 0; index < sharedLength; index++) {
126
+ if (leftCodePoints[index] !== rightCodePoints[index]) {
127
+ return leftCodePoints[index] < rightCodePoints[index] ? -1 : 1;
128
+ }
129
+ }
130
+ if (leftCodePoints.length === rightCodePoints.length) {
131
+ return 0;
132
+ }
133
+ return leftCodePoints.length < rightCodePoints.length ? -1 : 1;
134
+ };
135
+
136
+ function freezeIndex(
137
+ indexArg: {
138
+ name: string;
139
+ keys: Array<{
140
+ path: string;
141
+ direction: TSmartdataCollectionTopologyIndexDirection;
142
+ weight: number | null;
143
+ }>;
144
+ unique: boolean;
145
+ sparse: boolean;
146
+ expireAfterSeconds: number | null;
147
+ },
148
+ ): ISmartdataCollectionTopologyIndex {
149
+ return Object.freeze({
150
+ name: indexArg.name,
151
+ keys: Object.freeze(
152
+ indexArg.keys.map((keyArg) => Object.freeze({ ...keyArg })),
153
+ ),
154
+ unique: indexArg.unique,
155
+ sparse: indexArg.sparse,
156
+ expireAfterSeconds: indexArg.expireAfterSeconds,
157
+ });
158
+ }
159
+
160
+ const sortIndexes = (
161
+ indexesArg: readonly ISmartdataCollectionTopologyIndex[],
162
+ ): readonly ISmartdataCollectionTopologyIndex[] =>
163
+ Object.freeze(
164
+ [...indexesArg].sort((leftArg, rightArg) =>
165
+ compareSmartdataTopologyStrings(leftArg.name, rightArg.name),
166
+ ),
167
+ );
168
+
169
+ const indexValuesEqual = (
170
+ leftArg: ISmartdataCollectionTopologyIndex,
171
+ rightArg: ISmartdataCollectionTopologyIndex,
172
+ ): boolean => JSON.stringify(leftArg) === JSON.stringify(rightArg);
173
+
174
+ const getSchemaResolver = (
175
+ constructorArg: ICollectionTopologyModelConstructor,
176
+ ): TCollectionModelSchemaResolver => {
177
+ const resolver = constructorArg?.[collectionModelSchemaResolverSymbol];
178
+ if (
179
+ typeof constructorArg !== 'function' ||
180
+ !Object.prototype.hasOwnProperty.call(
181
+ constructorArg,
182
+ collectionModelSchemaResolverSymbol,
183
+ ) ||
184
+ typeof resolver !== 'function'
185
+ ) {
186
+ throw new SmartdataPersistenceError(
187
+ 'invalid_configuration',
188
+ `Model "${constructorArg?.name || 'unknown'}" has no collection schema binding.`,
189
+ );
190
+ }
191
+ return resolver;
192
+ };
193
+
194
+ const normalizeExpectedIndex = (
195
+ indexArg: INormalizedCollectionModelSchema['indexes'][number],
196
+ ): ISmartdataCollectionTopologyIndex => {
197
+ if (indexArg.name === '_id_') {
198
+ throw new SmartdataPersistenceError(
199
+ 'invalid_configuration',
200
+ 'Model index name "_id_" is reserved for MongoDB.',
201
+ );
202
+ }
203
+ if (indexArg.key.length > maximumIndexKeyCount) {
204
+ throw new SmartdataPersistenceError(
205
+ 'invalid_configuration',
206
+ `Index "${indexArg.name}" exceeds MongoDB's compound index field limit.`,
207
+ );
208
+ }
209
+ const expectedPhysicalKeyCount =
210
+ indexArg.key.filter(([, directionArg]) => directionArg !== 'text').length +
211
+ (indexArg.key.some(([, directionArg]) => directionArg === 'text') ? 2 : 0);
212
+ if (expectedPhysicalKeyCount > maximumIndexKeyCount) {
213
+ throw new SmartdataPersistenceError(
214
+ 'invalid_configuration',
215
+ `Index "${indexArg.name}" exceeds MongoDB's physical compound index field limit.`,
216
+ );
217
+ }
218
+ const supportedOptions = new Set([
219
+ 'background',
220
+ 'unique',
221
+ 'sparse',
222
+ 'expireAfterSeconds',
223
+ ]);
224
+ for (const optionName of Object.keys(indexArg.options)) {
225
+ if (!supportedOptions.has(optionName)) {
226
+ throw new SmartdataPersistenceError(
227
+ 'invalid_configuration',
228
+ `Index "${indexArg.name}" defines an unsupported topology option.`,
229
+ );
230
+ }
231
+ }
232
+
233
+ const textKeys = indexArg.key
234
+ .filter(([, directionArg]) => directionArg === 'text')
235
+ .map(([pathArg]) => pathArg)
236
+ .sort(compareSmartdataTopologyStrings);
237
+ const keys: Array<{
238
+ path: string;
239
+ direction: TSmartdataCollectionTopologyIndexDirection;
240
+ weight: number | null;
241
+ }> = [];
242
+ let emittedTextKeys = false;
243
+ for (const [path, direction] of indexArg.key) {
244
+ if (path === '_fts' || path === '_ftsx') {
245
+ throw new SmartdataPersistenceError(
246
+ 'invalid_configuration',
247
+ `Index "${indexArg.name}" uses a reserved MongoDB text-index field.`,
248
+ );
249
+ }
250
+ if (direction === 'text') {
251
+ if (!emittedTextKeys) {
252
+ keys.push(
253
+ ...textKeys.map((pathArg) => ({
254
+ path: pathArg,
255
+ direction: 'text' as const,
256
+ weight: 1,
257
+ })),
258
+ );
259
+ emittedTextKeys = true;
260
+ }
261
+ continue;
262
+ }
263
+ keys.push({ path, direction, weight: null });
264
+ }
265
+ return freezeIndex({
266
+ name: indexArg.name,
267
+ keys,
268
+ unique: indexArg.options.unique === true,
269
+ sparse: indexArg.options.sparse === true,
270
+ expireAfterSeconds: indexArg.options.expireAfterSeconds ?? null,
271
+ });
272
+ };
273
+
274
+ export const getExpectedCollectionTopologyForModel = (
275
+ constructorArg: ICollectionTopologyModelConstructor,
276
+ ): ISmartdataExpectedCollectionTopology => {
277
+ const schema = getSchemaResolver(constructorArg)();
278
+ return getExpectedCollectionTopologyForSchema(schema);
279
+ };
280
+
281
+ /** @internal Normalizes the same contract for a bound collection. */
282
+ export const getExpectedCollectionTopologyForSchema = (
283
+ schema: INormalizedCollectionModelSchema,
284
+ ): ISmartdataExpectedCollectionTopology => {
285
+ if (schema.indexes.length + 1 > maximumCollectionIndexCount) {
286
+ throw new SmartdataPersistenceError(
287
+ 'invalid_configuration',
288
+ `Collection "${schema.collectionName}" exceeds MongoDB's collection index limit.`,
289
+ );
290
+ }
291
+ const indexes = sortIndexes([
292
+ fixedIdIndex,
293
+ ...schema.indexes.map((indexArg) => normalizeExpectedIndex(indexArg)),
294
+ ]);
295
+ return Object.freeze({
296
+ collectionName: schema.collectionName,
297
+ indexes,
298
+ });
299
+ };
300
+
301
+ const normalizeActualIndex = (
302
+ rawIndexArg: unknown,
303
+ ): IActualIndexNormalization => {
304
+ if (
305
+ typeof rawIndexArg !== 'object' ||
306
+ rawIndexArg === null ||
307
+ Array.isArray(rawIndexArg)
308
+ ) {
309
+ return { supported: false };
310
+ }
311
+ const rawIndex = rawIndexArg as Record<string, unknown>;
312
+ const name = typeof rawIndex.name === 'string' ? rawIndex.name : undefined;
313
+ if (!name || typeof rawIndex.key !== 'object' || rawIndex.key === null) {
314
+ return { name, supported: false };
315
+ }
316
+ const allRawKeyEntries = Object.entries(
317
+ rawIndex.key as Record<string, unknown>,
318
+ );
319
+ const maximumPhysicalKeyCount = maximumIndexKeyCount;
320
+ const rawKeyEntries = allRawKeyEntries.slice(0, maximumPhysicalKeyCount);
321
+ if (rawKeyEntries.length === 0) {
322
+ return { name, supported: false };
323
+ }
324
+
325
+ const textMarkerIndex = rawKeyEntries.findIndex(
326
+ ([pathArg, directionArg]) =>
327
+ pathArg === '_fts' && directionArg === 'text',
328
+ );
329
+ const hasTextMarker = textMarkerIndex !== -1;
330
+ let supported = Reflect.ownKeys(rawIndex).every(
331
+ (keyArg) =>
332
+ typeof keyArg === 'string' &&
333
+ (hasTextMarker ? textActualIndexKeys : ordinaryActualIndexKeys).has(
334
+ keyArg,
335
+ ),
336
+ );
337
+ if (
338
+ allRawKeyEntries.length > maximumPhysicalKeyCount ||
339
+ rawKeyEntries.some(
340
+ ([pathArg]) => pathArg === '$**' || pathArg.endsWith('.$**'),
341
+ )
342
+ ) {
343
+ supported = false;
344
+ }
345
+ if (
346
+ rawIndex.background !== undefined &&
347
+ typeof rawIndex.background !== 'boolean'
348
+ ) {
349
+ supported = false;
350
+ }
351
+ if (rawIndex.unique !== undefined && typeof rawIndex.unique !== 'boolean') {
352
+ supported = false;
353
+ }
354
+ if (rawIndex.sparse !== undefined && typeof rawIndex.sparse !== 'boolean') {
355
+ supported = false;
356
+ }
357
+ const expireAfterSeconds = rawIndex.expireAfterSeconds;
358
+ if (
359
+ expireAfterSeconds !== undefined &&
360
+ (typeof expireAfterSeconds !== 'number' ||
361
+ !Number.isFinite(expireAfterSeconds) ||
362
+ expireAfterSeconds < 0)
363
+ ) {
364
+ supported = false;
365
+ }
366
+
367
+ let textWeights = new Map<string, number>();
368
+ if (hasTextMarker) {
369
+ if (
370
+ rawKeyEntries.filter(([pathArg]) => pathArg === '_fts').length !== 1 ||
371
+ rawKeyEntries[textMarkerIndex + 1]?.[0] !== '_ftsx' ||
372
+ rawKeyEntries[textMarkerIndex + 1]?.[1] !== 1 ||
373
+ typeof rawIndex.weights !== 'object' ||
374
+ rawIndex.weights === null ||
375
+ Array.isArray(rawIndex.weights)
376
+ ) {
377
+ supported = false;
378
+ } else {
379
+ const rawWeightEntries = Object.entries(
380
+ rawIndex.weights as Record<string, unknown>,
381
+ );
382
+ if (rawWeightEntries.length > maximumIndexKeyCount) {
383
+ supported = false;
384
+ }
385
+ textWeights = new Map(
386
+ rawWeightEntries
387
+ .sort(([leftArg], [rightArg]) =>
388
+ compareSmartdataTopologyStrings(leftArg, rightArg),
389
+ )
390
+ .slice(0, maximumIndexKeyCount)
391
+ .flatMap(([pathArg, weightArg]) => {
392
+ if (
393
+ typeof weightArg !== 'number' ||
394
+ !Number.isFinite(weightArg) ||
395
+ weightArg <= 0
396
+ ) {
397
+ supported = false;
398
+ return [];
399
+ }
400
+ return [[pathArg, weightArg] as const];
401
+ }),
402
+ );
403
+ if (textWeights.size === 0) {
404
+ supported = false;
405
+ }
406
+ }
407
+ if (
408
+ (rawIndex.default_language !== undefined &&
409
+ rawIndex.default_language !== 'english') ||
410
+ (rawIndex.language_override !== undefined &&
411
+ rawIndex.language_override !== 'language') ||
412
+ (rawIndex.textIndexVersion !== undefined &&
413
+ rawIndex.textIndexVersion !== 3)
414
+ ) {
415
+ supported = false;
416
+ }
417
+ }
418
+
419
+ const keys: Array<{
420
+ path: string;
421
+ direction: TSmartdataCollectionTopologyIndexDirection;
422
+ weight: number | null;
423
+ }> = [];
424
+ for (let index = 0; index < rawKeyEntries.length; index++) {
425
+ const [path, direction] = rawKeyEntries[index];
426
+ if (hasTextMarker && index === textMarkerIndex) {
427
+ keys.push(
428
+ ...[...textWeights].map(([pathArg, weightArg]) => ({
429
+ path: pathArg,
430
+ direction: 'text' as const,
431
+ weight: weightArg,
432
+ })),
433
+ );
434
+ index++;
435
+ continue;
436
+ }
437
+ if (direction !== 1 && direction !== -1) {
438
+ supported = false;
439
+ continue;
440
+ }
441
+ keys.push({ path, direction, weight: null });
442
+ }
443
+ if (keys.length > maximumIndexKeyCount) {
444
+ supported = false;
445
+ keys.length = maximumIndexKeyCount;
446
+ }
447
+ if (keys.length === 0) {
448
+ return { name, supported: false };
449
+ }
450
+
451
+ let normalized = freezeIndex({
452
+ name,
453
+ keys,
454
+ unique: rawIndex.unique === true,
455
+ sparse: rawIndex.sparse === true,
456
+ expireAfterSeconds:
457
+ typeof expireAfterSeconds === 'number' &&
458
+ Number.isFinite(expireAfterSeconds) &&
459
+ expireAfterSeconds >= 0
460
+ ? expireAfterSeconds
461
+ : null,
462
+ });
463
+ if (
464
+ name === '_id_' &&
465
+ normalized.keys.length === 1 &&
466
+ normalized.keys[0].path === '_id' &&
467
+ normalized.keys[0].direction === 1 &&
468
+ normalized.keys[0].weight === null &&
469
+ (rawIndex.unique === undefined || rawIndex.unique === true) &&
470
+ normalized.sparse === false &&
471
+ normalized.expireAfterSeconds === null
472
+ ) {
473
+ normalized = fixedIdIndex;
474
+ }
475
+ return { index: normalized, name, supported };
476
+ };
477
+
478
+ const buildReasonCodes = (
479
+ reasonsArg: ReadonlySet<TSmartdataCollectionTopologyReasonCode>,
480
+ ): readonly TSmartdataCollectionTopologyReasonCode[] =>
481
+ Object.freeze(
482
+ reasonCodeOrder.filter((reasonCodeArg) => reasonsArg.has(reasonCodeArg)),
483
+ );
484
+
485
+ const createInspection = (
486
+ expectedArg: ISmartdataExpectedCollectionTopology,
487
+ statusArg: TSmartdataCollectionTopologyStatus,
488
+ reasonsArg: ReadonlySet<TSmartdataCollectionTopologyReasonCode>,
489
+ actualIndexesArg: readonly ISmartdataCollectionTopologyIndex[],
490
+ ): ISmartdataCollectionTopologyInspection =>
491
+ Object.freeze({
492
+ collectionName: expectedArg.collectionName,
493
+ status: statusArg,
494
+ reasonCodes: buildReasonCodes(reasonsArg),
495
+ expectedIndexes: expectedArg.indexes,
496
+ actualIndexes: sortIndexes(actualIndexesArg),
497
+ });
498
+
499
+ export const inspectCollectionTopologyForModel = async (
500
+ constructorArg: ICollectionTopologyModelConstructor,
501
+ dbArg: SmartdataDb,
502
+ ): Promise<ISmartdataCollectionTopologyInspection> => {
503
+ const expected = getExpectedCollectionTopologyForModel(constructorArg);
504
+ const inspectionHost = dbArg as unknown as {
505
+ [collectionTopologyDbInspectionSymbol]?: <TResult>(
506
+ operationArg: (mongoDbArg: plugins.mongodb.Db) => Promise<TResult>,
507
+ ) => Promise<TResult>;
508
+ };
509
+ if (
510
+ typeof inspectionHost?.[collectionTopologyDbInspectionSymbol] !== 'function'
511
+ ) {
512
+ throw new SmartdataPersistenceError(
513
+ 'invalid_argument',
514
+ 'Collection topology inspection requires a SmartdataDb.',
515
+ );
516
+ }
517
+
518
+ const rawSnapshot = await inspectionHost[collectionTopologyDbInspectionSymbol](
519
+ async (mongoDbArg): Promise<ICollectionTopologyRawSnapshot> => {
520
+ const namespace = (await mongoDbArg
521
+ .listCollections(
522
+ { name: expected.collectionName },
523
+ { nameOnly: false },
524
+ )
525
+ .next()) as Record<string, unknown> | null;
526
+ if (!namespace || namespace.type !== 'collection') {
527
+ return { namespace, indexes: [] };
528
+ }
529
+ const indexes = await mongoDbArg
530
+ .collection(expected.collectionName)
531
+ .listIndexes()
532
+ .toArray();
533
+ return { namespace, indexes };
534
+ },
535
+ );
536
+
537
+ return inspectCollectionTopologySnapshot(expected, rawSnapshot);
538
+ };
539
+
540
+ /** @internal Pure normalization shared by model and namespace inspection. */
541
+ export const inspectCollectionTopologySnapshot = (
542
+ expected: ISmartdataExpectedCollectionTopology,
543
+ rawSnapshot: ICollectionTopologyRawSnapshot,
544
+ ): ISmartdataCollectionTopologyInspection => {
545
+
546
+ if (!rawSnapshot.namespace) {
547
+ return createInspection(expected, 'absent', new Set(), []);
548
+ }
549
+
550
+ try {
551
+ const reasons = new Set<TSmartdataCollectionTopologyReasonCode>();
552
+ const namespace = rawSnapshot.namespace;
553
+ if (
554
+ namespace.name !== expected.collectionName ||
555
+ namespace.type !== 'collection'
556
+ ) {
557
+ reasons.add('namespace_not_collection');
558
+ }
559
+ if (
560
+ typeof namespace.options !== 'object' ||
561
+ namespace.options === null ||
562
+ Array.isArray(namespace.options) ||
563
+ Reflect.ownKeys(namespace.options).length !== 0
564
+ ) {
565
+ reasons.add('collection_options_present');
566
+ }
567
+
568
+ const rawIndexes = rawSnapshot.indexes.slice(
569
+ 0,
570
+ maximumCollectionIndexCount,
571
+ );
572
+ if (rawSnapshot.indexes.length > maximumCollectionIndexCount) {
573
+ reasons.add('unsupported_actual_index');
574
+ }
575
+ const normalizedIndexes: ISmartdataCollectionTopologyIndex[] = [];
576
+ const unsupportedNames = new Set<string>();
577
+ for (const rawIndex of rawIndexes) {
578
+ const normalized = normalizeActualIndex(rawIndex);
579
+ if (!normalized.supported) {
580
+ reasons.add('unsupported_actual_index');
581
+ if (normalized.name) {
582
+ unsupportedNames.add(normalized.name);
583
+ }
584
+ }
585
+ if (normalized.index) {
586
+ normalizedIndexes.push(normalized.index);
587
+ }
588
+ }
589
+
590
+ const actualByName = new Map<string, ISmartdataCollectionTopologyIndex>();
591
+ for (const actualIndex of normalizedIndexes) {
592
+ if (actualByName.has(actualIndex.name)) {
593
+ reasons.add('unsupported_actual_index');
594
+ continue;
595
+ }
596
+ actualByName.set(actualIndex.name, actualIndex);
597
+ }
598
+ const expectedByName = new Map(
599
+ expected.indexes.map((indexArg) => [indexArg.name, indexArg]),
600
+ );
601
+ const actualIdIndex = actualByName.get('_id_');
602
+ if (!actualIdIndex && !unsupportedNames.has('_id_')) {
603
+ reasons.add('id_index_missing');
604
+ } else if (
605
+ actualIdIndex &&
606
+ !indexValuesEqual(actualIdIndex, fixedIdIndex)
607
+ ) {
608
+ reasons.add('id_index_changed');
609
+ }
610
+
611
+ for (const expectedIndex of expected.indexes) {
612
+ if (expectedIndex.name === '_id_') {
613
+ continue;
614
+ }
615
+ const actualIndex = actualByName.get(expectedIndex.name);
616
+ if (!actualIndex) {
617
+ if (!unsupportedNames.has(expectedIndex.name)) {
618
+ reasons.add('expected_index_missing');
619
+ }
620
+ } else if (!indexValuesEqual(expectedIndex, actualIndex)) {
621
+ reasons.add('index_changed');
622
+ }
623
+ }
624
+ for (const actualIndex of actualByName.values()) {
625
+ if (!expectedByName.has(actualIndex.name)) {
626
+ reasons.add('unexpected_index');
627
+ }
628
+ }
629
+
630
+ const status: TSmartdataCollectionTopologyStatus =
631
+ reasons.size === 0
632
+ ? 'exact'
633
+ : [...reasons].every(
634
+ (reasonArg) => reasonArg === 'expected_index_missing',
635
+ )
636
+ ? 'compatible'
637
+ : 'divergent';
638
+ return createInspection(expected, status, reasons, normalizedIndexes);
639
+ } catch {
640
+ throw new SmartdataPersistenceError(
641
+ 'unsupported_operation',
642
+ 'Collection topology inspection returned unreadable metadata.',
643
+ );
644
+ }
645
+ };
@@ -0,0 +1,31 @@
1
+ import { SmartdataDb } from './classes.db.js';
2
+ import type { ICapabilities, IOperationOptions, IReadiness } from '../core/interfaces.js';
3
+
4
+ export interface INoSqlConnectionOptions {
5
+ backend: 'nosqldb' | 'mongodb';
6
+ url: string;
7
+ database: string;
8
+ username?: string;
9
+ password?: string;
10
+ connectionLimit?: number;
11
+ }
12
+
13
+ export class NoSqlConnection extends SmartdataDb {
14
+ public readonly backend: 'nosqldb' | 'mongodb';
15
+ public readonly capabilities: ICapabilities;
16
+ constructor(public readonly options: INoSqlConnectionOptions) {
17
+ super({ mongoDbUrl: options.url, mongoDbName: options.database,
18
+ mongoDbUser: options.username, mongoDbPass: options.password,
19
+ ...(options.connectionLimit === undefined ? {} : { maxPoolSize: options.connectionLimit }) });
20
+ this.backend = options.backend;
21
+ this.capabilities = Object.freeze({ backend: options.backend,
22
+ transactions: options.backend === 'nosqldb' ? 'available' : 'unknown',
23
+ changeStreams: options.backend === 'nosqldb' ? 'unsupported' : 'unknown',
24
+ objectMetrics: 'unsupported', diskResidentScans: 'available' });
25
+ }
26
+ public async connect(options: IOperationOptions = {}): Promise<void> { await this.init(options); }
27
+ public async ready(options: IOperationOptions = {}): Promise<IReadiness> {
28
+ const result = await this.checkReadiness(options);
29
+ return result.ready ? { ready: true } : { ready: false, reason: result.reason };
30
+ }
31
+ }
@@ -0,0 +1,5 @@
1
+ import * as plugins from './plugins.js';
2
+
3
+ export const getNewUniqueId = async (prefixArg?: string) => {
4
+ return plugins.smartunique.uni(prefixArg);
5
+ };