@powersync/common 1.41.0 → 1.41.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 (182) hide show
  1. package/dist/bundle.cjs +10809 -22
  2. package/dist/bundle.cjs.map +1 -0
  3. package/dist/bundle.mjs +10730 -22
  4. package/dist/bundle.mjs.map +1 -0
  5. package/dist/bundle.node.cjs +10809 -0
  6. package/dist/bundle.node.cjs.map +1 -0
  7. package/dist/bundle.node.mjs +10730 -0
  8. package/dist/bundle.node.mjs.map +1 -0
  9. package/dist/index.d.cts +5 -0
  10. package/lib/client/AbstractPowerSyncDatabase.js +1 -0
  11. package/lib/client/AbstractPowerSyncDatabase.js.map +1 -0
  12. package/lib/client/AbstractPowerSyncOpenFactory.js +1 -0
  13. package/lib/client/AbstractPowerSyncOpenFactory.js.map +1 -0
  14. package/lib/client/ConnectionManager.js +1 -0
  15. package/lib/client/ConnectionManager.js.map +1 -0
  16. package/lib/client/CustomQuery.js +1 -0
  17. package/lib/client/CustomQuery.js.map +1 -0
  18. package/lib/client/Query.js +1 -0
  19. package/lib/client/Query.js.map +1 -0
  20. package/lib/client/SQLOpenFactory.js +1 -0
  21. package/lib/client/SQLOpenFactory.js.map +1 -0
  22. package/lib/client/compilableQueryWatch.js +1 -0
  23. package/lib/client/compilableQueryWatch.js.map +1 -0
  24. package/lib/client/connection/PowerSyncBackendConnector.js +1 -0
  25. package/lib/client/connection/PowerSyncBackendConnector.js.map +1 -0
  26. package/lib/client/connection/PowerSyncCredentials.js +1 -0
  27. package/lib/client/connection/PowerSyncCredentials.js.map +1 -0
  28. package/lib/client/constants.js +1 -0
  29. package/lib/client/constants.js.map +1 -0
  30. package/lib/client/runOnSchemaChange.js +1 -0
  31. package/lib/client/runOnSchemaChange.js.map +1 -0
  32. package/lib/client/sync/bucket/BucketStorageAdapter.js +1 -0
  33. package/lib/client/sync/bucket/BucketStorageAdapter.js.map +1 -0
  34. package/lib/client/sync/bucket/CrudBatch.js +1 -0
  35. package/lib/client/sync/bucket/CrudBatch.js.map +1 -0
  36. package/lib/client/sync/bucket/CrudEntry.js +1 -0
  37. package/lib/client/sync/bucket/CrudEntry.js.map +1 -0
  38. package/lib/client/sync/bucket/CrudTransaction.js +1 -0
  39. package/lib/client/sync/bucket/CrudTransaction.js.map +1 -0
  40. package/lib/client/sync/bucket/OpType.js +1 -0
  41. package/lib/client/sync/bucket/OpType.js.map +1 -0
  42. package/lib/client/sync/bucket/OplogEntry.js +1 -0
  43. package/lib/client/sync/bucket/OplogEntry.js.map +1 -0
  44. package/lib/client/sync/bucket/SqliteBucketStorage.js +1 -0
  45. package/lib/client/sync/bucket/SqliteBucketStorage.js.map +1 -0
  46. package/lib/client/sync/bucket/SyncDataBatch.js +1 -0
  47. package/lib/client/sync/bucket/SyncDataBatch.js.map +1 -0
  48. package/lib/client/sync/bucket/SyncDataBucket.js +1 -0
  49. package/lib/client/sync/bucket/SyncDataBucket.js.map +1 -0
  50. package/lib/client/sync/stream/AbstractRemote.d.ts +5 -0
  51. package/lib/client/sync/stream/AbstractRemote.js +9 -2
  52. package/lib/client/sync/stream/AbstractRemote.js.map +1 -0
  53. package/lib/client/sync/stream/AbstractStreamingSyncImplementation.js +1 -0
  54. package/lib/client/sync/stream/AbstractStreamingSyncImplementation.js.map +1 -0
  55. package/lib/client/sync/stream/WebsocketClientTransport.js +1 -0
  56. package/lib/client/sync/stream/WebsocketClientTransport.js.map +1 -0
  57. package/lib/client/sync/stream/core-instruction.js +1 -0
  58. package/lib/client/sync/stream/core-instruction.js.map +1 -0
  59. package/lib/client/sync/stream/streaming-sync-types.js +1 -0
  60. package/lib/client/sync/stream/streaming-sync-types.js.map +1 -0
  61. package/lib/client/sync/sync-streams.js +1 -0
  62. package/lib/client/sync/sync-streams.js.map +1 -0
  63. package/lib/client/triggers/TriggerManager.js +1 -0
  64. package/lib/client/triggers/TriggerManager.js.map +1 -0
  65. package/lib/client/triggers/TriggerManagerImpl.js +1 -0
  66. package/lib/client/triggers/TriggerManagerImpl.js.map +1 -0
  67. package/lib/client/triggers/sanitizeSQL.js +1 -0
  68. package/lib/client/triggers/sanitizeSQL.js.map +1 -0
  69. package/lib/client/watched/GetAllQuery.js +1 -0
  70. package/lib/client/watched/GetAllQuery.js.map +1 -0
  71. package/lib/client/watched/WatchedQuery.js +1 -0
  72. package/lib/client/watched/WatchedQuery.js.map +1 -0
  73. package/lib/client/watched/processors/AbstractQueryProcessor.js +1 -0
  74. package/lib/client/watched/processors/AbstractQueryProcessor.js.map +1 -0
  75. package/lib/client/watched/processors/DifferentialQueryProcessor.js +1 -0
  76. package/lib/client/watched/processors/DifferentialQueryProcessor.js.map +1 -0
  77. package/lib/client/watched/processors/OnChangeQueryProcessor.js +1 -0
  78. package/lib/client/watched/processors/OnChangeQueryProcessor.js.map +1 -0
  79. package/lib/client/watched/processors/comparators.js +1 -0
  80. package/lib/client/watched/processors/comparators.js.map +1 -0
  81. package/lib/db/DBAdapter.js +1 -0
  82. package/lib/db/DBAdapter.js.map +1 -0
  83. package/lib/db/crud/SyncProgress.js +1 -0
  84. package/lib/db/crud/SyncProgress.js.map +1 -0
  85. package/lib/db/crud/SyncStatus.js +1 -0
  86. package/lib/db/crud/SyncStatus.js.map +1 -0
  87. package/lib/db/crud/UploadQueueStatus.js +1 -0
  88. package/lib/db/crud/UploadQueueStatus.js.map +1 -0
  89. package/lib/db/schema/Column.js +1 -0
  90. package/lib/db/schema/Column.js.map +1 -0
  91. package/lib/db/schema/Index.js +1 -0
  92. package/lib/db/schema/Index.js.map +1 -0
  93. package/lib/db/schema/IndexedColumn.js +1 -0
  94. package/lib/db/schema/IndexedColumn.js.map +1 -0
  95. package/lib/db/schema/RawTable.js +1 -0
  96. package/lib/db/schema/RawTable.js.map +1 -0
  97. package/lib/db/schema/Schema.js +1 -0
  98. package/lib/db/schema/Schema.js.map +1 -0
  99. package/lib/db/schema/Table.js +1 -0
  100. package/lib/db/schema/Table.js.map +1 -0
  101. package/lib/db/schema/TableV2.js +1 -0
  102. package/lib/db/schema/TableV2.js.map +1 -0
  103. package/lib/index.js +1 -0
  104. package/lib/index.js.map +1 -0
  105. package/lib/types/types.js +1 -0
  106. package/lib/types/types.js.map +1 -0
  107. package/lib/utils/AbortOperation.js +1 -0
  108. package/lib/utils/AbortOperation.js.map +1 -0
  109. package/lib/utils/BaseObserver.js +1 -0
  110. package/lib/utils/BaseObserver.js.map +1 -0
  111. package/lib/utils/ControlledExecutor.js +1 -0
  112. package/lib/utils/ControlledExecutor.js.map +1 -0
  113. package/lib/utils/DataStream.js +1 -0
  114. package/lib/utils/DataStream.js.map +1 -0
  115. package/lib/utils/Logger.js +1 -0
  116. package/lib/utils/Logger.js.map +1 -0
  117. package/lib/utils/MetaBaseObserver.js +1 -0
  118. package/lib/utils/MetaBaseObserver.js.map +1 -0
  119. package/lib/utils/async.js +1 -0
  120. package/lib/utils/async.js.map +1 -0
  121. package/lib/utils/mutex.js +1 -0
  122. package/lib/utils/mutex.js.map +1 -0
  123. package/lib/utils/parseQuery.js +1 -0
  124. package/lib/utils/parseQuery.js.map +1 -0
  125. package/package.json +23 -15
  126. package/src/client/AbstractPowerSyncDatabase.ts +1343 -0
  127. package/src/client/AbstractPowerSyncOpenFactory.ts +39 -0
  128. package/src/client/ConnectionManager.ts +402 -0
  129. package/src/client/CustomQuery.ts +56 -0
  130. package/src/client/Query.ts +106 -0
  131. package/src/client/SQLOpenFactory.ts +55 -0
  132. package/src/client/compilableQueryWatch.ts +55 -0
  133. package/src/client/connection/PowerSyncBackendConnector.ts +25 -0
  134. package/src/client/connection/PowerSyncCredentials.ts +5 -0
  135. package/src/client/constants.ts +1 -0
  136. package/src/client/runOnSchemaChange.ts +31 -0
  137. package/src/client/sync/bucket/BucketStorageAdapter.ts +118 -0
  138. package/src/client/sync/bucket/CrudBatch.ts +21 -0
  139. package/src/client/sync/bucket/CrudEntry.ts +172 -0
  140. package/src/client/sync/bucket/CrudTransaction.ts +21 -0
  141. package/src/client/sync/bucket/OpType.ts +23 -0
  142. package/src/client/sync/bucket/OplogEntry.ts +50 -0
  143. package/src/client/sync/bucket/SqliteBucketStorage.ts +395 -0
  144. package/src/client/sync/bucket/SyncDataBatch.ts +11 -0
  145. package/src/client/sync/bucket/SyncDataBucket.ts +49 -0
  146. package/src/client/sync/stream/AbstractRemote.ts +626 -0
  147. package/src/client/sync/stream/AbstractStreamingSyncImplementation.ts +1258 -0
  148. package/src/client/sync/stream/WebsocketClientTransport.ts +80 -0
  149. package/src/client/sync/stream/core-instruction.ts +99 -0
  150. package/src/client/sync/stream/streaming-sync-types.ts +205 -0
  151. package/src/client/sync/sync-streams.ts +107 -0
  152. package/src/client/triggers/TriggerManager.ts +384 -0
  153. package/src/client/triggers/TriggerManagerImpl.ts +314 -0
  154. package/src/client/triggers/sanitizeSQL.ts +66 -0
  155. package/src/client/watched/GetAllQuery.ts +46 -0
  156. package/src/client/watched/WatchedQuery.ts +121 -0
  157. package/src/client/watched/processors/AbstractQueryProcessor.ts +226 -0
  158. package/src/client/watched/processors/DifferentialQueryProcessor.ts +305 -0
  159. package/src/client/watched/processors/OnChangeQueryProcessor.ts +122 -0
  160. package/src/client/watched/processors/comparators.ts +57 -0
  161. package/src/db/DBAdapter.ts +134 -0
  162. package/src/db/crud/SyncProgress.ts +100 -0
  163. package/src/db/crud/SyncStatus.ts +308 -0
  164. package/src/db/crud/UploadQueueStatus.ts +20 -0
  165. package/src/db/schema/Column.ts +60 -0
  166. package/src/db/schema/Index.ts +39 -0
  167. package/src/db/schema/IndexedColumn.ts +42 -0
  168. package/src/db/schema/RawTable.ts +67 -0
  169. package/src/db/schema/Schema.ts +76 -0
  170. package/src/db/schema/Table.ts +359 -0
  171. package/src/db/schema/TableV2.ts +9 -0
  172. package/src/index.ts +52 -0
  173. package/src/types/types.ts +9 -0
  174. package/src/utils/AbortOperation.ts +17 -0
  175. package/src/utils/BaseObserver.ts +41 -0
  176. package/src/utils/ControlledExecutor.ts +72 -0
  177. package/src/utils/DataStream.ts +211 -0
  178. package/src/utils/Logger.ts +47 -0
  179. package/src/utils/MetaBaseObserver.ts +81 -0
  180. package/src/utils/async.ts +61 -0
  181. package/src/utils/mutex.ts +34 -0
  182. package/src/utils/parseQuery.ts +25 -0
