query-engine.ts

Non-parsing query-engine on top of key-value storage
git clone git://git.finwo.net/lib/query-engine.ts
Log | Files | Refs | README | LICENSE

commit ce9f4c53c66fc33f66a6934b8ed574077417c3dc
parent 80a92ae669bba1521c8eeb731dc0c14bb35c0d2e
Author: finwo <finwo@pm.me>
Date:   Wed,  4 Feb 2026 15:47:35 +0100

Passing types into sub-entities

Diffstat:
A.gitignore | 1+
MREADME.md | 2+-
Apackage-lock.json | 44++++++++++++++++++++++++++++++++++++++++++++
Apackage.json | 6++++++
Asrc/adapter/abstract.ts | 1+
Asrc/adapter/level.ts | 5+++++
Asrc/decorators/composite-index.ts | 9+++++++++
Asrc/decorators/document.ts | 10++++++++++
Asrc/decorators/id.ts | 8++++++++
Asrc/decorators/idx.ts | 8++++++++
Asrc/decorators/index.ts | 6++++++
Asrc/decorators/string.ts | 8++++++++
Asrc/decorators/version.ts | 8++++++++
Asrc/index.ts | 39+++++++++++++++++++++++++++++++++++++++
Asrc/test.ts | 25+++++++++++++++++++++++++
Asrc/types/abstract-constructable.ts | 1+
Asrc/types/abstract-document.ts | 0
Asrc/types/constructable.ts | 1+
Atsconfig.json | 0
19 files changed, 181 insertions(+), 1 deletion(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/README.md b/README.md @@ -8,7 +8,7 @@ Intended usage: // model/user.ts -import { Document, ID, Version, String, Index, CompositeIndex } from '@finwo/query-engine/types'; +import { Document, ID, Version, String, Index, CompositeIndex } from '@finwo/query-engine/decorators'; @Document({ adapter?: customAdapterInstance }) @CompositeIndex('otherIndexName', { diff --git a/package-lock.json b/package-lock.json @@ -0,0 +1,44 @@ +{ + "name": "query-engine.ts", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "@types/node": "^25.2.0", + "typescript": "^5.9.3" + } + }, + "node_modules/@types/node": { + "version": "25.2.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.0.tgz", + "integrity": "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/package.json b/package.json @@ -0,0 +1,6 @@ +{ + "devDependencies": { + "@types/node": "^25.2.0", + "typescript": "^5.9.3" + } +} diff --git a/src/adapter/abstract.ts b/src/adapter/abstract.ts @@ -0,0 +1 @@ +export abstract class AbstractAdapter {} diff --git a/src/adapter/level.ts b/src/adapter/level.ts @@ -0,0 +1,5 @@ +import {AbstractAdapter} from "./abstract"; + +export class LevelAdapter extends AbstractAdapter { + +} diff --git a/src/decorators/composite-index.ts b/src/decorators/composite-index.ts @@ -0,0 +1,9 @@ +export function CompositeIndex(): ClassDecorator { + return targetConstructor => { + // map.set(targetConstructor, { + // type : targetConstructor, + // fn : targetConstructor, + // value : EMPTY_VALUE, + // }); + }; +} diff --git a/src/decorators/document.ts b/src/decorators/document.ts @@ -0,0 +1,10 @@ + +export function Document(): ClassDecorator { + return targetConstructor => { + // map.set(targetConstructor, { + // type : targetConstructor, + // fn : targetConstructor, + // value : EMPTY_VALUE, + // }); + }; +} diff --git a/src/decorators/id.ts b/src/decorators/id.ts @@ -0,0 +1,8 @@ +export function ID(): ParameterDecorator { + return function(target: any, propertyKey: string | symbol | undefined, index: number) { + // TBD + // const paramTypes: any[] = Reflect.getMetadata('design:paramtypes', target); + // paramTypes[index] = identifier; + // Reflect.defineMetadata('design:paramtypes', paramTypes, target); + }; +} diff --git a/src/decorators/idx.ts b/src/decorators/idx.ts @@ -0,0 +1,8 @@ +export function Index(): ParameterDecorator { + return function(target: any, propertyKey: string | symbol | undefined, index: number) { + // TBD + // const paramTypes: any[] = Reflect.getMetadata('design:paramtypes', target); + // paramTypes[index] = identifier; + // Reflect.defineMetadata('design:paramtypes', paramTypes, target); + }; +} diff --git a/src/decorators/index.ts b/src/decorators/index.ts @@ -0,0 +1,6 @@ +export * from './composite-index'; +export * from './document'; +export * from './id'; +export * from './idx'; +export * from './string'; +export * from './version'; diff --git a/src/decorators/string.ts b/src/decorators/string.ts @@ -0,0 +1,8 @@ +export function String(): ParameterDecorator { + return function(target: any, propertyKey: string | symbol | undefined, index: number) { + // TBD + // const paramTypes: any[] = Reflect.getMetadata('design:paramtypes', target); + // paramTypes[index] = identifier; + // Reflect.defineMetadata('design:paramtypes', paramTypes, target); + }; +} diff --git a/src/decorators/version.ts b/src/decorators/version.ts @@ -0,0 +1,8 @@ +export function Version(): ParameterDecorator { + return function(target: any, propertyKey: string | symbol | undefined, index: number) { + // TBD + // const paramTypes: any[] = Reflect.getMetadata('design:paramtypes', target); + // paramTypes[index] = identifier; + // Reflect.defineMetadata('design:paramtypes', paramTypes, target); + }; +} diff --git a/src/index.ts b/src/index.ts @@ -0,0 +1,39 @@ +import {AbstractAdapter} from "./adapter/abstract"; +import {Constructable} from "./types/constructable"; + +export type DocumentDefinition = { + model: Constructable<{}> +} + +export class Query<P extends Constructable<{}>> { + constructor(protected documentType: P) { + // TBD + } +} + +export class QueryEngine<DocumentDefinitions extends Record<string, DocumentDefinition>> { + protected documents: DocumentDefinitions; + + constructor(options: { + defaultAdapter?: AbstractAdapter, + documents?: DocumentDefinitions, + } = { + + }) { + // Sanitize inputs + if ('object' !== typeof options) options = {}; + options = Object.assign({ documents: {} }, options || {}); + if ('object' !== typeof options.documents) options.documents = {} as DocumentDefinitions; + options.documents = Object.assign({}, options.documents || {} as DocumentDefinitions); + + // clean enough + this.documents = options.documents; + } + + query<M extends keyof DocumentDefinitions>(documentType: M): Query<DocumentDefinitions[M]['model']> { + return new Query(this.documents[documentType].model); + } + +} + + diff --git a/src/test.ts b/src/test.ts @@ -0,0 +1,25 @@ +import {QueryEngine} from "."; + +class User {} +class Post {} +class Book {} + +const queryEngine = new QueryEngine({ + documents: { + user: { + model: User + }, + post: { + model: Post + }, + book: { + model: Book + }, + } +}); + +const query = queryEngine.query('user'); + +query + +console.log({ queryEngine }); diff --git a/src/types/abstract-constructable.ts b/src/types/abstract-constructable.ts @@ -0,0 +1 @@ +export type AbstractConstructable<T> = NewableFunction & { prototype: T }; diff --git a/src/types/abstract-document.ts b/src/types/abstract-document.ts diff --git a/src/types/constructable.ts b/src/types/constructable.ts @@ -0,0 +1 @@ +export type Constructable<T> = new (...args: any[]) => T; diff --git a/tsconfig.json b/tsconfig.json