BREAKING CHANGE(decorators): Migrate to TC39 Stage 3 decorators and refactor decorator metadata handling; update class initialization, lucene adapter fixes and docs

This commit is contained in:
2025-11-17 12:51:45 +00:00
parent d254f58a05
commit 1cd0f09598
19 changed files with 451 additions and 364 deletions

View File

@@ -26,9 +26,14 @@ const collectionFactory = new CollectionFactory();
* @param dbArg
*/
export function Collection(dbArg: SmartdataDb | TDelayed<SmartdataDb>) {
return function classDecorator<T extends { new (...args: any[]): {} }>(constructor: T) {
return function classDecorator(value: Function, context: ClassDecoratorContext) {
if (context.kind !== 'class') {
throw new Error('Collection can only decorate classes');
}
// Capture original constructor for _svDbOptions forwarding
const originalConstructor = constructor as any;
const originalConstructor = value as any;
const constructor = value as { new (...args: any[]): any };
const getCollection = () => {
if (!(dbArg instanceof SmartdataDb)) {
@@ -71,7 +76,44 @@ export function Collection(dbArg: SmartdataDb | TDelayed<SmartdataDb>) {
configurable: true
});
return decoratedClass;
// Initialize prototype properties from context.metadata (TC39 decorator metadata)
// This ensures prototype properties are available before any instance is created
const metadata = context.metadata as any;
if (metadata) {
const proto = decoratedClass.prototype;
// Initialize globalSaveableProperties
if (metadata.globalSaveableProperties && !proto.globalSaveableProperties) {
proto.globalSaveableProperties = [...metadata.globalSaveableProperties];
}
// Initialize saveableProperties
if (metadata.saveableProperties && !proto.saveableProperties) {
proto.saveableProperties = [...metadata.saveableProperties];
}
// Initialize uniqueIndexes
if (metadata.uniqueIndexes && !proto.uniqueIndexes) {
proto.uniqueIndexes = [...metadata.uniqueIndexes];
}
// Initialize regularIndexes
if (metadata.regularIndexes && !proto.regularIndexes) {
proto.regularIndexes = [...metadata.regularIndexes];
}
// Initialize searchableFields on constructor (not prototype)
if (metadata.searchableFields && !Array.isArray((decoratedClass as any).searchableFields)) {
(decoratedClass as any).searchableFields = [...metadata.searchableFields];
}
// Initialize _svDbOptions from metadata
if (metadata._svDbOptions && !originalConstructor._svDbOptions) {
originalConstructor._svDbOptions = { ...metadata._svDbOptions };
}
}
return decoratedClass as any;
};
}
@@ -89,7 +131,13 @@ export const setDefaultManagerForDoc = <T,>(managerArg: IManager, dbDocArg: T):
* @param dbArg
*/
export function managed<TManager extends IManager>(managerArg?: TManager | TDelayed<TManager>) {
return function classDecorator<T extends { new (...args: any[]): any }>(constructor: T) {
return function classDecorator(value: Function, context: ClassDecoratorContext) {
if (context.kind !== 'class') {
throw new Error('managed can only decorate classes');
}
const constructor = value as { new (...args: any[]): any };
const decoratedClass = class extends constructor {
public static className = constructor.name;
public static get collection() {
@@ -139,7 +187,46 @@ export function managed<TManager extends IManager>(managerArg?: TManager | TDela
return manager;
}
};
return decoratedClass;
// Initialize prototype properties from context.metadata (TC39 decorator metadata)
// This ensures prototype properties are available before any instance is created
const originalConstructor = value as any;
const metadata = context.metadata as any;
if (metadata) {
const proto = decoratedClass.prototype;
// Initialize globalSaveableProperties
if (metadata.globalSaveableProperties && !proto.globalSaveableProperties) {
proto.globalSaveableProperties = [...metadata.globalSaveableProperties];
}
// Initialize saveableProperties
if (metadata.saveableProperties && !proto.saveableProperties) {
proto.saveableProperties = [...metadata.saveableProperties];
}
// Initialize uniqueIndexes
if (metadata.uniqueIndexes && !proto.uniqueIndexes) {
proto.uniqueIndexes = [...metadata.uniqueIndexes];
}
// Initialize regularIndexes
if (metadata.regularIndexes && !proto.regularIndexes) {
proto.regularIndexes = [...metadata.regularIndexes];
}
// Initialize searchableFields on constructor (not prototype)
if (metadata.searchableFields && !Array.isArray((decoratedClass as any).searchableFields)) {
(decoratedClass as any).searchableFields = [...metadata.searchableFields];
}
// Initialize _svDbOptions from metadata
if (metadata._svDbOptions && !originalConstructor._svDbOptions) {
originalConstructor._svDbOptions = { ...metadata._svDbOptions };
}
}
return decoratedClass as any;
};
}