@@ -0,0 +1,211 @@
1
+ import Logger, { ILogger } from 'js-logger';
2
+ import { BaseListener, BaseObserver } from './BaseObserver.js';
3
+
4
+ export type DataStreamOptions<ParsedData, SourceData> = {
5
+ mapLine?: (line: SourceData) => ParsedData;
6
+
7
+ /**
8
+ * Close the stream if any consumer throws an error
9
+ */
10
+ closeOnError?: boolean;
11
+ pressure?: {
12
+ highWaterMark?: number;
13
+ lowWaterMark?: number;
14
+ };
15
+ logger?: ILogger;
16
+ };
17
+
18
+ export type DataStreamCallback<Data extends any = any> = (data: Data) => Promise<void>;
19
+
20
+ export interface DataStreamListener<Data extends any = any> extends BaseListener {
21
+ data: (data: Data) => Promise<void>;
22
+ closed: () => void;
23
+ error: (error: Error) => void;
24
+ highWater: () => Promise<void>;
25
+ lowWater: () => Promise<void>;
26
+ }
27
+
28
+ export const DEFAULT_PRESSURE_LIMITS = {
29
+ highWater: 10,
30
+ lowWater: 0
31
+ };
32
+
33
+ /**
34
+ * A very basic implementation of a data stream with backpressure support which does not use
35
+ * native JS streams or async iterators.
36
+ * This is handy for environments such as React Native which need polyfills for the above.
37
+ */
38
+ export class DataStream<ParsedData, SourceData = any> extends BaseObserver<DataStreamListener<ParsedData>> {
39
+ dataQueue: SourceData[];
40
+
41
+ protected isClosed: boolean;
42
+
43
+ protected processingPromise: Promise<void> | null;
44
+ protected notifyDataAdded: (() => void) | null;
45
+
46
+ protected logger: ILogger;
47
+
48
+ protected mapLine: (line: SourceData) => ParsedData;
49
+
50
+ constructor(protected options?: DataStreamOptions<ParsedData, SourceData>) {
51
+ super();
52
+ this.processingPromise = null;
53
+ this.isClosed = false;
54
+ this.dataQueue = [];
55
+ this.mapLine = options?.mapLine ?? ((line) => line as any);
56
+
57
+ this.logger = options?.logger ?? Logger.get('DataStream');
58
+
59
+ if (options?.closeOnError) {
60
+ const l = this.registerListener({
61
+ error: (ex) => {
62
+ l?.();
63
+ this.close();
64
+ }
65
+ });
66
+ }
67
+ }
68
+
69
+ get highWatermark() {
70
+ return this.options?.pressure?.highWaterMark ?? DEFAULT_PRESSURE_LIMITS.highWater;
71
+ }
72
+
73
+ get lowWatermark() {
74
+ return this.options?.pressure?.lowWaterMark ?? DEFAULT_PRESSURE_LIMITS.lowWater;
75
+ }
76
+
77
+ get closed() {
78
+ return this.isClosed;
79
+ }
80
+
81
+ async close() {
82
+ this.isClosed = true;
83
+ await this.processingPromise;
84
+ this.iterateListeners((l) => l.closed?.());
85
+ // Discard any data in the queue
86
+ this.dataQueue = [];
87
+ this.listeners.clear();
88
+ }
89
+
90
+ /**
91
+ * Enqueues data for the consumers to read
92
+ */
93
+ enqueueData(data: SourceData) {
94
+ if (this.isClosed) {
95
+ throw new Error('Cannot enqueue data into closed stream.');
96
+ }
97
+
98
+ this.dataQueue.push(data);
99
+ this.notifyDataAdded?.();
100
+
101
+ this.processQueue();
102
+ }
103
+
104
+ /**
105
+ * Reads data once from the data stream
106
+ * @returns a Data payload or Null if the stream closed.
107
+ */
108
+ async read(): Promise<ParsedData | null> {
109
+ if (this.closed) {
110
+ return null;
111
+ }
112
+
113
+ return new Promise((resolve, reject) => {
114
+ const l = this.registerListener({
115
+ data: async (data) => {
116
+ resolve(data);
117
+ // Remove the listener
118
+ l?.();
119
+ },
120
+ closed: () => {
121
+ resolve(null);
122
+ l?.();
123
+ },
124
+ error: (ex) => {
125
+ reject(ex);
126
+ l?.();
127
+ }
128
+ });
129
+
130
+ this.processQueue();
131
+ });
132
+ }
133
+
134
+ /**
135
+ * Executes a callback for each data item in the stream
136
+ */
137
+ forEach(callback: DataStreamCallback<ParsedData>) {
138
+ if (this.dataQueue.length <= this.lowWatermark) {
139
+ this.iterateAsyncErrored(async (l) => l.lowWater?.());
140
+ }
141
+
142
+ return this.registerListener({
143
+ data: callback
144
+ });
145
+ }
146
+
147
+ protected processQueue() {
148
+ if (this.processingPromise) {
149
+ return;
150
+ }
151
+
152
+ const promise = (this.processingPromise = this._processQueue());
153
+ promise.finally(() => {
154
+ return (this.processingPromise = null);
155
+ });
156
+ return promise;
157
+ }
158
+
159
+ protected hasDataReader() {
160
+ return Array.from(this.listeners.values()).some((l) => !!l.data);
161
+ }
162
+
163
+ protected async _processQueue() {
164
+ /**
165
+ * Allow listeners to mutate the queue before processing.
166
+ * This allows for operations such as dropping or compressing data
167
+ * on high water or requesting more data on low water.
168
+ */
169
+ if (this.dataQueue.length >= this.highWatermark) {
170
+ await this.iterateAsyncErrored(async (l) => l.highWater?.());
171
+ }
172
+
173
+ if (this.isClosed || !this.hasDataReader()) {
174
+ return;
175
+ }
176
+
177
+ if (this.dataQueue.length) {
178
+ const data = this.dataQueue.shift()!;
179
+ const mapped = this.mapLine(data);
180
+ await this.iterateAsyncErrored(async (l) => l.data?.(mapped));
181
+ }
182
+
183
+ if (this.dataQueue.length <= this.lowWatermark) {
184
+ const dataAdded = new Promise<void>((resolve) => {
185
+ this.notifyDataAdded = resolve;
186
+ });
187
+
188
+ await Promise.race([this.iterateAsyncErrored(async (l) => l.lowWater?.()), dataAdded]);
189
+ this.notifyDataAdded = null;
190
+ }
191
+
192
+ if (this.dataQueue.length > 0) {
193
+ // Next tick
194
+ setTimeout(() => this.processQueue());
195
+ }
196
+ }
197
+
198
+ protected async iterateAsyncErrored(cb: (l: Partial<DataStreamListener<ParsedData>>) => Promise<void>) {
199
+ // Important: We need to copy the listeners, as calling a listener could result in adding another
200
+ // listener, resulting in infinite loops.
201
+ const listeners = Array.from(this.listeners.values());
202
+ for (let i of listeners) {
203
+ try {
204
+ await cb(i);
205
+ } catch (ex) {
206
+ this.logger.error(ex);
207
+ this.iterateListeners((l) => l.error?.(ex));
208
+ }
209
+ }
210
+ }
211
+ }
@@ -0,0 +1,47 @@
1
+ import Logger, { type ILogger, type ILogLevel } from 'js-logger';
2
+
3
+ export { GlobalLogger, ILogger, ILoggerOpts, ILogHandler, ILogLevel } from 'js-logger';
4
+
5
+ const TypedLogger: ILogger = Logger as any;
6
+
7
+ export const LogLevel = {
8
+ TRACE: TypedLogger.TRACE,
9
+ DEBUG: TypedLogger.DEBUG,
10
+ INFO: TypedLogger.INFO,
11
+ TIME: TypedLogger.TIME,
12
+ WARN: TypedLogger.WARN,
13
+ ERROR: TypedLogger.ERROR,
14
+ OFF: TypedLogger.OFF
15
+ };
16
+
17
+ export interface CreateLoggerOptions {
18
+ logLevel?: ILogLevel;
19
+ }
20
+
21
+ /**
22
+ * Retrieves the base (default) logger instance.
23
+ *
24
+ * This base logger controls the default logging configuration and is shared
25
+ * across all loggers created with `createLogger`. Adjusting settings on this
26
+ * base logger affects all loggers derived from it unless explicitly overridden.
27
+ *
28
+ */
29
+ export function createBaseLogger() {
30
+ return Logger;
31
+ }
32
+
33
+ /**
34
+ * Creates and configures a new named logger based on the base logger.
35
+ *
36
+ * Named loggers allow specific modules or areas of your application to have
37
+ * their own logging levels and behaviors. These loggers inherit configuration
38
+ * from the base logger by default but can override settings independently.
39
+ */
40
+ export function createLogger(name: string, options: CreateLoggerOptions = {}): ILogger {
41
+ const logger = Logger.get(name);
42
+ if (options.logLevel) {
43
+ logger.setLevel(options.logLevel);
44
+ }
45
+
46
+ return logger;
47
+ }
@@ -0,0 +1,81 @@
1
+ import { BaseListener, BaseObserver, BaseObserverInterface } from './BaseObserver.js';
2
+
3
+ /**
4
+ * Represents the counts of listeners for each event type in a BaseListener.
5
+ */
6
+ export type ListenerCounts<Listener extends BaseListener> = Partial<Record<keyof Listener, number>> & {
7
+ total: number;
8
+ };
9
+
10
+ /**
11
+ * Meta listener which reports the counts of listeners for each event type.
12
+ */
13
+ export interface MetaListener<ParentListener extends BaseListener> extends BaseListener {
14
+ listenersChanged?: (counts: ListenerCounts<ParentListener>) => void;
15
+ }
16
+
17
+ export interface ListenerMetaManager<Listener extends BaseListener>
18
+ extends BaseObserverInterface<MetaListener<Listener>> {
19
+ counts: ListenerCounts<Listener>;
20
+ }
21
+
22
+ export interface MetaBaseObserverInterface<Listener extends BaseListener> extends BaseObserverInterface<Listener> {
23
+ listenerMeta: ListenerMetaManager<Listener>;
24
+ }
25
+
26
+ /**
27
+ * A BaseObserver that tracks the counts of listeners for each event type.
28
+ */
29
+ export class MetaBaseObserver<Listener extends BaseListener>
30
+ extends BaseObserver<Listener>
31
+ implements MetaBaseObserverInterface<Listener>
32
+ {
33
+ protected get listenerCounts(): ListenerCounts<Listener> {
34
+ const counts = {} as Partial<Record<keyof Listener, number>>;
35
+ let total = 0;
36
+ for (const listener of this.listeners) {
37
+ for (const key in listener) {
38
+ if (listener[key]) {
39
+ counts[key] = (counts[key] ?? 0) + 1;
40
+ total++;
41
+ }
42
+ }
43
+ }
44
+ return {
45
+ ...counts,
46
+ total
47
+ };
48
+ }
49
+
50
+ get listenerMeta(): ListenerMetaManager<Listener> {
51
+ return {
52
+ counts: this.listenerCounts,
53
+ // Allows registering a meta listener that will be notified of changes in listener counts
54
+ registerListener: (listener: Partial<MetaListener<Listener>>) => {
55
+ return this.metaListener.registerListener(listener);
56
+ }
57
+ };
58
+ }
59
+
60
+ protected metaListener: BaseObserver<MetaListener<Listener>>;
61
+
62
+ constructor() {
63
+ super();
64
+ this.metaListener = new BaseObserver<MetaListener<Listener>>();
65
+ }
66
+
67
+ registerListener(listener: Partial<Listener>): () => void {
68
+ const dispose = super.registerListener(listener);
69
+ const updatedCount = this.listenerCounts;
70
+ this.metaListener.iterateListeners((l) => {
71
+ l.listenersChanged?.(updatedCount);
72
+ });
73
+ return () => {
74
+ dispose();
75
+ const updatedCount = this.listenerCounts;
76
+ this.metaListener.iterateListeners((l) => {
77
+ l.listenersChanged?.(updatedCount);
78
+ });
79
+ };
80
+ }
81
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * A ponyfill for `Symbol.asyncIterator` that is compatible with the
3
+ * [recommended polyfill](https://github.com/Azure/azure-sdk-for-js/blob/%40azure/core-asynciterator-polyfill_1.0.2/sdk/core/core-asynciterator-polyfill/src/index.ts#L4-L6)
4
+ * we recommend for React Native.
5
+ *
6
+ * As long as we use this symbol (instead of `for await` and `async *`) in this package, we can be compatible with async
7
+ * iterators without requiring them.
8
+ */
9
+ export const symbolAsyncIterator: typeof Symbol.asyncIterator =
10
+ Symbol.asyncIterator ?? Symbol.for('Symbol.asyncIterator');
11
+
12
+ /**
13
+ * Throttle a function to be called at most once every "wait" milliseconds,
14
+ * on the trailing edge.
15
+ *
16
+ * Roughly equivalent to lodash/throttle with {leading: false, trailing: true}
17
+ */
18
+ export function throttleTrailing(func: () => void, wait: number) {
19
+ let timeoutId: ReturnType<typeof setTimeout> | null = null;
20
+
21
+ const later = () => {
22
+ func();
23
+ timeoutId = null;
24
+ };
25
+
26
+ return function () {
27
+ if (timeoutId == null) {
28
+ timeoutId = setTimeout(later, wait);
29
+ }
30
+ };
31
+ }
32
+
33
+ /**
34
+ * Throttle a function to be called at most once every "wait" milliseconds,
35
+ * on the leading and trailing edge.
36
+ *
37
+ * Roughly equivalent to lodash/throttle with {leading: true, trailing: true}
38
+ */
39
+ export function throttleLeadingTrailing(func: () => void, wait: number) {
40
+ let timeoutId: ReturnType<typeof setTimeout> | null = null;
41
+ let lastCallTime: number = 0;
42
+
43
+ const invokeFunction = () => {
44
+ func();
45
+ lastCallTime = Date.now();
46
+ timeoutId = null;
47
+ };
48
+
49
+ return function () {
50
+ const now = Date.now();
51
+ const timeToWait = wait - (now - lastCallTime);
52
+
53
+ if (timeToWait <= 0) {
54
+ // Leading edge: Call the function immediately if enough time has passed
55
+ invokeFunction();
56
+ } else if (!timeoutId) {
57
+ // Set a timeout for the trailing edge if not already set
58
+ timeoutId = setTimeout(invokeFunction, timeToWait);
59
+ }
60
+ };
61
+ }
@@ -0,0 +1,34 @@
1
+ import { Mutex } from 'async-mutex';
2
+
3
+ /**
4
+ * Wrapper for async-mutex runExclusive, which allows for a timeout on each exclusive lock.
5
+ */
6
+ export async function mutexRunExclusive<T>(
7
+ mutex: Mutex,
8
+ callback: () => Promise<T>,
9
+ options?: { timeoutMs: number }
10
+ ): Promise<T> {
11
+ return new Promise((resolve, reject) => {
12
+ const timeout = options?.timeoutMs;
13
+ let timedOut = false;
14
+ const timeoutId = timeout
15
+ ? setTimeout(() => {
16
+ timedOut = true;
17
+ reject(new Error('Timeout waiting for lock'));
18
+ }, timeout)
19
+ : undefined;
20
+
21
+ mutex.runExclusive(async () => {
22
+ if (timeoutId) {
23
+ clearTimeout(timeoutId);
24
+ }
25
+ if (timedOut) return;
26
+
27
+ try {
28
+ resolve(await callback());
29
+ } catch (ex) {
30
+ reject(ex);
31
+ }
32
+ });
33
+ });
34
+ }
@@ -0,0 +1,25 @@
1
+ import type { CompilableQuery } from '../types/types.js';
2
+
3
+ export interface ParsedQuery {
4
+ sqlStatement: string;
5
+ parameters: any[];
6
+ }
7
+
8
+ export const parseQuery = <T>(query: string | CompilableQuery<T>, parameters: any[]): ParsedQuery => {
9
+ let sqlStatement: string;
10
+
11
+ if (typeof query == 'string') {
12
+ sqlStatement = query;
13
+ } else {
14
+ const hasAdditionalParameters = parameters.length > 0;
15
+ if (hasAdditionalParameters) {
16
+ throw new Error('You cannot pass parameters to a compiled query.');
17
+ }
18
+
19
+ const compiled = query.compile();
20
+ sqlStatement = compiled.sql;
21
+ parameters = compiled.parameters as any[];
22
+ }
23
+
24
+ return { sqlStatement, parameters: parameters };
25
+ };