Compare commits

..

4 Commits

Author SHA1 Message Date
8a3425e554 7.0.10
Some checks failed
Default (tags) / security (push) Successful in 58s
Default (tags) / test (push) Failing after 1m20s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-11-28 11:17:25 +00:00
d2092cc5f3 chore(debug): Add metadata debug logging to Collection decorator 2025-11-28 11:17:25 +00:00
1a621ca64e v7.0.9
Some checks failed
Default (tags) / security (push) Successful in 38s
Default (tags) / test (push) Failing after 50s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-11-28 11:02:39 +00:00
f6cc07880a fix(classes.collection): Fix closure bug in Collection decorator by defining collection getter on original constructor and prototype 2025-11-28 11:02:39 +00:00
4 changed files with 27 additions and 2 deletions

View File

@@ -1,5 +1,11 @@
# Changelog # Changelog
## 2025-11-28 - 7.0.9 - fix(classes.collection)
Fix closure bug in Collection decorator by defining collection getter on original constructor and prototype
- Define the collection getter on the original constructor so class-level references (e.g. `User.collection`) resolve to the decorated collection instead of the original constructor's closure value.
- Also define the getter on the original constructor's prototype to ensure instance access works consistently across runtimes (Deno/Node).
## 2025-11-28 - 7.0.8 - fix(classes.collection) ## 2025-11-28 - 7.0.8 - fix(classes.collection)
Fix closure issue in managed decorator so Class.collection/instance.collection resolve correctly Fix closure issue in managed decorator so Class.collection/instance.collection resolve correctly

View File

@@ -1,6 +1,6 @@
{ {
"name": "@push.rocks/smartdata", "name": "@push.rocks/smartdata",
"version": "7.0.8", "version": "7.0.10",
"private": false, "private": false,
"description": "An advanced library for NoSQL data organization and manipulation using TypeScript with support for MongoDB, data validation, collections, and custom data types.", "description": "An advanced library for NoSQL data organization and manipulation using TypeScript with support for MongoDB, data validation, collections, and custom data types.",
"exports": { "exports": {

View File

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@push.rocks/smartdata', name: '@push.rocks/smartdata',
version: '7.0.8', version: '7.0.9',
description: 'An advanced library for NoSQL data organization and manipulation using TypeScript with support for MongoDB, data validation, collections, and custom data types.' description: 'An advanced library for NoSQL data organization and manipulation using TypeScript with support for MongoDB, data validation, collections, and custom data types.'
} }

View File

@@ -64,6 +64,20 @@ export function Collection(dbArg: SmartdataDb | TDelayed<SmartdataDb>) {
configurable: true configurable: true
}); });
// Closure fix: When class methods reference the class name (e.g., `User.collection`),
// they get the original constructor via closure, not the decorated class.
// Define collection getter on the original constructor.
Object.defineProperty(constructor, 'collection', {
get: getCollection,
enumerable: false,
configurable: true
});
Object.defineProperty(constructor.prototype, 'collection', {
get: getCollection,
enumerable: false,
configurable: true
});
// Deno compatibility note: Property decorators set properties on the prototype. // Deno compatibility note: Property decorators set properties on the prototype.
// Since we removed instance property declarations from SmartDataDbDoc, // Since we removed instance property declarations from SmartDataDbDoc,
// the decorator-set prototype properties are now accessible without shadowing. // the decorator-set prototype properties are now accessible without shadowing.
@@ -79,17 +93,22 @@ export function Collection(dbArg: SmartdataDb | TDelayed<SmartdataDb>) {
// Initialize prototype properties from context.metadata (TC39 decorator metadata) // Initialize prototype properties from context.metadata (TC39 decorator metadata)
// This ensures prototype properties are available before any instance is created // This ensures prototype properties are available before any instance is created
const metadata = context.metadata as any; const metadata = context.metadata as any;
logger.log('debug', `Collection decorator: metadata keys = ${metadata ? Object.keys(metadata).join(', ') : 'null'}`);
logger.log('debug', `Collection decorator: saveableProperties in metadata = ${metadata?.saveableProperties?.length ?? 0}`);
logger.log('debug', `Collection decorator: globalSaveableProperties in metadata = ${metadata?.globalSaveableProperties?.length ?? 0}`);
if (metadata) { if (metadata) {
const proto = decoratedClass.prototype; const proto = decoratedClass.prototype;
// Initialize globalSaveableProperties // Initialize globalSaveableProperties
if (metadata.globalSaveableProperties && !proto.globalSaveableProperties) { if (metadata.globalSaveableProperties && !proto.globalSaveableProperties) {
proto.globalSaveableProperties = [...metadata.globalSaveableProperties]; proto.globalSaveableProperties = [...metadata.globalSaveableProperties];
logger.log('debug', `Collection decorator: initialized globalSaveableProperties with ${proto.globalSaveableProperties.length} properties`);
} }
// Initialize saveableProperties // Initialize saveableProperties
if (metadata.saveableProperties && !proto.saveableProperties) { if (metadata.saveableProperties && !proto.saveableProperties) {
proto.saveableProperties = [...metadata.saveableProperties]; proto.saveableProperties = [...metadata.saveableProperties];
logger.log('debug', `Collection decorator: initialized saveableProperties with ${proto.saveableProperties.length} properties`);
} }
// Initialize uniqueIndexes // Initialize uniqueIndexes