aboutsummaryrefslogtreecommitdiff
path: root/src/extensions/ArrayExtensions.ts
diff options
context:
space:
mode:
authorSam Wilkins <samwilkins333@gmail.com>2019-09-19 16:30:14 -0400
committerSam Wilkins <samwilkins333@gmail.com>2019-09-19 16:30:14 -0400
commit3fb212eb601dbaff28a61100fc0478b1c706a3b8 (patch)
tree0211e63a7f279c0f677b94de1aac4c14586f7d71 /src/extensions/ArrayExtensions.ts
parent7b97d7e054c2630dd0d37cd146dd2cf32c31d3e1 (diff)
organized and genericized
Diffstat (limited to 'src/extensions/ArrayExtensions.ts')
-rw-r--r--src/extensions/ArrayExtensions.ts537
1 files changed, 263 insertions, 274 deletions
diff --git a/src/extensions/ArrayExtensions.ts b/src/extensions/ArrayExtensions.ts
index 1190aa48c..70508f6df 100644
--- a/src/extensions/ArrayExtensions.ts
+++ b/src/extensions/ArrayExtensions.ts
@@ -1,61 +1,3 @@
-interface BatchContext {
- completedBatches: number;
- remainingBatches: number;
-}
-type BatchConverterSync<I, O> = (batch: I[], context: BatchContext) => O[];
-type BatchHandlerSync<I> = (batch: I[], context: BatchContext) => void;
-type BatchConverterAsync<I, O> = (batch: I[], context: BatchContext) => Promise<O[]>;
-type BatchHandlerAsync<I> = (batch: I[], context: BatchContext) => Promise<void>;
-type BatchConverter<I, O> = BatchConverterSync<I, O> | BatchConverterAsync<I, O>;
-type BatchHandler<I> = BatchHandlerSync<I> | BatchHandlerAsync<I>;
-type FixedBatcher = { batchSize: number } | { batchCount: number, mode?: Mode };
-interface ExecutorResult<A> {
- updated: A;
- makeNextBatch: boolean;
-}
-interface PredicateBatcher<I, A> {
- executor: (element: I, accumulator: A) => ExecutorResult<A>;
- initial: A;
- persistAccumulator?: boolean;
-}
-interface PredicateBatcherAsyncInterface<I, A> {
- executor: (element: I, accumulator: A) => Promise<ExecutorResult<A>>;
- initial: A;
- persistAccumulator?: boolean;
-}
-type PredicateBatcherAsync<I, A> = PredicateBatcher<I, A> | PredicateBatcherAsyncInterface<I, A>;
-type Batcher<I, A> = FixedBatcher | PredicateBatcher<I, A>;
-type BatcherAsync<I, A> = Batcher<I, A> | PredicateBatcherAsync<I, A>;
-
-enum TimeUnit {
- Milliseconds,
- Seconds,
- Minutes
-}
-
-interface Interval {
- magnitude: number;
- unit: TimeUnit;
-}
-
-enum Mode {
- Balanced,
- Even
-}
-
-const convert = (interval: Interval) => {
- const { magnitude, unit } = interval;
- switch (unit) {
- default:
- case TimeUnit.Milliseconds:
- return magnitude;
- case TimeUnit.Seconds:
- return magnitude * 1000;
- case TimeUnit.Minutes:
- return magnitude * 1000 * 60;
- }
-};
-
interface Array<T> {
fixedBatch<T>(batcher: FixedBatcher): T[][];
predicateBatch<T, A = undefined>(batcher: PredicateBatcher<T, A>): T[][];
@@ -75,134 +17,185 @@ interface Array<T> {
lastElement(): T;
}
-module.exports.AssignArrayExtensions = function () {
- Array.prototype.fixedBatch = module.exports.fixedBatch;
- Array.prototype.predicateBatch = module.exports.predicateBatch;
- Array.prototype.predicateBatchAsync = module.exports.predicateBatchAsync;
- Array.prototype.batch = module.exports.batch;
- Array.prototype.batchAsync = module.exports.batchAsync;
- Array.prototype.batchedForEach = module.exports.batchedForEach;
- Array.prototype.batchedMap = module.exports.batchedMap;
- Array.prototype.batchedForEachAsync = module.exports.batchedForEachAsync;
- Array.prototype.batchedMapAsync = module.exports.batchedMapAsync;
- Array.prototype.batchedForEachInterval = module.exports.batchedForEachInterval;
- Array.prototype.batchedMapInterval = module.exports.batchedMapInterval;
- Array.prototype.lastElement = module.exports.lastElement;
+interface BatchContext {
+ completedBatches: number;
+ remainingBatches: number;
+}
+
+interface ExecutorResult<A> {
+ updated: A;
+ makeNextBatch: boolean;
+}
+
+interface PredicateBatcherCommon<I, A> {
+ initial: A;
+ persistAccumulator?: boolean;
+}
+
+interface Interval {
+ magnitude: number;
+ unit: typeof module.exports.TimeUnit;
+}
+
+type BatchConverterSync<I, O> = (batch: I[], context: BatchContext) => O[];
+type BatchHandlerSync<I> = (batch: I[], context: BatchContext) => void;
+type BatchConverterAsync<I, O> = (batch: I[], context: BatchContext) => Promise<O[]>;
+type BatchHandlerAsync<I> = (batch: I[], context: BatchContext) => Promise<void>;
+type BatchConverter<I, O> = BatchConverterSync<I, O> | BatchConverterAsync<I, O>;
+type BatchHandler<I> = BatchHandlerSync<I> | BatchHandlerAsync<I>;
+
+type FixedBatcher = { batchSize: number } | { batchCount: number, mode?: typeof module.exports.Mode };
+type PredicateBatcher<I, A> = PredicateBatcherCommon<I, A> & { executor: (element: I, accumulator: A) => ExecutorResult<A> };
+type PredicateBatcherAsync<I, A> = PredicateBatcherCommon<I, A> & { executor: (element: I, accumulator: A) => ExecutorResult<A> | Promise<ExecutorResult<A>> };
+
+type Batcher<I, A> = FixedBatcher | PredicateBatcher<I, A>;
+type BatcherAsync<I, A> = Batcher<I, A> | PredicateBatcherAsync<I, A>;
+
+module.exports.Mode = {
+ Balanced: 0,
+ Even: 1
};
-module.exports.fixedBatch = function <T>(batcher: FixedBatcher): T[][] {
- const batches: T[][] = [];
- const length = this.length;
- let i = 0;
- if ("batchSize" in batcher) {
- const { batchSize } = batcher;
- while (i < this.length) {
- const cap = Math.min(i + batchSize, length);
- batches.push(this.slice(i, i = cap));
- }
- } else if ("batchCount" in batcher) {
- let { batchCount, mode } = batcher;
- const resolved = mode || Mode.Balanced;
- if (batchCount < 1) {
- throw new Error("Batch count must be a positive integer!");
- }
- if (batchCount === 1) {
- return [this];
- }
- if (batchCount >= this.length) {
- return this.map((element: T) => [element]);
- }
+module.exports.TimeUnit = {
+ Milliseconds: 0,
+ Seconds: 1,
+ Minutes: 2
+};
- let length = this.length;
- let size: number;
+module.exports.Assign = function () {
- if (length % batchCount === 0) {
- size = Math.floor(length / batchCount);
- while (i < length) {
- batches.push(this.slice(i, i += size));
+ Array.prototype.fixedBatch = function <T>(batcher: FixedBatcher): T[][] {
+ const batches: T[][] = [];
+ const length = this.length;
+ let i = 0;
+ if ("batchSize" in batcher) {
+ const { batchSize } = batcher;
+ while (i < this.length) {
+ const cap = Math.min(i + batchSize, length);
+ batches.push(this.slice(i, i = cap));
}
- } else if (resolved === Mode.Balanced) {
- while (i < length) {
- size = Math.ceil((length - i) / batchCount--);
- batches.push(this.slice(i, i += size));
+ } else if ("batchCount" in batcher) {
+ let { batchCount, mode } = batcher;
+ const resolved = mode || module.exports.Mode.Balanced;
+ if (batchCount < 1) {
+ throw new Error("Batch count must be a positive integer!");
}
- } else {
- batchCount--;
- size = Math.floor(length / batchCount);
- if (length % size === 0) {
- size--;
+ if (batchCount === 1) {
+ return [this];
}
- while (i < size * batchCount) {
- batches.push(this.slice(i, i += size));
+ if (batchCount >= this.length) {
+ return this.map((element: T) => [element]);
+ }
+
+ let length = this.length;
+ let size: number;
+
+ if (length % batchCount === 0) {
+ size = Math.floor(length / batchCount);
+ while (i < length) {
+ batches.push(this.slice(i, i += size));
+ }
+ } else if (resolved === module.exports.Mode.Balanced) {
+ while (i < length) {
+ size = Math.ceil((length - i) / batchCount--);
+ batches.push(this.slice(i, i += size));
+ }
+ } else {
+ batchCount--;
+ size = Math.floor(length / batchCount);
+ if (length % size === 0) {
+ size--;
+ }
+ while (i < size * batchCount) {
+ batches.push(this.slice(i, i += size));
+ }
+ batches.push(this.slice(size * batchCount));
}
- batches.push(this.slice(size * batchCount));
}
- }
- return batches;
-};
+ return batches;
+ };
-module.exports.predicateBatch = function <T, A>(batcher: PredicateBatcher<T, A>): T[][] {
- const batches: T[][] = [];
- let batch: T[] = [];
- const { executor, initial, persistAccumulator } = batcher;
- let accumulator = initial;
- for (let element of this) {
- const { updated, makeNextBatch } = executor(element, accumulator);
- accumulator = updated;
- if (!makeNextBatch) {
- batch.push(element);
- } else {
- batches.push(batch);
- batch = [element];
- if (!persistAccumulator) {
- accumulator = initial;
+ Array.prototype.predicateBatch = function <T, A>(batcher: PredicateBatcher<T, A>): T[][] {
+ const batches: T[][] = [];
+ let batch: T[] = [];
+ const { executor, initial, persistAccumulator } = batcher;
+ let accumulator = initial;
+ for (let element of this) {
+ const { updated, makeNextBatch } = executor(element, accumulator);
+ accumulator = updated;
+ if (!makeNextBatch) {
+ batch.push(element);
+ } else {
+ batches.push(batch);
+ batch = [element];
+ if (!persistAccumulator) {
+ accumulator = initial;
+ }
}
}
- }
- batches.push(batch);
- return batches;
-};
+ batches.push(batch);
+ return batches;
+ };
-module.exports.predicateBatchAsync = async function <T, A>(batcher: PredicateBatcherAsync<T, A>): Promise<T[][]> {
- const batches: T[][] = [];
- let batch: T[] = [];
- const { executor, initial, persistAccumulator } = batcher;
- let accumulator: A = initial;
- for (let element of this) {
- const { updated, makeNextBatch } = await executor(element, accumulator);
- accumulator = updated;
- if (!makeNextBatch) {
- batch.push(element);
- } else {
- batches.push(batch);
- batch = [element];
- if (!persistAccumulator) {
- accumulator = initial;
+ Array.prototype.predicateBatchAsync = async function <T, A>(batcher: PredicateBatcherAsync<T, A>): Promise<T[][]> {
+ const batches: T[][] = [];
+ let batch: T[] = [];
+ const { executor, initial, persistAccumulator } = batcher;
+ let accumulator: A = initial;
+ for (let element of this) {
+ const { updated, makeNextBatch } = await executor(element, accumulator);
+ accumulator = updated;
+ if (!makeNextBatch) {
+ batch.push(element);
+ } else {
+ batches.push(batch);
+ batch = [element];
+ if (!persistAccumulator) {
+ accumulator = initial;
+ }
}
}
- }
- batches.push(batch);
- return batches;
-};
+ batches.push(batch);
+ return batches;
+ };
-module.exports.batch = function <T, A>(batcher: Batcher<T, A>): T[][] {
- if ("executor" in batcher) {
- return this.predicateBatch(batcher);
- } else {
- return this.fixedBatch(batcher);
- }
-};
+ Array.prototype.batch = function <T, A>(batcher: Batcher<T, A>): T[][] {
+ if ("executor" in batcher) {
+ return this.predicateBatch(batcher);
+ } else {
+ return this.fixedBatch(batcher);
+ }
+ };
-module.exports.batchAsync = async function <T, A>(batcher: BatcherAsync<T, A>): Promise<T[][]> {
- if ("executor" in batcher) {
- return this.predicateBatchAsync(batcher);
- } else {
- return this.fixedBatch(batcher);
- }
-};
+ Array.prototype.batchAsync = async function <T, A>(batcher: BatcherAsync<T, A>): Promise<T[][]> {
+ if ("executor" in batcher) {
+ return this.predicateBatchAsync(batcher);
+ } else {
+ return this.fixedBatch(batcher);
+ }
+ };
+
+ Array.prototype.batchedForEach = function <I, A>(batcher: Batcher<I, A>, handler: BatchHandlerSync<I>): void {
+ if (this.length) {
+ let completed = 0;
+ const batches = this.batch(batcher);
+ const quota = batches.length;
+ for (let batch of batches) {
+ const context: BatchContext = {
+ completedBatches: completed,
+ remainingBatches: quota - completed,
+ };
+ handler(batch, context);
+ completed++;
+ }
+ }
+ };
-module.exports.batchedForEach = function <I, A>(batcher: Batcher<I, A>, handler: BatchHandlerSync<I>): void {
- if (this.length) {
+ Array.prototype.batchedMap = function <I, O, A>(batcher: Batcher<I, A>, handler: BatchConverterSync<I, O>): O[] {
+ if (!this.length) {
+ return [];
+ }
+ let collector: O[] = [];
let completed = 0;
const batches = this.batch(batcher);
const quota = batches.length;
@@ -211,33 +204,33 @@ module.exports.batchedForEach = function <I, A>(batcher: Batcher<I, A>, handler:
completedBatches: completed,
remainingBatches: quota - completed,
};
- handler(batch, context);
+ collector.push(...handler(batch, context));
completed++;
}
- }
-};
+ return collector;
+ };
-module.exports.batchedMap = function <I, O, A>(batcher: Batcher<I, A>, handler: BatchConverterSync<I, O>): O[] {
- if (!this.length) {
- return [];
- }
- let collector: O[] = [];
- let completed = 0;
- const batches = this.batch(batcher);
- const quota = batches.length;
- for (let batch of batches) {
- const context: BatchContext = {
- completedBatches: completed,
- remainingBatches: quota - completed,
- };
- collector.push(...handler(batch, context));
- completed++;
- }
- return collector;
-};
+ Array.prototype.batchedForEachAsync = async function <I, A>(batcher: BatcherAsync<I, A>, handler: BatchHandler<I>): Promise<void> {
+ if (this.length) {
+ let completed = 0;
+ const batches = await this.batchAsync(batcher);
+ const quota = batches.length;
+ for (let batch of batches) {
+ const context: BatchContext = {
+ completedBatches: completed,
+ remainingBatches: quota - completed,
+ };
+ await handler(batch, context);
+ completed++;
+ }
+ }
+ };
-module.exports.batchedForEachAsync = async function <I, A>(batcher: BatcherAsync<I, A>, handler: BatchHandler<I>): Promise<void> {
- if (this.length) {
+ Array.prototype.batchedMapAsync = async function <I, O, A>(batcher: BatcherAsync<I, A>, handler: BatchConverter<I, O>): Promise<O[]> {
+ if (!this.length) {
+ return [];
+ }
+ let collector: O[] = [];
let completed = 0;
const batches = await this.batchAsync(batcher);
const quota = batches.length;
@@ -246,96 +239,92 @@ module.exports.batchedForEachAsync = async function <I, A>(batcher: BatcherAsync
completedBatches: completed,
remainingBatches: quota - completed,
};
- await handler(batch, context);
+ collector.push(...(await handler(batch, context)));
completed++;
}
- }
-};
+ return collector;
+ };
-module.exports.batchedMapAsync = async function <I, O, A>(batcher: BatcherAsync<I, A>, handler: BatchConverter<I, O>): Promise<O[]> {
- if (!this.length) {
- return [];
- }
- let collector: O[] = [];
- let completed = 0;
- const batches = await this.batchAsync(batcher);
- const quota = batches.length;
- for (let batch of batches) {
- const context: BatchContext = {
- completedBatches: completed,
- remainingBatches: quota - completed,
- };
- collector.push(...(await handler(batch, context)));
- completed++;
- }
- return collector;
-};
-
-module.exports.batchedForEachInterval = async function <I, A>(batcher: BatcherAsync<I, A>, handler: BatchHandler<I>, interval: Interval): Promise<void> {
- if (!this.length) {
- return;
- }
- const batches = await this.batchAsync(batcher);
- const quota = batches.length;
- return new Promise<void>(async resolve => {
- const iterator = batches[Symbol.iterator]();
- let completed = 0;
- while (true) {
- const next = iterator.next();
- await new Promise<void>(resolve => {
- setTimeout(async () => {
- const batch = next.value;
- const context: BatchContext = {
- completedBatches: completed,
- remainingBatches: quota - completed,
- };
- await handler(batch, context);
- resolve();
- }, convert(interval));
- });
- if (++completed === quota) {
- break;
- }
+ Array.prototype.batchedForEachInterval = async function <I, A>(batcher: BatcherAsync<I, A>, handler: BatchHandler<I>, interval: Interval): Promise<void> {
+ if (!this.length) {
+ return;
}
- resolve();
- });
-};
+ const batches = await this.batchAsync(batcher);
+ const quota = batches.length;
+ return new Promise<void>(async resolve => {
+ const iterator = batches[Symbol.iterator]();
+ let completed = 0;
+ while (true) {
+ const next = iterator.next();
+ await new Promise<void>(resolve => {
+ setTimeout(async () => {
+ const batch = next.value;
+ const context: BatchContext = {
+ completedBatches: completed,
+ remainingBatches: quota - completed,
+ };
+ await handler(batch, context);
+ resolve();
+ }, convert(interval));
+ });
+ if (++completed === quota) {
+ break;
+ }
+ }
+ resolve();
+ });
+ };
-module.exports.batchedMapInterval = async function <I, O, A>(batcher: BatcherAsync<I, A>, handler: BatchConverter<I, O>, interval: Interval): Promise<O[]> {
- if (!this.length) {
- return [];
- }
- let collector: O[] = [];
- const batches = await this.batchAsync(batcher);
- const quota = batches.length;
- return new Promise<O[]>(async resolve => {
- const iterator = batches[Symbol.iterator]();
- let completed = 0;
- while (true) {
- const next = iterator.next();
- await new Promise<void>(resolve => {
- setTimeout(async () => {
- const batch = next.value;
- const context: BatchContext = {
- completedBatches: completed,
- remainingBatches: quota - completed,
- };
- collector.push(...(await handler(batch, context)));
- resolve();
- }, convert(interval));
- });
- if (++completed === quota) {
- resolve(collector);
- break;
+ Array.prototype.batchedMapInterval = async function <I, O, A>(batcher: BatcherAsync<I, A>, handler: BatchConverter<I, O>, interval: Interval): Promise<O[]> {
+ if (!this.length) {
+ return [];
+ }
+ let collector: O[] = [];
+ const batches = await this.batchAsync(batcher);
+ const quota = batches.length;
+ return new Promise<O[]>(async resolve => {
+ const iterator = batches[Symbol.iterator]();
+ let completed = 0;
+ while (true) {
+ const next = iterator.next();
+ await new Promise<void>(resolve => {
+ setTimeout(async () => {
+ const batch = next.value;
+ const context: BatchContext = {
+ completedBatches: completed,
+ remainingBatches: quota - completed,
+ };
+ collector.push(...(await handler(batch, context)));
+ resolve();
+ }, convert(interval));
+ });
+ if (++completed === quota) {
+ resolve(collector);
+ break;
+ }
}
+ });
+ };
+
+ Array.prototype.lastElement = function <T>() {
+ if (!this.length) {
+ return undefined;
}
- });
+ const last: T = this[this.length - 1];
+ return last;
+ };
+
};
-module.exports.lastElement = function <T>() {
- if (!this.length) {
- return undefined;
+const convert = (interval: Interval) => {
+ const { magnitude, unit } = interval;
+ switch (unit) {
+ default:
+ case module.exports.Mode.TimeUnit.Milliseconds:
+ return magnitude;
+ case module.exports.Mode.TimeUnit.Seconds:
+ return magnitude * 1000;
+ case module.exports.Mode.TimeUnit.Minutes:
+ return magnitude * 1000 * 60;
}
- const last: T = this[this.length - 1];
- return last;
-};
+}; \ No newline at end of file