[IMP] mail: RecordList auto-call unimplemented array method

This allows to support many unimplemented array methods, such
as `Array.prototype.findLast()`.

Part-of: odoo/odoo#139501
This commit is contained in:
Alexandre Kühn
2023-10-26 13:41:16 +00:00
parent c9a3b335d8
commit eae6943021
+14 -60
View File
@@ -92,7 +92,17 @@ export class RecordList extends Array {
if (name === "length") {
return receiver.data.length;
}
return Reflect.get(target, name, receiver);
if (
typeof name === "symbol" ||
Object.keys(target).includes(name) ||
Object.prototype.hasOwnProperty.call(target.constructor.prototype, name)
) {
return Reflect.get(target, name, receiver);
} else {
// Attempt an unimplemented array method call
const array = [...receiver];
return array[name].bind(array);
}
},
/** @param {RecordList<R>} receiver */
set(target, name, val, receiver) {
@@ -167,13 +177,6 @@ export class RecordList extends Array {
}
return r3;
}
/**
* @param {number} index
* @returns {R}
*/
at(index) {
return this.store.get(this.data.at(index));
}
/** @param {R[]} records */
push(...records) {
for (const val of records) {
@@ -225,61 +228,10 @@ export class RecordList extends Array {
}
return this.data.length;
}
/**
* @param {(a: R, b: R) => boolean} func
* @returns {R[]}
*/
map(func) {
return this.data.map((localId) => func(this.store.get(localId)));
}
/**
* @param {(a: R, b: R) => boolean} predicate
* @returns {R[]}
*/
filter(predicate) {
return this.data
.filter((localId) => predicate(this.store.get(localId)))
.map((localId) => this.store.get(localId));
}
/** @param {(a: R, b: R) => boolean} predicate */
some(predicate) {
return this.data.some((localId) => predicate(this.store.get(localId)));
}
/** @param {(a: R, b: R) => boolean} predicate */
every(predicate) {
return this.data.every((localId) => predicate(this.store.get(localId)));
}
/**
* @param {(a: R, b: R) => boolean} predicate
* @returns {R}
*/
find(predicate) {
return this.store.get(this.data.find((localId) => predicate(this.store.get(localId))));
}
/** @param {(a: R, b: R) => boolean} predicate */
findIndex(predicate) {
return this.data.findIndex((localId) => predicate(this.store.get(localId)));
}
/** @param {R} record */
indexOf(record) {
return this.data.indexOf(record?.localId);
}
/** @param {R} record */
includes(record) {
return this.data.includes(record.localId);
}
/** @param {(acc: any, r: R) => any} fn */
reduce(fn, init) {
return this.data.reduce((acc, localId) => fn(acc, this.store.get(localId)), init);
}
/**
* @param {number} [start]
* @param {number} [end]
* @returns {R[]}
*/
slice(start, end) {
return this.data.slice(start, end).map((localId) => this.store.get(localId));
}
/**
* @param {number} [start]
* @param {number} [deleteCount]
@@ -287,7 +239,9 @@ export class RecordList extends Array {
*/
splice(start, deleteCount, ...newRecords) {
const oldRecords = this.slice(start, start + deleteCount);
this.data.splice(start, deleteCount, ...newRecords.map((r) => r.localId));
const list = this.data.slice(); // splice on copy of list so that reactive observers not triggered while splicing
list.splice(start, deleteCount, ...newRecords.map((r) => r.localId));
this.data = list;
for (const r of oldRecords) {
r.__uses__.delete(this);
const { inverse, onDelete } = this.owner.Model._fields[this.name];