fix: prevent entity mutation during upsert

In EntityStoreService, update and upsert both make use of the
detect_identifier utility function to get an identifier to pass through
to (eventually) SQLES.

For `update`, the `id` object is passed as the argument. Properties are
removed from this object when "redundant identifiers" are extracted to
create the update predicate.

For `upsert`, the `entity` object is passed and `id` is ignored. It is
suspected that this was done for reasons of improved developer
experience for developers using the API. The mutation behavior of
detect_identifier caused issues when trying to modify a property that
can also be used as an identifier, without having another identifier
available. (i.e. need to get UID of a subdomain to change the
`subdomain` property instead of just using `subdomain` to identify it).

This commit modifies the default behavior of detect_identifier to not
remove properties, then adds a flag to preserve the previous behavior
which is set TRUE by `update` since it's widelely used by puter.js and
has higher impact for potential regressions.
This commit is contained in:
KernelDeimos
2025-07-28 17:41:46 -04:00
parent 9f8cd18fd8
commit f2a29d5228
2 changed files with 4 additions and 4 deletions
+3 -3
View File
@@ -26,7 +26,7 @@ class IdentifierUtil extends AdvancedBase {
new WeakConstructorFeature(),
]
async detect_identifier (object) {
async detect_identifier (object, allow_mutation = false) {
const redundant_identifiers = this.om.redundant_identifiers ?? [];
let match_found = null;
@@ -60,9 +60,9 @@ class IdentifierUtil extends AdvancedBase {
await object.get(key) : object[key],
}));
if ( object instanceof Entity ) {
await object.del(key);
if ( allow_mutation ) await object.del(key);
} else {
delete object[key];
if ( allow_mutation ) delete object[key];
}
}
let predicate = new And({ children: key_eqs });
@@ -194,7 +194,7 @@ class EntityStoreService extends BaseService {
om: this.om,
});
const predicate = await idu.detect_identifier(id ?? {});
const predicate = await idu.detect_identifier(id ?? {}, true);
if ( predicate ) {
const maybe_entity = await this.select({ predicate, limit: 1 });
if ( maybe_entity.length ) {