Import other modules into monorepo
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
33
src/util/collection/ArrayIterable.ts
Normal file
33
src/util/collection/ArrayIterable.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { Iterable } from './Iterable'
|
||||
import { collect } from './Collection'
|
||||
|
||||
/**
|
||||
* A basic Iterable implementation that uses an array as a backend.
|
||||
* @extends Iterable
|
||||
*/
|
||||
export class ArrayIterable<T> extends Iterable<T> {
|
||||
constructor(
|
||||
/**
|
||||
* Items to use for this iterable.
|
||||
*/
|
||||
protected items: T[],
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async at(i: number) {
|
||||
return this.items[i]
|
||||
}
|
||||
|
||||
async range(start: number, end: number) {
|
||||
return collect(this.items.slice(start, end + 1))
|
||||
}
|
||||
|
||||
async count() {
|
||||
return this.items.length
|
||||
}
|
||||
|
||||
clone() {
|
||||
return new ArrayIterable([...this.items])
|
||||
}
|
||||
}
|
||||
1031
src/util/collection/AsyncCollection.ts
Normal file
1031
src/util/collection/AsyncCollection.ts
Normal file
File diff suppressed because it is too large
Load Diff
1115
src/util/collection/Collection.ts
Normal file
1115
src/util/collection/Collection.ts
Normal file
File diff suppressed because it is too large
Load Diff
119
src/util/collection/Iterable.ts
Normal file
119
src/util/collection/Iterable.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
import {Collection} from './Collection'
|
||||
|
||||
export type MaybeIterationItem<T> = { done: boolean, value?: T }
|
||||
export type ChunkCallback<T> = (items: Collection<T>) => any
|
||||
|
||||
export class StopIteration extends Error {}
|
||||
|
||||
/**
|
||||
* Abstract class representing an iterable, lazy-loaded dataset.
|
||||
* @abstract
|
||||
*/
|
||||
export abstract class Iterable<T> {
|
||||
/**
|
||||
* The current index of the iterable.
|
||||
* @type number
|
||||
*/
|
||||
protected index = 0
|
||||
|
||||
/**
|
||||
* Get the item of this iterable at the given index, if one exists.
|
||||
* @param {number} i
|
||||
* @return Promise<any|undefined>
|
||||
*/
|
||||
abstract at(i: number): Promise<T | undefined>
|
||||
|
||||
/**
|
||||
* Get the collection of items in the given range of this iterable.
|
||||
* @param {number} start
|
||||
* @param {number} end
|
||||
* @return Promise<Collection>
|
||||
*/
|
||||
abstract range(start: number, end: number): Promise<Collection<T>>
|
||||
|
||||
/**
|
||||
* Count the number of items in this collection.
|
||||
* @return Promise<number>
|
||||
*/
|
||||
abstract count(): Promise<number>
|
||||
|
||||
/**
|
||||
* Get a copy of this iterable.
|
||||
* @return Iterable
|
||||
*/
|
||||
abstract clone(): Iterable<T>
|
||||
|
||||
/**
|
||||
* Return a collection of all items in this iterable.
|
||||
* @return Promise<Collection>
|
||||
*/
|
||||
public async all(): Promise<Collection<T>> {
|
||||
return this.range(0, (await this.count()) + 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Advance to the next value of this iterable.
|
||||
* @return Promise<MaybeIterationItem>
|
||||
*/
|
||||
public async next(): Promise<MaybeIterationItem<T>> {
|
||||
const i = this.index
|
||||
|
||||
if ( i >= await this.count() ) {
|
||||
return { done: true }
|
||||
}
|
||||
|
||||
this.index = i + 1
|
||||
return { done: false, value: await this.at(i) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Chunk the iterable into the given size and call the callback passing the chunk along.
|
||||
* @param {number} size
|
||||
* @param {ChunkCallback} callback
|
||||
* @return Promise<void>
|
||||
*/
|
||||
public async chunk(size: number, callback: ChunkCallback<T>) {
|
||||
const total = await this.count()
|
||||
|
||||
while ( this.index < total ) {
|
||||
const items = await this.range(this.index, this.index + size - 1)
|
||||
|
||||
try {
|
||||
await callback(items)
|
||||
} catch ( error ) {
|
||||
if ( error instanceof StopIteration ) break
|
||||
else throw error
|
||||
}
|
||||
|
||||
this.index += size
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Advance the iterable to the given index.
|
||||
* @param {number} index
|
||||
* @return Promise<void>
|
||||
*/
|
||||
public async seek(index: number) {
|
||||
if ( index < 0 ) throw new TypeError('Cannot seek to negative index.')
|
||||
else if ( index >= await this.count() ) throw new TypeError('Cannot seek past last item.')
|
||||
this.index = index
|
||||
}
|
||||
|
||||
/**
|
||||
* Peek at the next value of the iterable, without advancing.
|
||||
* @return Promise<any|undefined>
|
||||
*/
|
||||
public async peek(): Promise<T | undefined> {
|
||||
if ( this.index + 1 >= await this.count() ) return undefined
|
||||
else return this.at(this.index + 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the iterable to the first index.
|
||||
* @return Promise<any>
|
||||
*/
|
||||
public async reset() {
|
||||
this.index = 0
|
||||
}
|
||||
}
|
||||
86
src/util/collection/where.ts
Normal file
86
src/util/collection/where.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* Type representing a valid where operator.
|
||||
*/
|
||||
type WhereOperator = '&' | '>' | '>=' | '<' | '<=' | '!=' | '<=>' | '%' | '|' | '!' | '~' | '=' | '^'
|
||||
|
||||
/**
|
||||
* Type associating search items with a key.
|
||||
*/
|
||||
type AssociatedSearchItem = { key: any, item: any }
|
||||
|
||||
/**
|
||||
* Type representing the result of a where.
|
||||
*/
|
||||
type WhereResult = any[]
|
||||
|
||||
/**
|
||||
* Returns true if the given item satisfies the given where clause.
|
||||
* @param {AssociatedSearchItem} item
|
||||
* @param {WhereOperator} operator
|
||||
* @param [operand]
|
||||
* @return boolean
|
||||
*/
|
||||
const whereMatch = (item: AssociatedSearchItem, operator: WhereOperator, operand?: any): boolean => {
|
||||
switch ( operator ) {
|
||||
case '&':
|
||||
if ( item.key & operand ) return true
|
||||
break
|
||||
case '>':
|
||||
if ( item.key > operand ) return true
|
||||
break
|
||||
case '>=':
|
||||
if ( item.key >= operand ) return true
|
||||
break
|
||||
case '<':
|
||||
if ( item.key < operand ) return true
|
||||
break
|
||||
case '<=':
|
||||
if ( item.key <= operand ) return true
|
||||
break
|
||||
case '!=':
|
||||
if ( item.key !== operand ) return true
|
||||
break
|
||||
case '<=>':
|
||||
if ( item.key === operand && typeof item.key !== 'undefined' && item.key !== null )
|
||||
return true
|
||||
break
|
||||
case '%':
|
||||
if ( item.key % operand ) return true
|
||||
break
|
||||
case '|':
|
||||
if ( item.key | operand ) return true
|
||||
break
|
||||
case '!':
|
||||
if ( !item.key ) return true
|
||||
break
|
||||
case '~':
|
||||
if ( ~item.key ) return true
|
||||
break
|
||||
case '=':
|
||||
if ( item.key === operand ) return true
|
||||
break
|
||||
case '^':
|
||||
if ( item.key ^ operand ) return true
|
||||
break
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the given where clause to the items and return those that match.
|
||||
* @param {Array<AssociatedSearchItem>} items
|
||||
* @param {WhereOperator} operator
|
||||
* @param [operand]
|
||||
*/
|
||||
const applyWhere = (items: AssociatedSearchItem[], operator: WhereOperator, operand?: any): WhereResult => {
|
||||
const matches: WhereResult = []
|
||||
for ( const item of items ) {
|
||||
if ( whereMatch(item, operator, operand) )
|
||||
matches.push(item.item)
|
||||
}
|
||||
|
||||
return matches
|
||||
}
|
||||
|
||||
export { WhereOperator, WhereResult, AssociatedSearchItem, applyWhere, whereMatch }
|
||||
Reference in New Issue
Block a user