Skip to content

Commit

Permalink
🐛 Don't flatten objects when updating records, it causes too many issues
Browse files Browse the repository at this point in the history
  • Loading branch information
skerit committed Aug 21, 2024
1 parent fedc91a commit 46fd4d2
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 74 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 1.4.0-alpha.6 (WIP)

* Don't flatten objects when updating records, it causes too many issues

## 1.4.0-alpha.5 (2024-08-16)

* Pre-release with updated dependencies

## 1.4.0-alpha.4 (2024-08-04)

* Make `AQL` trail placeholders default to explicit `null` values
Expand Down
165 changes: 92 additions & 73 deletions lib/app/datasource/mongo_datasource.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,11 @@ Mongo.setMethod(function castToBigInt(value) {
}

if (typeof value == 'object') {
return value.toBigInt();
if (value.toBigInt) {
return value.toBigInt();
}

return null;
}

return BigInt(value);
Expand Down Expand Up @@ -541,110 +545,125 @@ Mongo.setMethod(function _create(context) {
*/
Mongo.setMethod(function _update(context) {

const model = context.getModel(),
options = context.getSaveOptions();
const model = context.getModel();

return Swift.waterfall(
this.collection(model.table),
collection => {
return performUpdate(collection, model, context);
}
);
});

let key;
/**
* Perform the update
*
* @author Jelle De Loecker <jelle@elevenways.be>
* @since 1.4.0
* @version 1.4.0
*
* @return {Pledge}
*/
const performUpdate = (collection, model, context) => {

// Get the converted data
const data = context.getConvertedData();
const options = context.getSaveOptions();

// Get the id to update, it should always be inside the given data
let id = data._id;
let key;

// Clone the data object
let doc = {...data};
// Get the converted data
const data = context.getConvertedData();

// Values that will get flattened
let to_flatten = {};
// Get the id to update, it should always be inside the given data
let id = data._id;

// Field names that won't get flattened
let no_flatten = {};
// Clone the data object
let doc = {...data};

// Remove the id
delete doc._id;
// Values that will get flattened
let to_flatten = {};

if (!options.override_created) {
delete doc.created;
}
// Field names that won't get flattened
let no_flatten = {};

// Iterate over the fields
for (key in doc) {
let field = model.getField(key);
// Remove the id
delete doc._id;

if (field && (field.is_self_contained || field.is_translatable)) {
no_flatten[key] = doc[key];
} else {
to_flatten[key] = doc[key];
}
}
if (!options.override_created) {
delete doc.created;
}

// Flatten the object, using periods & NOT flattening arrays
let flat = Object.flatten(to_flatten, '.', false);
// Iterate over the fields
for (key in doc) {
let field = model.getField(key);

// Assign the no-flatten values, too
Object.assign(flat, no_flatten);
if (field && (field.is_self_contained || field.is_translatable || typeof doc[key] == 'object')) {
no_flatten[key] = doc[key];
} else {
to_flatten[key] = doc[key];
}
}

let unset = {};
// Flatten the object, using periods & NOT flattening arrays
let flat = Object.flatten(to_flatten, '.', false);

for (key in flat) {
// Undefined or null means we want to delete the value
// We can't set null, because that could interfere with dot notation updates
if (flat[key] == null) {
// Assign the no-flatten values, too
Object.assign(flat, no_flatten);

// Add the key to the unset object
unset[key] = '';
let unset = {};

// Remove it from the flat object
delete flat[key];
}
}
for (key in flat) {
// Undefined or null means we want to delete the value
// We can't set null, because that could interfere with dot notation updates
if (flat[key] == null) {

let update_object = {
$set: flat
};
// Add the key to the unset object
unset[key] = '';

if (!Object.isEmpty(unset)) {
update_object.$unset = unset;
}
// Remove it from the flat object
delete flat[key];
}
}

if (options.debug) {
console.log('Updating with obj', id, update_object);
}
let update_object = {
$set: flat
};

let promise;
if (!Object.isEmpty(unset)) {
update_object.$unset = unset;
}

if (collection.findOneAndUpdate) {
promise = collection.findOneAndUpdate({_id: id}, update_object, {upsert: true});
} else if (collection.findAndModify) {
promise = collection.findAndModify({_id: id}, [['_id', 1]], update_object, {upsert: true});
} else {
// If it's not available (like nedb)
promise = collection.update({_id: ''+id}, update_object, {upsert: true});
}
if (options.debug) {
console.log('Updating with obj', id, update_object);
}

let pledge = new Swift();
let promise;

Pledge.done(promise, function afterUpdate(err, result) {
if (collection.findOneAndUpdate) {
promise = collection.findOneAndUpdate({_id: id}, update_object, {upsert: true});
} else if (collection.findAndModify) {
promise = collection.findAndModify({_id: id}, [['_id', 1]], update_object, {upsert: true});
} else {
// If it's not available (like nedb)
promise = collection.update({_id: ''+id}, update_object, {upsert: true});
}

// Clear the cache
model.nukeCache();
let pledge = new Swift();

if (err != null) {
return pledge.reject(err);
}
Pledge.done(promise, function afterUpdate(err, result) {

pledge.resolve(Object.assign({}, data));
});
// Clear the cache
model.nukeCache();

return pledge;
if (err != null) {
return pledge.reject(err);
}
);
});

pledge.resolve(Object.assign({}, data));
});

return pledge;

};

/**
* Remove a record from the database
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "alchemymvc",
"description": "MVC framework for Node.js",
"version": "1.4.0-alpha.5",
"version": "1.4.0-alpha.6",
"author": "Jelle De Loecker <jelle@elevenways.be>",
"keywords": [
"alchemy",
Expand Down

0 comments on commit 46fd4d2

Please sign in to comment.