Conversión de código JS duplicado en una función de orden superior
Tengo un bloque de código que se reutiliza y quiero usar programación funcional para eliminar esta duplicación.
Mi código toma una serie de elementos, los divide en lotes de 500 y luego hace algún tipo de trabajo en ellos.
En la primera función, elimina elementos de una base de datos:
Función de eliminación:
const deleteDocuments = async (documentReferences) => {
const batchesOf500 = Math.ceil(documentReferences.length / 500);
for(let batchNumber = 0; batchNumber < batchesOf500; batchNumber += 1) {
const batch = getBatchWriter();
const startingIndex = batchNumber * 500;
const maxIndex = startingIndex + 500;
for(let index = startingIndex; index < maxIndex; index += 1) {
if(index < documentReferences.length) {
const documentPath = documentReferences[index];
batch.delete(documentPath);
}
}
await batch.commit();
}
}
La segunda función es casi idéntica, pero en lugar de eliminar de una base de datos, escribe en la base de datos:
Agregar función:
const writeToCollection = async (dataArray, collectionRef) => {
const batchesOf500 = Math.ceil(dataArray.length / 500);
for(let batchNumber = 0; batchNumber < batchesOf500; batchNumber += 1) {
const batch = getBatchWriter();
const startingIndex = batchNumber * 500;
const maxIndex = startingIndex + 500;
for(let index = startingIndex; index < maxIndex; index += 1) {
if(index < dataArray.length) {
const [key, value] = dataArray[index];
const doc = getDocFromPath(key);
batch.set(doc, value);
}
}
}
await batch.commit();
}
}
Estas funciones son casi idénticas, así que escribí una función de orden superior para hacer la mayor parte del trabajo preliminar.
Función de orden superior:
const runFunctionInBatchesOf500 = (func, dataArray) => {
const batchesOf500 = Math.ceil(dataArray.length / 500);
for(let batchNumber = 0; batchNumber < batchesOf500; batchNumber += 1) {
const batch = this.firestore.batch();
const startingIndex = batchNumber * 500;
const maxIndex = startingIndex + 500;
for(let index = startingIndex; index < maxIndex; index += 1) {
const document = dataArray[index];
func(document, batch);
}
}
await batch.commit();
}
Y para ello, puede crear su propia funcionalidad para aplicarla a cada documento y usarla así:
const write = (document, batch) => {
const doc = getDocFromPath(key);
batch.set(doc, value);
};
await runFunctionInBatchesOf500(write, dataArray);
Todo esto funciona, pero creo que me falta algo. ¿Es este un uso eficiente de funciones de orden superior? ¿Cuál sería una solución estilo FP más elegante?
Respuestas
De una breve reseña;
- ¿Por qué codificar la longitud del lote en 500?
- ¿Por qué no hacer que la longitud del lote sea una buena constante?
- Incluso ha codificado la longitud en el nombre de la función, lo cual es realmente desafortunado
batchNumber++
es más canónico quebatchNumber += 1
- Hubiera ido a por
maxIndex = Math.min(startingIndex + 500, dataArray.length);
porque ahora tienes un montón de llamadasfunc
conundefined
comodocument
valor await
requiererunFunctionInBatchesOf500
serasync
(falta ahora)- Usaría
Array.prototype.slice()
para crear lotes como una matriz y luego usaríaforEach
en cada porción / lote const doc = getDocFromPath(key);
<- ¿de dóndekey
viene, un mal global?
Personalmente, sería un poco malvado ajustando el prototipo Array para poder seguir encadenando, estilo FP;
Array.prototype.mapSlice = function arrrayMapSlice(n){
//Just return `this` if we get a non-sensical parameter
if(isNaN(n) || n <= 0){
return this;
}
let start = 0, out = [];
while(start < this.length){
out.push(this.slice(start, start+=n));
}
return out;
}
async function runBatches(list, f, batchSize){
batchSize = batchSize || 500;
list.mapSlice(batchSize).forEach(batch => {
const firestoreBatch = this.firestore.batch();
batch.forEach(document => f(document, firestoreBatch ));
});
await batch.commit();
}