Setup eslint and enforce rules
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -3,7 +3,7 @@ import {
|
||||
Collection, CollectionIndex,
|
||||
CollectionItem, ComparisonFunction,
|
||||
DeterminesEquality, KeyFunction,
|
||||
KeyOperator, KeyReducerFunction, MaybeCollectionIndex, MaybeCollectionItem
|
||||
KeyOperator, KeyReducerFunction, MaybeCollectionIndex, MaybeCollectionItem,
|
||||
} from './Collection'
|
||||
import {Iterable, StopIteration} from './Iterable'
|
||||
import {applyWhere, WhereOperator} from './where'
|
||||
@@ -20,53 +20,56 @@ export class AsyncCollection<T> {
|
||||
* Iterable of items to base this collction on.
|
||||
* @type Iterable
|
||||
*/
|
||||
private _items: Iterable<T>,
|
||||
private storedItems: Iterable<T>,
|
||||
|
||||
/**
|
||||
* Size to use when chunking results for memory-optimization.
|
||||
* @type number
|
||||
*/
|
||||
private _chunk_size: number = 1000, // TODO fix this. It's just for testing
|
||||
private iteratorChunkSize: number = 1000, // TODO fix this. It's just for testing
|
||||
) {}
|
||||
|
||||
private async _chunk(callback: (items: Collection<T>) => any): Promise<void> {
|
||||
await this._items.chunk(this._chunk_size, async items => {
|
||||
private async inChunks(callback: (items: Collection<T>) => any): Promise<void> {
|
||||
await this.storedItems.chunk(this.iteratorChunkSize, async items => {
|
||||
await callback(items)
|
||||
})
|
||||
await this._items.reset()
|
||||
await this.storedItems.reset()
|
||||
}
|
||||
|
||||
private async _chunk_all<T2>(key: KeyOperator<T, T2>, callback: (items: Collection<T2>) => any): Promise<void> {
|
||||
await this._items.chunk(this._chunk_size, async items => {
|
||||
private async inChunksAll<T2>(key: KeyOperator<T, T2>, callback: (items: Collection<T2>) => any): Promise<void> {
|
||||
await this.storedItems.chunk(this.iteratorChunkSize, async items => {
|
||||
await callback(items.pluck(key))
|
||||
})
|
||||
await this._items.reset()
|
||||
await this.storedItems.reset()
|
||||
}
|
||||
|
||||
private async _chunk_all_numbers<T2>(key: KeyOperator<T, T2>, callback: (items: number[]) => any): Promise<void> {
|
||||
await this._items.chunk(this._chunk_size, async items => {
|
||||
await callback(items.pluck(key).map(x => Number(x)).all())
|
||||
private async inChunksAllNumbers<T2>(key: KeyOperator<T, T2>, callback: (items: number[]) => any): Promise<void> {
|
||||
await this.storedItems.chunk(this.iteratorChunkSize, async items => {
|
||||
await callback(items.pluck(key).map(x => Number(x))
|
||||
.all())
|
||||
})
|
||||
await this._items.reset()
|
||||
await this.storedItems.reset()
|
||||
}
|
||||
|
||||
private async _chunk_all_associate<T2>(key: KeyOperator<T, T2>, callback: (items: AssociatedCollectionItem<T2, T>[]) => any): Promise<void> {
|
||||
await this._items.chunk(this._chunk_size, async items => {
|
||||
const assoc_items: AssociatedCollectionItem<T2, T>[] = []
|
||||
private async inChunksAllAssociated<T2>(key: KeyOperator<T, T2>, callback: (items: AssociatedCollectionItem<T2, T>[]) => any): Promise<void> {
|
||||
await this.storedItems.chunk(this.iteratorChunkSize, async items => {
|
||||
const assocItems: AssociatedCollectionItem<T2, T>[] = []
|
||||
if ( typeof key === 'function' ) {
|
||||
items.map((item, index) => {
|
||||
const key_item = key(item, index)
|
||||
assoc_items.push({ key: key_item, item })
|
||||
const keyItem = key(item, index)
|
||||
assocItems.push({ key: keyItem,
|
||||
item })
|
||||
})
|
||||
} else {
|
||||
items.map((item, index) => {
|
||||
assoc_items.push({key: (<any>item)[key], item})
|
||||
items.map(item => {
|
||||
assocItems.push({key: (<any>item)[key],
|
||||
item})
|
||||
})
|
||||
}
|
||||
|
||||
await callback(assoc_items)
|
||||
await callback(assocItems)
|
||||
})
|
||||
await this._items.reset()
|
||||
await this.storedItems.reset()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,7 +77,7 @@ export class AsyncCollection<T> {
|
||||
* @return Promise<array>
|
||||
*/
|
||||
async all(): Promise<CollectionItem<T>[]> {
|
||||
return (await this._items.all()).toArray()
|
||||
return (await this.storedItems.all()).toArray()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,7 +85,7 @@ export class AsyncCollection<T> {
|
||||
* @return Promise<Collection>
|
||||
*/
|
||||
async collect(): Promise<Collection<T>> {
|
||||
return this._items.all()
|
||||
return this.storedItems.all()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,20 +94,23 @@ export class AsyncCollection<T> {
|
||||
* @return Promise<number>
|
||||
*/
|
||||
async average<T2>(key?: KeyOperator<T, T2>): Promise<number> {
|
||||
let running_total = 0
|
||||
let running_items = 0
|
||||
let runningTotal = 0
|
||||
let runningItems = 0
|
||||
|
||||
const chunk_helper = (items: number[]) => {
|
||||
running_items += items.length
|
||||
running_total += items.reduce((prev, curr) => prev + curr)
|
||||
const chunkHelper = (items: number[]) => {
|
||||
runningItems += items.length
|
||||
runningTotal += items.reduce((prev, curr) => prev + curr)
|
||||
}
|
||||
|
||||
if ( key ) await this._chunk_all_numbers(key, chunk_helper)
|
||||
else await this._chunk((items) => {
|
||||
chunk_helper(items.map(x => Number(x)).all())
|
||||
})
|
||||
if ( key ) {
|
||||
await this.inChunksAllNumbers(key, chunkHelper)
|
||||
} else {
|
||||
await this.inChunks((items) => {
|
||||
chunkHelper(items.map(x => Number(x)).all())
|
||||
})
|
||||
}
|
||||
|
||||
return running_total / running_items
|
||||
return runningTotal / runningItems
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -115,19 +121,25 @@ export class AsyncCollection<T> {
|
||||
async median<T2>(key?: KeyOperator<T, T2>): Promise<number> {
|
||||
let items: number[] = []
|
||||
|
||||
const chunk_helper = (next_items: number[]) => {
|
||||
items = items.concat(next_items)
|
||||
const chunkHelper = (nextItems: number[]) => {
|
||||
items = items.concat(nextItems)
|
||||
}
|
||||
|
||||
if ( key ) await this._chunk_all_numbers(key, chunk_helper)
|
||||
else await this._chunk(items => {
|
||||
chunk_helper(items.map(x => Number(x)).all())
|
||||
})
|
||||
if ( key ) {
|
||||
await this.inChunksAllNumbers(key, chunkHelper)
|
||||
} else {
|
||||
await this.inChunks(chunkItems => {
|
||||
chunkHelper(chunkItems.map(x => Number(x)).all())
|
||||
})
|
||||
}
|
||||
|
||||
items = items.sort((a, b) => a - b)
|
||||
const middle = Math.floor((items.length - 1) / 2)
|
||||
if ( items.length % 2 ) return items[middle]
|
||||
else return (items[middle] + items[middle + 1]) / 2
|
||||
if ( items.length % 2 ) {
|
||||
return items[middle]
|
||||
} else {
|
||||
return (items[middle] + items[middle + 1]) / 2
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,19 +148,25 @@ export class AsyncCollection<T> {
|
||||
* @return Promise<number>
|
||||
*/
|
||||
async mode<T2>(key?: KeyOperator<T, T2>): Promise<number> {
|
||||
let counts: any = {}
|
||||
const counts: any = {}
|
||||
|
||||
const chunk_helper = (items: number[]) => {
|
||||
const chunkHelper = (items: number[]) => {
|
||||
for ( const item of items ) {
|
||||
if ( !counts[item] ) counts[item] = 1
|
||||
else counts[item] += 1
|
||||
if ( !counts[item] ) {
|
||||
counts[item] = 1
|
||||
} else {
|
||||
counts[item] += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( key ) await this._chunk_all_numbers(key, chunk_helper)
|
||||
else await this._chunk(items => {
|
||||
chunk_helper(items.map(x => Number(x)).all())
|
||||
})
|
||||
if ( key ) {
|
||||
await this.inChunksAllNumbers(key, chunkHelper)
|
||||
} else {
|
||||
await this.inChunks(items => {
|
||||
chunkHelper(items.map(x => Number(x)).all())
|
||||
})
|
||||
}
|
||||
|
||||
return Number(Object.keys(counts).reduce((a, b) => counts[a] > counts[b] ? a : b)[0])
|
||||
}
|
||||
@@ -171,10 +189,10 @@ export class AsyncCollection<T> {
|
||||
* @param [operand]
|
||||
* @return Promise<boolean>
|
||||
*/
|
||||
async contains<T2>(key: KeyOperator<T, T2>, operator: WhereOperator, operand?: any): Promise<boolean> {
|
||||
async contains<T2>(key: KeyOperator<T, T2>, operator: WhereOperator, operand?: unknown): Promise<boolean> {
|
||||
let contains = false
|
||||
|
||||
await this._chunk_all_associate(key, (items: AssociatedCollectionItem<T2, T>[]) => {
|
||||
await this.inChunksAllAssociated(key, (items: AssociatedCollectionItem<T2, T>[]) => {
|
||||
const matches = applyWhere(items, operator, operand)
|
||||
if ( matches.length > 0 ) {
|
||||
contains = true
|
||||
@@ -190,7 +208,7 @@ export class AsyncCollection<T> {
|
||||
* @return Promise<AsyncCollection>
|
||||
*/
|
||||
async clone(): Promise<AsyncCollection<T>> {
|
||||
return new AsyncCollection<T>(await this._items.clone())
|
||||
return new AsyncCollection<T>(await this.storedItems.clone())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -201,7 +219,7 @@ export class AsyncCollection<T> {
|
||||
async diff(items: AsyncCollectionComparable<T>): Promise<Collection<T>> {
|
||||
const matches: T[] = []
|
||||
|
||||
await this._chunk(async chunk => {
|
||||
await this.inChunks(async chunk => {
|
||||
for ( const item of chunk.all() ) {
|
||||
if ( !(await items.includes(item)) ) {
|
||||
matches.push(item)
|
||||
@@ -222,10 +240,11 @@ export class AsyncCollection<T> {
|
||||
async diffUsing(items: AsyncCollectionComparable<T>, compare: DeterminesEquality<T>): Promise<Collection<T>> {
|
||||
const matches: T[] = []
|
||||
|
||||
await this._chunk(async chunk => {
|
||||
await this.inChunks(async chunk => {
|
||||
for ( const item of chunk.all() ) {
|
||||
if ( !(await items.some(exc => compare(item, exc))) )
|
||||
if ( !(await items.some(exc => compare(item, exc))) ) {
|
||||
matches.push(item)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -240,7 +259,7 @@ export class AsyncCollection<T> {
|
||||
async includes(item: CollectionItem<T>): Promise<boolean> {
|
||||
let contains = false
|
||||
|
||||
await this._chunk(items => {
|
||||
await this.inChunks(items => {
|
||||
if ( items.includes(item) ) {
|
||||
contains = true
|
||||
throw new StopIteration()
|
||||
@@ -258,7 +277,7 @@ export class AsyncCollection<T> {
|
||||
async some(operator: (item: T) => boolean): Promise<boolean> {
|
||||
let contains = false
|
||||
|
||||
await this._chunk(items => {
|
||||
await this.inChunks(items => {
|
||||
for ( const item of items.all() ) {
|
||||
if ( operator(item) ) {
|
||||
contains = true
|
||||
@@ -278,7 +297,7 @@ export class AsyncCollection<T> {
|
||||
async each<T2>(func: AsyncKeyFunction<T, T2>): Promise<void> {
|
||||
let index = 0
|
||||
|
||||
await this._chunk(async items => {
|
||||
await this.inChunks(async items => {
|
||||
for ( const item of items.all() ) {
|
||||
await func(item, index)
|
||||
index += 1
|
||||
@@ -292,11 +311,11 @@ export class AsyncCollection<T> {
|
||||
* @return Promise<Collection>
|
||||
*/
|
||||
async map<T2>(func: AsyncKeyFunction<T, T2>): Promise<Collection<T2>> {
|
||||
const new_items: CollectionItem<T2>[] = []
|
||||
const newItems: CollectionItem<T2>[] = []
|
||||
await this.each(async (item, index) => {
|
||||
new_items.push(await func(item, index))
|
||||
newItems.push(await func(item, index))
|
||||
})
|
||||
return new Collection<T2>(new_items)
|
||||
return new Collection<T2>(newItems)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -308,7 +327,7 @@ export class AsyncCollection<T> {
|
||||
let pass = true
|
||||
let index = 0
|
||||
|
||||
await this._chunk(async items => {
|
||||
await this.inChunks(async items => {
|
||||
for ( const item of items.all() ) {
|
||||
if ( !(await func(item, index)) ) {
|
||||
pass = false
|
||||
@@ -328,10 +347,10 @@ export class AsyncCollection<T> {
|
||||
* @param {WhereOperator} operator
|
||||
* @param [operand]
|
||||
*/
|
||||
async everyWhere<T2>(key: KeyOperator<T, T2>, operator: WhereOperator, operand?: any): Promise<boolean> {
|
||||
async everyWhere<T2>(key: KeyOperator<T, T2>, operator: WhereOperator, operand?: unknown): Promise<boolean> {
|
||||
let pass = true
|
||||
|
||||
await this._chunk(async items => {
|
||||
await this.inChunks(async items => {
|
||||
pass = pass && items.everyWhere(key, operator, operand)
|
||||
if ( !pass ) {
|
||||
throw new StopIteration()
|
||||
@@ -347,13 +366,13 @@ export class AsyncCollection<T> {
|
||||
* @return Promise<Collection>
|
||||
*/
|
||||
async filter<T2>(func: KeyFunction<T, T2>): Promise<Collection<T>> {
|
||||
let new_items: CollectionItem<T>[] = []
|
||||
let newItems: CollectionItem<T>[] = []
|
||||
|
||||
await this._chunk(async items => {
|
||||
new_items = new_items.concat(items.filter(func).all())
|
||||
await this.inChunks(async items => {
|
||||
newItems = newItems.concat(items.filter(func).all())
|
||||
})
|
||||
|
||||
return new Collection<T>(new_items)
|
||||
return new Collection<T>(newItems)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -363,7 +382,9 @@ export class AsyncCollection<T> {
|
||||
* @return AsyncCollection
|
||||
*/
|
||||
when<T2>(bool: boolean, then: AsyncCollectionFunction<T, T2>): AsyncCollection<T> {
|
||||
if ( bool ) then(this)
|
||||
if ( bool ) {
|
||||
then(this)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
@@ -374,7 +395,9 @@ export class AsyncCollection<T> {
|
||||
* @return AsyncCollection
|
||||
*/
|
||||
unless<T2>(bool: boolean, then: AsyncCollectionFunction<T, T2>): AsyncCollection<T> {
|
||||
if ( !bool ) then(this)
|
||||
if ( !bool ) {
|
||||
then(this)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
@@ -385,12 +408,12 @@ export class AsyncCollection<T> {
|
||||
* @param [operand]
|
||||
* @return Promise<Collection>
|
||||
*/
|
||||
async where<T2>(key: KeyOperator<T, T2>, operator: WhereOperator, operand?: any): Promise<Collection<T>> {
|
||||
let new_items: CollectionItem<T>[] = []
|
||||
await this._chunk(async items => {
|
||||
new_items = new_items.concat(items.where(key, operator, operand).all())
|
||||
async where<T2>(key: KeyOperator<T, T2>, operator: WhereOperator, operand?: unknown): Promise<Collection<T>> {
|
||||
let newItems: CollectionItem<T>[] = []
|
||||
await this.inChunks(async items => {
|
||||
newItems = newItems.concat(items.where(key, operator, operand).all())
|
||||
})
|
||||
return new Collection<T>(new_items)
|
||||
return new Collection<T>(newItems)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -401,12 +424,12 @@ export class AsyncCollection<T> {
|
||||
* @param [operand]
|
||||
* @return Promise<Collection>
|
||||
*/
|
||||
async whereNot<T2>(key: KeyOperator<T, T2>, operator: WhereOperator, operand?: any): Promise<Collection<T>> {
|
||||
let new_items: CollectionItem<T>[] = []
|
||||
await this._chunk(async items => {
|
||||
new_items = new_items.concat(items.whereNot(key, operator, operand).all())
|
||||
async whereNot<T2>(key: KeyOperator<T, T2>, operator: WhereOperator, operand?: unknown): Promise<Collection<T>> {
|
||||
let newItems: CollectionItem<T>[] = []
|
||||
await this.inChunks(async items => {
|
||||
newItems = newItems.concat(items.whereNot(key, operator, operand).all())
|
||||
})
|
||||
return new Collection<T>(new_items)
|
||||
return new Collection<T>(newItems)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -416,15 +439,15 @@ export class AsyncCollection<T> {
|
||||
* @return Promise<Collection>
|
||||
*/
|
||||
async whereIn<T2>(key: KeyOperator<T, T2>, items: AsyncCollectionComparable<T2>): Promise<Collection<T>> {
|
||||
let new_items: CollectionItem<T>[] = []
|
||||
await this._chunk_all_associate(key,async chunk => {
|
||||
const newItems: CollectionItem<T>[] = []
|
||||
await this.inChunksAllAssociated(key, async chunk => {
|
||||
for ( const item of chunk ) {
|
||||
if ( await items.includes(item.key) ) {
|
||||
new_items.push(item.item)
|
||||
newItems.push(item.item)
|
||||
}
|
||||
}
|
||||
})
|
||||
return new Collection<T>(new_items)
|
||||
return new Collection<T>(newItems)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -435,15 +458,15 @@ export class AsyncCollection<T> {
|
||||
* @return Promise<Collection>
|
||||
*/
|
||||
async whereNotIn<T2>(key: KeyOperator<T, T2>, items: AsyncCollectionComparable<T2>): Promise<Collection<T>> {
|
||||
let new_items: CollectionItem<T>[] = []
|
||||
await this._chunk_all_associate(key,async chunk => {
|
||||
const newItems: CollectionItem<T>[] = []
|
||||
await this.inChunksAllAssociated(key, async chunk => {
|
||||
for ( const item of chunk ) {
|
||||
if ( !(await items.includes(item.key)) ) {
|
||||
new_items.push(item.item)
|
||||
newItems.push(item.item)
|
||||
}
|
||||
}
|
||||
})
|
||||
return new Collection<T>(new_items)
|
||||
return new Collection<T>(newItems)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -451,7 +474,7 @@ export class AsyncCollection<T> {
|
||||
* @return Promise<MaybeCollectionItem>
|
||||
*/
|
||||
async first(): Promise<MaybeCollectionItem<T>> {
|
||||
return this._items.at(0)
|
||||
return this.storedItems.at(0)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -463,7 +486,7 @@ export class AsyncCollection<T> {
|
||||
*/
|
||||
async firstWhere<T2>(key: KeyOperator<T, T2>, operator: WhereOperator = '=', operand: any = true): Promise<MaybeCollectionItem<T>> {
|
||||
let item = undefined
|
||||
await this._chunk_all_associate(key, async items => {
|
||||
await this.inChunksAllAssociated(key, async items => {
|
||||
const matches = applyWhere(items, operator, operand)
|
||||
if ( matches.length > 0 ) {
|
||||
item = matches[0]
|
||||
@@ -481,7 +504,7 @@ export class AsyncCollection<T> {
|
||||
*/
|
||||
async firstWhereNot<T2>(key: KeyOperator<T, T2>, operator: WhereOperator = '=', operand: any = true): Promise<MaybeCollectionItem<T>> {
|
||||
let item: MaybeCollectionItem<T> = undefined
|
||||
await this._chunk(async items => {
|
||||
await this.inChunks(async items => {
|
||||
const matches = items.whereNot(key, operator, operand)
|
||||
if ( matches.length > 0 ) {
|
||||
item = matches.first()
|
||||
@@ -495,16 +518,16 @@ export class AsyncCollection<T> {
|
||||
* Returns the number of elements in this collection.
|
||||
* @return Promise<number>
|
||||
*/
|
||||
async count() {
|
||||
return this._items.count()
|
||||
async count(): Promise<number> {
|
||||
return this.storedItems.count()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of elements in this collection.
|
||||
* @return Promise<number>
|
||||
*/
|
||||
async length() {
|
||||
return this._items.count()
|
||||
async length(): Promise<number> {
|
||||
return this.storedItems.count()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -514,9 +537,12 @@ export class AsyncCollection<T> {
|
||||
* @param [fallback]
|
||||
* @return Promise<any>
|
||||
*/
|
||||
async get(index: number, fallback?: any) {
|
||||
if ( (await this.count()) > index ) return this._items.at(index)
|
||||
else return fallback
|
||||
async get(index: number, fallback?: T): Promise<T | undefined> {
|
||||
if ( (await this.count()) > index ) {
|
||||
return this.storedItems.at(index)
|
||||
} else {
|
||||
return fallback
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -553,13 +579,13 @@ export class AsyncCollection<T> {
|
||||
* @return Promise<string>
|
||||
*/
|
||||
async join(delimiter: string): Promise<string> {
|
||||
let running_strings: string[] = []
|
||||
const runningStrings: string[] = []
|
||||
|
||||
await this._chunk(async items => {
|
||||
running_strings.push(items.join(delimiter))
|
||||
await this.inChunks(async items => {
|
||||
runningStrings.push(items.join(delimiter))
|
||||
})
|
||||
|
||||
return running_strings.join(delimiter)
|
||||
return runningStrings.join(delimiter)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -580,7 +606,7 @@ export class AsyncCollection<T> {
|
||||
* @return Promise<boolean>
|
||||
*/
|
||||
async isEmpty(): Promise<boolean> {
|
||||
return (await this._items.count()) < 1
|
||||
return (await this.storedItems.count()) < 1
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -588,7 +614,7 @@ export class AsyncCollection<T> {
|
||||
* @return Promise<boolean>
|
||||
*/
|
||||
async isNotEmpty(): Promise<boolean> {
|
||||
return (await this._items.count()) > 0
|
||||
return (await this.storedItems.count()) > 0
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -596,8 +622,10 @@ export class AsyncCollection<T> {
|
||||
* @return Promise<MaybeCollectionItem>
|
||||
*/
|
||||
async last(): Promise<MaybeCollectionItem<T>> {
|
||||
const length = await this._items.count()
|
||||
if ( length > 0 ) return this._items.at(length - 1)
|
||||
const length = await this.storedItems.count()
|
||||
if ( length > 0 ) {
|
||||
return this.storedItems.at(length - 1)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -607,7 +635,7 @@ export class AsyncCollection<T> {
|
||||
* @param [operand]
|
||||
* @return Promise<MaybeCollectionItem>
|
||||
*/
|
||||
async lastWhere<T2>(key: KeyOperator<T, T2>, operator: WhereOperator, operand?: any): Promise<MaybeCollectionItem<T>> {
|
||||
async lastWhere<T2>(key: KeyOperator<T, T2>, operator: WhereOperator, operand?: unknown): Promise<MaybeCollectionItem<T>> {
|
||||
return (await this.where(key, operator, operand)).last()
|
||||
}
|
||||
|
||||
@@ -618,7 +646,7 @@ export class AsyncCollection<T> {
|
||||
* @param [operand]
|
||||
* @return Promise<MaybeCollectionItem>
|
||||
*/
|
||||
async lastWhereNot<T2>(key: KeyOperator<T, T2>, operator: WhereOperator, operand?: any): Promise<MaybeCollectionItem<T>> {
|
||||
async lastWhereNot<T2>(key: KeyOperator<T, T2>, operator: WhereOperator, operand?: unknown): Promise<MaybeCollectionItem<T>> {
|
||||
return (await this.whereNot(key, operator, operand)).last()
|
||||
}
|
||||
|
||||
@@ -631,13 +659,13 @@ export class AsyncCollection<T> {
|
||||
* @return Promise<Collection>
|
||||
*/
|
||||
async pluck<T2>(key: KeyOperator<T, T2>): Promise<Collection<T2>> {
|
||||
let new_items: CollectionItem<T2>[] = []
|
||||
let newItems: CollectionItem<T2>[] = []
|
||||
|
||||
await this._chunk_all(key, async items => {
|
||||
new_items = new_items.concat(items.all())
|
||||
await this.inChunksAll(key, async items => {
|
||||
newItems = newItems.concat(items.all())
|
||||
})
|
||||
|
||||
return new Collection<T2>(new_items)
|
||||
return new Collection<T2>(newItems)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -645,17 +673,19 @@ export class AsyncCollection<T> {
|
||||
* @param {KeyOperator} key
|
||||
* @return Promise<number>
|
||||
*/
|
||||
async max<T2>(key: KeyOperator<T, T2>): Promise<number> {
|
||||
let running_max: number
|
||||
async max<T2>(key: KeyOperator<T, T2>): Promise<number | undefined> {
|
||||
let runningMax: number | undefined = undefined
|
||||
|
||||
await this._chunk_all_numbers(key, async items => {
|
||||
const local_max = Math.max(...items)
|
||||
if ( typeof running_max === 'undefined' ) running_max = local_max
|
||||
else running_max = Math.max(running_max, local_max)
|
||||
await this.inChunksAllNumbers(key, async items => {
|
||||
const localMax = Math.max(...items)
|
||||
if ( typeof runningMax === 'undefined' ) {
|
||||
runningMax = localMax
|
||||
} else {
|
||||
runningMax = Math.max(runningMax, localMax)
|
||||
}
|
||||
})
|
||||
|
||||
// @ts-ignore
|
||||
return running_max
|
||||
return runningMax
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -672,17 +702,19 @@ export class AsyncCollection<T> {
|
||||
* @param {KeyOperator} key
|
||||
* @return Promise<number>
|
||||
*/
|
||||
async min<T2>(key: KeyOperator<T, T2>): Promise<number> {
|
||||
let running_min: number
|
||||
async min<T2>(key: KeyOperator<T, T2>): Promise<number | undefined> {
|
||||
let runningMin: number | undefined = undefined
|
||||
|
||||
await this._chunk_all_numbers(key, async items => {
|
||||
const local_min = Math.min(...items)
|
||||
if ( typeof running_min === 'undefined' ) running_min = local_min
|
||||
else running_min = Math.min(running_min, local_min)
|
||||
await this.inChunksAllNumbers(key, async items => {
|
||||
const localMin = Math.min(...items)
|
||||
if ( typeof runningMin === 'undefined' ) {
|
||||
runningMin = localMin
|
||||
} else {
|
||||
runningMin = Math.min(runningMin, localMin)
|
||||
}
|
||||
})
|
||||
|
||||
// @ts-ignore
|
||||
return running_min
|
||||
return runningMin
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -696,16 +728,19 @@ export class AsyncCollection<T> {
|
||||
|
||||
/**
|
||||
* Merge the two collections.
|
||||
* @param {AsyncCollectionComparable} merge_with
|
||||
* @param {AsyncCollectionComparable} mergeWith
|
||||
* @return Promise<Collection>
|
||||
*/
|
||||
async merge<T2>(merge_with: AsyncCollectionComparable<T2>): Promise<Collection<T|T2>> {
|
||||
let items: T2[]
|
||||
if ( merge_with instanceof Collection ) items = await merge_with.all()
|
||||
else if ( merge_with instanceof AsyncCollection ) items = await merge_with.all()
|
||||
else if ( Array.isArray(merge_with) ) items = merge_with
|
||||
async merge<T2>(mergeWith: AsyncCollectionComparable<T2>): Promise<Collection<T|T2>> {
|
||||
let items: T2[] = []
|
||||
if ( mergeWith instanceof Collection ) {
|
||||
items = await mergeWith.all()
|
||||
} else if ( mergeWith instanceof AsyncCollection ) {
|
||||
items = await mergeWith.all()
|
||||
} else if ( Array.isArray(mergeWith) ) {
|
||||
items = mergeWith
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
return new Collection<T|T2>([...items, ...await this.all()])
|
||||
}
|
||||
|
||||
@@ -718,11 +753,15 @@ export class AsyncCollection<T> {
|
||||
const matches: CollectionItem<T>[] = []
|
||||
let current = 1
|
||||
|
||||
await this._chunk(async chunk => {
|
||||
await this.inChunks(async chunk => {
|
||||
for ( const item of chunk.all() ) {
|
||||
if ( current === 1 ) matches.push(item)
|
||||
if ( current === 1 ) {
|
||||
matches.push(item)
|
||||
}
|
||||
current += 1
|
||||
if ( current > n ) current = 1
|
||||
if ( current > n ) {
|
||||
current = 1
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -732,12 +771,12 @@ export class AsyncCollection<T> {
|
||||
/**
|
||||
* Return a collection containing the items that would be on the given page, with the given number of items per page.
|
||||
* @param {number} page
|
||||
* @param {number} per_page
|
||||
* @param {number} perPage
|
||||
*/
|
||||
async forPage(page: number, per_page: number): Promise<Collection<T>> {
|
||||
const start = page * per_page - per_page
|
||||
const end = page * per_page - 1
|
||||
return this._items.range(start, end)
|
||||
async forPage(page: number, perPage: number): Promise<Collection<T>> {
|
||||
const start = page * perPage - perPage
|
||||
const end = page * perPage - 1
|
||||
return this.storedItems.range(start, end)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -748,10 +787,10 @@ export class AsyncCollection<T> {
|
||||
return func(this)
|
||||
}
|
||||
|
||||
/*async pop(): Promise<MaybeCollectionItem<T>> {
|
||||
const next_item = await this._items.next()
|
||||
if ( !next_item.done ) {
|
||||
return next_item.value
|
||||
/* async pop(): Promise<MaybeCollectionItem<T>> {
|
||||
const nextItem = await this.storedItems.next()
|
||||
if ( !nextItem.done ) {
|
||||
return nextItem.value
|
||||
}
|
||||
}*/ // TODO Fix this
|
||||
|
||||
@@ -762,57 +801,60 @@ export class AsyncCollection<T> {
|
||||
* @return Promise<Collection>
|
||||
*/
|
||||
async random(n: number): Promise<Collection<T>> {
|
||||
const random_items: CollectionItem<T>[] = []
|
||||
const fetched_indices: number[] = []
|
||||
const randomItems: CollectionItem<T>[] = []
|
||||
const fetchedIndices: number[] = []
|
||||
|
||||
const max_n = await this._items.count()
|
||||
if ( n > max_n ) n = max_n
|
||||
const maxN = await this.storedItems.count()
|
||||
if ( n > maxN ) {
|
||||
n = maxN
|
||||
}
|
||||
|
||||
while ( random_items.length < n ) {
|
||||
const index = Math.floor(Math.random() * max_n)
|
||||
while ( randomItems.length < n ) {
|
||||
const index = Math.floor(Math.random() * maxN)
|
||||
|
||||
if ( !fetched_indices.includes(index) ) {
|
||||
fetched_indices.push(index)
|
||||
const item = await this._items.at(index)
|
||||
if ( typeof item !== 'undefined' )
|
||||
random_items.push(item)
|
||||
if ( !fetchedIndices.includes(index) ) {
|
||||
fetchedIndices.push(index)
|
||||
const item = await this.storedItems.at(index)
|
||||
if ( typeof item !== 'undefined' ) {
|
||||
randomItems.push(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Collection<T>(random_items)
|
||||
return new Collection<T>(randomItems)
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapse the collection into a single value using a reducer function.
|
||||
* @param {KeyReducerFunction} reducer
|
||||
* @param [initial_value]
|
||||
* @param [initialValue]
|
||||
* @return Promise<any>
|
||||
*/
|
||||
async reduce<T2>(reducer: KeyReducerFunction<T, T2>, initial_value?: T2): Promise<T2 | undefined> {
|
||||
let current_value = initial_value
|
||||
async reduce<T2>(reducer: KeyReducerFunction<T, T2>, initialValue?: T2): Promise<T2 | undefined> {
|
||||
let currentValue = initialValue
|
||||
let index = 0
|
||||
|
||||
await this._chunk(async items => {
|
||||
await this.inChunks(async items => {
|
||||
for ( const item of items.all() ) {
|
||||
current_value = reducer(current_value, item, index)
|
||||
currentValue = reducer(currentValue, item, index)
|
||||
index += 1
|
||||
}
|
||||
})
|
||||
|
||||
return current_value
|
||||
return currentValue
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a collection of items that fail the truth test.
|
||||
* @param {AsyncKeyFunction} truth_test
|
||||
* @param {AsyncKeyFunction} truthTestFunction
|
||||
* @return Promise<Collection>
|
||||
*/
|
||||
async reject<T2>(truth_test: AsyncKeyFunction<T, T2>): Promise<Collection<T>> {
|
||||
async reject<T2>(truthTestFunction: AsyncKeyFunction<T, T2>): Promise<Collection<T>> {
|
||||
let rejected: CollectionItem<T>[] = []
|
||||
|
||||
await this._chunk(async items => {
|
||||
await this.inChunks(async items => {
|
||||
rejected = rejected.concat(items.all().filter((item, index) => {
|
||||
return !truth_test(item, index)
|
||||
return !truthTestFunction(item, index)
|
||||
}))
|
||||
})
|
||||
|
||||
@@ -833,13 +875,13 @@ export class AsyncCollection<T> {
|
||||
* @return Promise<MaybeCollectionIndex>
|
||||
*/
|
||||
async search(item: CollectionItem<T>): Promise<MaybeCollectionIndex> {
|
||||
let found_index
|
||||
let foundIndex
|
||||
let index = 0
|
||||
|
||||
await this._chunk(async items => {
|
||||
items.some(possible_item => {
|
||||
if ( possible_item === item ) {
|
||||
found_index = index
|
||||
await this.inChunks(async items => {
|
||||
items.some(possibleItem => {
|
||||
if ( possibleItem === item ) {
|
||||
foundIndex = index
|
||||
throw new StopIteration()
|
||||
}
|
||||
|
||||
@@ -848,7 +890,7 @@ export class AsyncCollection<T> {
|
||||
})
|
||||
})
|
||||
|
||||
return found_index
|
||||
return foundIndex
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -856,9 +898,9 @@ export class AsyncCollection<T> {
|
||||
* @return Promise<MaybeCollectionItem>
|
||||
*/
|
||||
async shift(): Promise<MaybeCollectionItem<T>> {
|
||||
const next_item = await this._items.next()
|
||||
if ( !next_item.done ) {
|
||||
return next_item.value
|
||||
const nextItem = await this.storedItems.next()
|
||||
if ( !nextItem.done ) {
|
||||
return nextItem.value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -877,16 +919,16 @@ export class AsyncCollection<T> {
|
||||
* @return Promise<Collection>
|
||||
*/
|
||||
async slice(start: number, end: number): Promise<Collection<T>> {
|
||||
return this._items.range(start, end - 1)
|
||||
return this.storedItems.range(start, end - 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the collection, optionally with the given comparison function.
|
||||
* @param {ComparisonFunction} compare_func
|
||||
* @param {ComparisonFunction} comparisonFunction
|
||||
* @return Promise<Collection>
|
||||
*/
|
||||
async sort(compare_func?: ComparisonFunction<T>): Promise<Collection<T>> {
|
||||
return (await this.collect()).sort(compare_func)
|
||||
async sort(comparisonFunction?: ComparisonFunction<T>): Promise<Collection<T>> {
|
||||
return (await this.collect()).sort(comparisonFunction)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -900,11 +942,11 @@ export class AsyncCollection<T> {
|
||||
|
||||
/**
|
||||
* Reverse sort the collection, optionally with the given comparison function.
|
||||
* @param {ComparisonFunction} compare_func
|
||||
* @param {ComparisonFunction} comparisonFunction
|
||||
* @return Promise<Collection>
|
||||
*/
|
||||
async sortDesc(compare_func?: ComparisonFunction<T>): Promise<Collection<T>> {
|
||||
return (await this.collect()).sortDesc(compare_func)
|
||||
async sortDesc(comparisonFunction?: ComparisonFunction<T>): Promise<Collection<T>> {
|
||||
return (await this.collect()).sortDesc(comparisonFunction)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -932,20 +974,23 @@ export class AsyncCollection<T> {
|
||||
* @return Promise<number>
|
||||
*/
|
||||
async sum<T2>(key?: KeyOperator<T, T2>): Promise<number> {
|
||||
let running_sum: number = 0
|
||||
let runningSum = 0
|
||||
|
||||
const chunk_handler = (items: number[]) => {
|
||||
const chunkHandler = (items: number[]) => {
|
||||
for ( const item of items ) {
|
||||
running_sum += item
|
||||
runningSum += item
|
||||
}
|
||||
}
|
||||
|
||||
if ( key ) await this._chunk_all_numbers(key, chunk_handler)
|
||||
else await this._chunk(async chunk => {
|
||||
chunk_handler(chunk.map(x => Number(x)).all())
|
||||
})
|
||||
if ( key ) {
|
||||
await this.inChunksAllNumbers(key, chunkHandler)
|
||||
} else {
|
||||
await this.inChunks(async chunk => {
|
||||
chunkHandler(chunk.map(x => Number(x)).all())
|
||||
})
|
||||
}
|
||||
|
||||
return running_sum
|
||||
return runningSum
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -954,12 +999,13 @@ export class AsyncCollection<T> {
|
||||
* @return Promise<Collection>
|
||||
*/
|
||||
async take(limit: number): Promise<Collection<T>> {
|
||||
if ( limit === 0 ) return new Collection<T>()
|
||||
else if ( limit > 0 ) {
|
||||
if ( limit === 0 ) {
|
||||
return new Collection<T>()
|
||||
} else if ( limit > 0 ) {
|
||||
return this.slice(0, limit)
|
||||
} else {
|
||||
const cnt = await this._items.count()
|
||||
return this._items.range(cnt - (-1 * limit), cnt - 1)
|
||||
const cnt = await this.storedItems.count()
|
||||
return this.storedItems.range(cnt - (-1 * limit), cnt - 1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -982,15 +1028,19 @@ export class AsyncCollection<T> {
|
||||
const has: CollectionItem<T|T2>[] = []
|
||||
|
||||
if ( !key ) {
|
||||
await this._chunk(async items => {
|
||||
await this.inChunks(async items => {
|
||||
for ( const item of items.all() ) {
|
||||
if ( !has.includes(item) ) has.push(item)
|
||||
if ( !has.includes(item) ) {
|
||||
has.push(item)
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
await this._chunk_all(key, async items => {
|
||||
await this.inChunksAll(key, async items => {
|
||||
for ( const item of items.all() ) {
|
||||
if ( !has.includes(item) ) has.push(item)
|
||||
if ( !has.includes(item) ) {
|
||||
has.push(item)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1005,9 +1055,13 @@ export class AsyncCollection<T> {
|
||||
async toArray(): Promise<any[]> {
|
||||
const returns: any = []
|
||||
for ( const item of (await this.all()) ) {
|
||||
if ( item instanceof Collection ) returns.push(item.toArray())
|
||||
else if ( item instanceof AsyncCollection ) returns.push(await item.toArray())
|
||||
else returns.push(item)
|
||||
if ( item instanceof Collection ) {
|
||||
returns.push(item.toArray())
|
||||
} else if ( item instanceof AsyncCollection ) {
|
||||
returns.push(await item.toArray())
|
||||
} else {
|
||||
returns.push(item)
|
||||
}
|
||||
}
|
||||
return returns
|
||||
}
|
||||
@@ -1025,7 +1079,7 @@ export class AsyncCollection<T> {
|
||||
* Get a clone of the underlying iterator of this collection.
|
||||
* @return Iterable
|
||||
*/
|
||||
iterator() {
|
||||
return this._items.clone()
|
||||
iterator(): Iterable<T> {
|
||||
return this.storedItems.clone()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user