@heinlein-video/rrule
Version:
rrule fork. Includes the src/ folder for typescript sourceMaps
107 lines (95 loc) • 3.12 kB
text/typescript
import IterResult, { IterArgs } from './iterresult'
import { clone, cloneDates } from './dateutil'
import { isArray } from './helpers'
export type CacheKeys = 'before' | 'after' | 'between'
function argsMatch(
left: IterArgs[keyof IterArgs] | undefined,
right: IterArgs[keyof IterArgs] | undefined
) {
if (Array.isArray(left)) {
if (!Array.isArray(right)) return false
if (left.length !== right.length) return false
return left.every((date, i) => date.getTime() === right[i].getTime())
}
if (left instanceof Date) {
return right instanceof Date && left.getTime() === right.getTime()
}
return left === right
}
export class Cache {
all: Date[] | Partial<IterArgs> | false = false
before: IterArgs[] = []
after: IterArgs[] = []
between: IterArgs[] = []
/**
* @param {String} what - all/before/after/between
* @param {Array,Date} value - an array of dates, one date, or null
* @param {Object?} args - _iter arguments
*/
public _cacheAdd(
what: CacheKeys | 'all',
value: Date[] | Date | null,
args?: Partial<IterArgs>
) {
if (value) {
value = value instanceof Date ? clone(value) : cloneDates(value)
}
if (what === 'all') {
this.all = value as Date[]
} else {
args._value = value
this[what].push(args as IterArgs)
}
}
/**
* @return false - not in the cache
* @return null - cached, but zero occurrences (before/after)
* @return Date - cached (before/after)
* @return [] - cached, but zero occurrences (all/between)
* @return [Date1, DateN] - cached (all/between)
*/
public _cacheGet(
what: CacheKeys | 'all',
args?: Partial<IterArgs>
): Date | Date[] | false | null {
let cached: Date | Date[] | false | null = false
const argsKeys = args ? (Object.keys(args) as (keyof IterArgs)[]) : []
const findCacheDiff = function (item: IterArgs) {
for (let i = 0; i < argsKeys.length; i++) {
const key = argsKeys[i]
if (!argsMatch(args[key], item[key])) {
return true
}
}
return false
}
const cachedObject = this[what]
if (what === 'all') {
cached = this.all as Date[]
} else if (isArray(cachedObject)) {
// Let's see whether we've already called the
// 'what' method with the same 'args'
for (let i = 0; i < cachedObject.length; i++) {
const item = cachedObject[i] as IterArgs
if (argsKeys.length && findCacheDiff(item)) continue
cached = item._value
break
}
}
if (!cached && this.all) {
// Not in the cache, but we already know all the occurrences,
// so we can find the correct dates from the cached ones.
const iterResult = new IterResult(what, args)
for (let i = 0; i < (this.all as Date[]).length; i++) {
if (!iterResult.accept((this.all as Date[])[i])) break
}
cached = iterResult.getValue() as Date
this._cacheAdd(what, cached, args)
}
return isArray(cached)
? cloneDates(cached)
: cached instanceof Date
? clone(cached)
: cached
}
}