mirror of
https://github.com/koush/scrypted.git
synced 2026-02-10 09:12:03 +00:00
297 lines
9.9 KiB
TypeScript
297 lines
9.9 KiB
TypeScript
// Type definitions for abstract-leveldown 5.0
|
|
// Project: https://github.com/Level/abstract-leveldown
|
|
// Definitions by: Meirion Hughes <https://github.com/MeirionHughes>
|
|
// Daniel Byrne <https://github.com/danwbyrne>
|
|
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
|
// TypeScript Version: 2.3
|
|
|
|
export interface AbstractOptions {
|
|
// wtf is this?
|
|
readonly [k: string]: any;
|
|
}
|
|
|
|
export type ErrorCallback = (err: Error | undefined) => void;
|
|
export type ErrorValueCallback<V> = (err: Error | undefined, value: V) => void;
|
|
export type ErrorKeyValueCallback<K, V> = (err: Error | undefined, key: K, value: V) => void;
|
|
|
|
export interface AbstractOpenOptions extends AbstractOptions {
|
|
createIfMissing?: boolean;
|
|
errorIfExists?: boolean;
|
|
}
|
|
|
|
export interface AbstractGetOptions extends AbstractOptions {
|
|
asBuffer?: boolean;
|
|
}
|
|
|
|
export interface LevelDocument {
|
|
_id?: any;
|
|
_documentType?: string;
|
|
}
|
|
|
|
export interface LevelDocumentConstructor<T extends LevelDocument> {
|
|
new(): T;
|
|
}
|
|
|
|
export interface AbstractLevelDOWN<K = any, V = any> /* extends AbstractOptions */ {
|
|
open(cb?: ErrorCallback): Promise<void>;
|
|
open(options: AbstractOpenOptions, cb?: ErrorCallback): Promise<void>;
|
|
|
|
close(cb?: ErrorCallback): void;
|
|
|
|
get(key: K, cb?: ErrorValueCallback<V>): Promise<V>;
|
|
get(key: K, options: AbstractGetOptions, cb?: ErrorValueCallback<V>): Promise<V>;
|
|
|
|
put(key: K, value: V, cb?: ErrorCallback): Promise<void>;
|
|
put(key: K, value: V, options: AbstractOptions, cb?: ErrorCallback): Promise<void>;
|
|
|
|
del(key: K, cb?: ErrorCallback): Promise<void>;
|
|
del(key: K, options: AbstractOptions, cb?: ErrorCallback): Promise<void>;
|
|
|
|
batch(): AbstractChainedBatch<K, V>;
|
|
batch(array: ReadonlyArray<AbstractBatch<K, V>>, cb?: ErrorCallback): AbstractChainedBatch<K, V>;
|
|
batch(
|
|
array: ReadonlyArray<AbstractBatch<K, V>>,
|
|
options: AbstractOptions,
|
|
cb?: ErrorCallback,
|
|
): AbstractChainedBatch<K, V>;
|
|
|
|
iterator(options?: AbstractIteratorOptions<K>): AbstractIterator<K, V>;
|
|
|
|
[Symbol.asyncIterator](): AsyncIterator<{ key: K, value: V }>;
|
|
nextId(): number;
|
|
tryGet<T extends LevelDocument>(documentConstructor: LevelDocumentConstructor<T>, _id: any, options?: AbstractGetOptions): Promise<T | undefined>;
|
|
getAll<T extends LevelDocument>(documentConstructor: LevelDocumentConstructor<T>, options?: AbstractGetOptions): AsyncIterable<T>;
|
|
upsert<T extends LevelDocument>(value: T, options?: AbstractOptions): Promise<T>;
|
|
remove<T extends LevelDocument>(value: T): Promise<void>;
|
|
removeId<T extends LevelDocument>(documentConstructor: LevelDocumentConstructor<T>, _id: any): Promise<void>;
|
|
removeAll<T extends LevelDocument>(documentConstructor: LevelDocumentConstructor<T>): Promise<void>;
|
|
getCount<T extends LevelDocument>(documentConstructor: LevelDocumentConstructor<T>, options?: AbstractGetOptions): Promise<number>;
|
|
}
|
|
|
|
export interface AbstractLevelDOWNConstructor {
|
|
// tslint:disable-next-line no-unnecessary-generics
|
|
new <K = any, V = any>(location: string): AbstractLevelDOWN<K, V>;
|
|
// tslint:disable-next-line no-unnecessary-generics
|
|
<K = any, V = any>(location: string): AbstractLevelDOWN<K, V>;
|
|
}
|
|
|
|
export interface AbstractIteratorOptions<K = any> extends AbstractOptions {
|
|
gt?: K;
|
|
gte?: K;
|
|
lt?: K;
|
|
lte?: K;
|
|
reverse?: boolean;
|
|
limit?: number;
|
|
keys?: boolean;
|
|
values?: boolean;
|
|
keyAsBuffer?: boolean;
|
|
valueAsBuffer?: boolean;
|
|
}
|
|
|
|
export type AbstractBatch<K = any, V = any> = PutBatch<K, V> | DelBatch<K, V>;
|
|
|
|
export interface PutBatch<K = any, V = any> {
|
|
readonly type: 'put';
|
|
readonly key: K;
|
|
readonly value: V;
|
|
}
|
|
|
|
export interface DelBatch<K = any, V = any> {
|
|
readonly type: 'del';
|
|
readonly key: K;
|
|
}
|
|
|
|
export interface AbstractChainedBatch<K = any, V = any> extends AbstractOptions {
|
|
put: (key: K, value: V) => this;
|
|
del: (key: K) => this;
|
|
clear: () => this;
|
|
write(cb?: ErrorCallback): any;
|
|
write(options: any, cb?: ErrorCallback): any;
|
|
}
|
|
|
|
export interface AbstractChainedBatchConstructor {
|
|
// tslint:disable-next-line no-unnecessary-generics
|
|
new <K = any, V = any>(db: any): AbstractChainedBatch<K, V>;
|
|
// tslint:disable-next-line no-unnecessary-generics
|
|
<K = any, V = any>(db: any): AbstractChainedBatch<K, V>;
|
|
}
|
|
|
|
export interface AbstractIterator<K, V> extends AbstractOptions {
|
|
db: AbstractLevelDOWN<K, V>;
|
|
next(cb?: ErrorKeyValueCallback<K, V>): this;
|
|
end(cb?: ErrorCallback): void;
|
|
}
|
|
|
|
export interface AbstractIteratorConstructor {
|
|
// tslint:disable-next-line no-unnecessary-generics
|
|
new <K = any, V = any>(db: any): AbstractIterator<K, V>;
|
|
// tslint:disable-next-line no-unnecessary-generics
|
|
<K = any, V = any>(db: any): AbstractIterator<K, V>;
|
|
}
|
|
|
|
export interface Level extends AbstractLevelDOWN {
|
|
readonly location: string;
|
|
readonly prefix: string;
|
|
readonly version: string | number;
|
|
destroy(location: string, cb?: (err: Error | undefined) => void): void;
|
|
destroy(location: string, prefix: string, cb?: (err: Error | undefined) => void): void;
|
|
}
|
|
|
|
interface LevelOptions {
|
|
readonly prefix?: string;
|
|
readonly version?: string | number;
|
|
}
|
|
|
|
|
|
interface LevelConstructor {
|
|
new(location: string, options?: LevelOptions): Level;
|
|
(location: string, options?: LevelOptions): Level;
|
|
}
|
|
|
|
declare const Level: LevelConstructor;
|
|
|
|
const level = require('level') as LevelConstructor;
|
|
|
|
function createLevelDocument(documentConstructor: any, json: any) {
|
|
const doc = new documentConstructor();
|
|
Object.assign(doc, JSON.parse(json));
|
|
return doc;
|
|
}
|
|
|
|
const wrapped = (location: string, options?: LevelOptions) => {
|
|
const ret = level(location, options);
|
|
ret.tryGet = async (documentConstructor: any, _id: any, options?: AbstractGetOptions): Promise<any> => {
|
|
try {
|
|
const _documentType = documentConstructor.name;
|
|
const key = `${_documentType}/${_id}`;
|
|
const json = await ret.get(key, options);
|
|
return createLevelDocument(documentConstructor, json);
|
|
}
|
|
catch (e) {
|
|
}
|
|
}
|
|
|
|
const iterable = {
|
|
async*[Symbol.asyncIterator]() {
|
|
const iterator = ret.iterator();
|
|
try {
|
|
while (true) {
|
|
const { key, value } = await new Promise<{ key: any, value: any }>((resolve, reject) => {
|
|
iterator.next((err, key, value) => {
|
|
if (err) {
|
|
reject(err);
|
|
}
|
|
else {
|
|
resolve({ key, value });
|
|
}
|
|
})
|
|
});
|
|
|
|
if (key == null && value == null)
|
|
break;
|
|
yield {
|
|
key,
|
|
value,
|
|
}
|
|
}
|
|
}
|
|
finally {
|
|
await new Promise(resolve => iterator.end(resolve));
|
|
}
|
|
}
|
|
};
|
|
|
|
ret[Symbol.asyncIterator] = iterable[Symbol.asyncIterator] as any;
|
|
ret.getAll = (documentConstructor: any, options?: AbstractGetOptions): AsyncIterable<any> => {
|
|
const _documentType = documentConstructor.name;
|
|
const prefix = `${_documentType}/`;
|
|
return {
|
|
async*[Symbol.asyncIterator]() {
|
|
for await (const entry of ret) {
|
|
if (entry.key.startsWith(prefix)) {
|
|
const doc = createLevelDocument(documentConstructor, entry.value);
|
|
if (doc._documentType === _documentType) {
|
|
yield doc;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ret.getCount = async (documentConstructor: any, options?: AbstractGetOptions): Promise<any> => {
|
|
let count = 0;
|
|
for await (const doc of ret.getAll(documentConstructor)) {
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
let curId: number;
|
|
|
|
const oldOpen = ret.open.bind(ret);
|
|
(ret as any).open = async (...args: any) => {
|
|
try {
|
|
curId = parseInt(await ret.get('_id'));
|
|
}
|
|
catch (e) {
|
|
}
|
|
if (!curId)
|
|
curId = 0;
|
|
return oldOpen(...args);
|
|
}
|
|
|
|
ret.nextId = () => {
|
|
if (typeof curId !== 'number')
|
|
throw new Error('curId is not a number');
|
|
return ++curId;
|
|
}
|
|
|
|
const saveId = async () => {
|
|
return ret.put("_id", curId);
|
|
}
|
|
|
|
ret.upsert = async (value: LevelDocument, options?: AbstractOptions): Promise<any> => {
|
|
const _documentType = value.constructor.name;
|
|
if (!value._id)
|
|
value._id = ret.nextId();
|
|
|
|
await saveId();
|
|
|
|
value._documentType = _documentType;
|
|
const key = `${_documentType}/${value._id}`;
|
|
await ret.put(key, JSON.stringify(value), options);
|
|
return value;
|
|
};
|
|
|
|
ret.remove = async (value: LevelDocument) => {
|
|
const _documentType = value.constructor.name;
|
|
let { _id } = value;
|
|
const key = `${_documentType}/${_id}`;
|
|
await ret.del(key);
|
|
}
|
|
|
|
ret.removeId = async (documentConstructor: LevelDocumentConstructor<any>, _id: any) => {
|
|
const _documentType = documentConstructor.name;
|
|
const key = `${_documentType}/${_id}`;
|
|
await ret.del(key);
|
|
}
|
|
|
|
ret.removeAll = async (documentConstructor: LevelDocumentConstructor<any>) => {
|
|
const _documentType = documentConstructor.name;
|
|
const prefix = `${_documentType}/`;
|
|
for await (const entry of ret) {
|
|
if (entry.key.startsWith(prefix)) {
|
|
const doc = createLevelDocument(documentConstructor, entry.value);
|
|
if (doc._documentType === _documentType) {
|
|
await ret.del(entry.key);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
};
|
|
|
|
export default wrapped as LevelConstructor;
|