Finish fleshing out Model; refactor mixin types; TRUNCATE

This commit is contained in:
garrettmills
2020-07-19 14:13:48 -05:00
parent e4f5da7ac6
commit b915fcedf9
30 changed files with 832 additions and 131 deletions

View File

@@ -496,7 +496,9 @@ export class AsyncCollection<T> {
if ( !fetched_indices.includes(index) ) {
fetched_indices.push(index)
random_items.push(await this._items.at_index(index))
const item = await this._items.at_index(index)
if ( typeof item !== 'undefined' )
random_items.push(item)
}
}

View File

@@ -8,7 +8,7 @@ export class StopIteration extends Error {}
export abstract class Iterable<T> {
protected index = 0
abstract async at_index(i: number): Promise<T>
abstract async at_index(i: number): Promise<T | undefined>
abstract async from_range(start: number, end: number): Promise<Collection<T>>
abstract async count(): Promise<number>
abstract clone(): Iterable<T>

View File

@@ -29,17 +29,17 @@ export default abstract class Logger {
case LoggingLevel.Success:
return green('success')
case LoggingLevel.Error:
return red('error')
return red(' error')
case LoggingLevel.Warning:
return yellow('warning')
case LoggingLevel.Info:
return blue('info')
return blue(' info')
case LoggingLevel.Debug:
return cyan('debug')
return cyan(' debug')
case LoggingLevel.Verbose:
return gray('verbose')
case LoggingLevel.Silent:
return gray('silent')
return gray(' silent')
}
}
}

View File

@@ -59,6 +59,7 @@ class Logging {
level,
output,
date: new Date,
caller_name: this.get_caller_info(),
}
}
@@ -73,6 +74,14 @@ class Logging {
public remove_logger(logger_class: typeof Logger) {
this._loggers = this._loggers.filter(x => !(x instanceof logger_class))
}
protected get_caller_info(level = 5): string {
let e = new Error
if ( !e.stack ) return 'Unknown'
return e.stack.split(' at ')
.slice(level)
.map((x: string): string => x.trim().split(' (')[0].split('.')[0].split(':')[0])[0]
}
}
export { Logging }

View File

@@ -1,11 +1,11 @@
import AbstractLogger from './Logger.ts'
import { LogMessage } from './types.ts'
import { gray } from '../../external/std.ts'
import { gray, cyan } from '../../external/std.ts'
export default class StandardLogger extends AbstractLogger {
public async write(message: LogMessage): Promise<void> {
const prefix = this.level_display(message.level)
const text = `${prefix} ${gray(this.format_date(message.date))}`
const text = `${prefix} ${gray(this.format_date(message.date))} (${cyan(message.caller_name || 'Unknown')})`
console.log(text, message.output)
}
}

View File

@@ -24,6 +24,7 @@ interface LogMessage {
level: LoggingLevel,
date: Date,
output: any,
caller_name: string,
}
const isLogMessage = (something: any): something is LogMessage => {

View File

@@ -0,0 +1,115 @@
export class UnsubscribeError extends Error {}
export class CompletedObservableError extends Error {
constructor() {
super('This observable can no longer be pushed to, as it has been completed.')
}
}
export type SubscriberFunction<T> = (val: T) => any
export type SubscriberErrorFunction = (error: Error) => any
export type SubscriberCompleteFunction<T> = (val?: T) => any
export type ComplexSubscriber<T> = {
next?: SubscriberFunction<T>,
error?: SubscriberErrorFunction,
complete?: SubscriberCompleteFunction<T>,
}
export type Subscription<T> = SubscriberFunction<T> | ComplexSubscriber<T>
export type Unsubscribe = { unsubscribe: () => void }
export class BehaviorSubject<T> {
protected subscribers: ComplexSubscriber<T>[] = []
protected _is_complete: boolean = false
protected _value?: T
protected _has_push: boolean = false
public subscribe(subscriber: Subscription<T>): Unsubscribe {
if ( typeof subscriber === 'function' ) {
this.subscribers.push({ next: subscriber })
} else {
this.subscribers.push(subscriber)
}
return {
unsubscribe: () => {
this.subscribers = this.subscribers.filter(x => x !== subscriber)
}
}
}
public to_promise(): Promise<T> {
return new Promise((resolve, reject) => {
const { unsubscribe } = this.subscribe({
next: (val: T) => {
resolve(val)
unsubscribe()
},
error: (error: Error) => {
reject(error)
unsubscribe()
},
complete: (val?: T) => {
resolve(val)
unsubscribe()
}
})
})
}
public async next(val: T): Promise<void> {
if ( this._is_complete ) throw new CompletedObservableError()
this._value = val
this._has_push = true
for ( const subscriber of this.subscribers ) {
if ( subscriber.next ) {
try {
await subscriber.next(val)
} catch (e) {
if ( e instanceof UnsubscribeError ) {
this.subscribers = this.subscribers.filter(x => x !== subscriber)
} else if (subscriber.error) {
await subscriber.error(e)
} else {
throw e
}
}
}
}
}
public async push(vals: T[]): Promise<void> {
if ( this._is_complete ) throw new CompletedObservableError()
await Promise.all(vals.map(val => this.next(val)))
}
public async complete(final_val?: T): Promise<void> {
if ( this._is_complete ) throw new CompletedObservableError()
if ( typeof final_val === 'undefined' ) final_val = this.value()
else this._value = final_val
for ( const subscriber of this.subscribers ) {
if ( subscriber.complete ) {
try {
await subscriber.complete(final_val)
} catch (e) {
if ( subscriber.error ) {
await subscriber.error(e)
} else {
throw e
}
}
}
}
this._is_complete = true
}
public value(): T | undefined {
return this._value
}
public is_complete(): boolean {
return this._is_complete
}
}

View File

@@ -7,3 +7,5 @@ export function applyMixins(derivedCtor: any, baseCtors: any[]) {
})
})
}
export type Constructor<T = {}> = new (...args: any[]) => T