mirror of
https://github.com/cerc-io/watcher-ts
synced 2025-08-03 04:44:06 +00:00
Load relations sequentially (#212)
This commit is contained in:
parent
2517f110ea
commit
be65ca45ea
@ -632,118 +632,21 @@ export class Database {
|
|||||||
return entities;
|
return entities;
|
||||||
}
|
}
|
||||||
|
|
||||||
const relationPromises = selections.filter((selection) => selection.kind === 'Field' && Boolean(relations[selection.name.value]))
|
const relationSelections = selections.filter((selection) => selection.kind === 'Field' && Boolean(relations[selection.name.value]));
|
||||||
.map(async selection => {
|
|
||||||
assert(selection.kind === 'Field');
|
|
||||||
const field = selection.name.value;
|
|
||||||
const { entity: relationEntity, isArray, isDerived, field: foreignKey } = relations[field];
|
|
||||||
let childSelections = selection.selectionSet?.selections || [];
|
|
||||||
|
|
||||||
// Filter out __typename field in GQL for loading relations.
|
for (const selection of relationSelections) {
|
||||||
childSelections = childSelections.filter(selection => !(selection.kind === 'Field' && selection.name.value === '__typename'));
|
assert(selection.kind === 'Field');
|
||||||
|
const field = selection.name.value;
|
||||||
|
const { entity: relationEntity, isArray, isDerived, field: foreignKey } = relations[field];
|
||||||
|
let childSelections = selection.selectionSet?.selections || [];
|
||||||
|
|
||||||
if (isDerived) {
|
// Filter out __typename field in GQL for loading relations.
|
||||||
const where: Where = {
|
childSelections = childSelections.filter(selection => !(selection.kind === 'Field' && selection.name.value === '__typename'));
|
||||||
[foreignKey]: [{
|
|
||||||
value: entities.map((entity: any) => entity.id),
|
|
||||||
not: false,
|
|
||||||
operator: 'in'
|
|
||||||
}]
|
|
||||||
};
|
|
||||||
|
|
||||||
const relatedEntities = await this.getEntities(
|
|
||||||
queryRunner,
|
|
||||||
relationEntity,
|
|
||||||
relationsMap,
|
|
||||||
block,
|
|
||||||
where,
|
|
||||||
{},
|
|
||||||
childSelections
|
|
||||||
);
|
|
||||||
|
|
||||||
const relatedEntitiesMap = relatedEntities.reduce((acc: {[key:string]: any[]}, entity: any) => {
|
|
||||||
// Related entity might be loaded with data.
|
|
||||||
const parentEntityId = entity[foreignKey].id ?? entity[foreignKey];
|
|
||||||
|
|
||||||
if (!acc[parentEntityId]) {
|
|
||||||
acc[parentEntityId] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (acc[parentEntityId].length < DEFAULT_LIMIT) {
|
|
||||||
acc[parentEntityId].push(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
entities.forEach((entity: any) => {
|
|
||||||
if (relatedEntitiesMap[entity.id]) {
|
|
||||||
entity[field] = relatedEntitiesMap[entity.id];
|
|
||||||
} else {
|
|
||||||
entity[field] = [];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isArray) {
|
|
||||||
const relatedIds = entities.reduce((acc: Set<string>, entity: any) => {
|
|
||||||
entity[field].forEach((relatedEntityId: string) => acc.add(relatedEntityId));
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
}, new Set());
|
|
||||||
|
|
||||||
const where: Where = {
|
|
||||||
id: [{
|
|
||||||
value: Array.from(relatedIds),
|
|
||||||
not: false,
|
|
||||||
operator: 'in'
|
|
||||||
}]
|
|
||||||
};
|
|
||||||
|
|
||||||
const relatedEntities = await this.getEntities(
|
|
||||||
queryRunner,
|
|
||||||
relationEntity,
|
|
||||||
relationsMap,
|
|
||||||
block,
|
|
||||||
where,
|
|
||||||
{},
|
|
||||||
childSelections
|
|
||||||
);
|
|
||||||
|
|
||||||
entities.forEach((entity: any) => {
|
|
||||||
const relatedEntityIds: Set<string> = entity[field].reduce((acc: Set<string>, id: string) => {
|
|
||||||
acc.add(id);
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
}, new Set());
|
|
||||||
|
|
||||||
entity[field] = [];
|
|
||||||
|
|
||||||
relatedEntities.forEach((relatedEntity: any) => {
|
|
||||||
if (relatedEntityIds.has(relatedEntity.id) && entity[field].length < DEFAULT_LIMIT) {
|
|
||||||
entity[field].push(relatedEntity);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// field is neither an array nor derivedFrom
|
|
||||||
if (childSelections.length === 1 && childSelections[0].kind === 'Field' && childSelections[0].name.value === 'id') {
|
|
||||||
// Avoid loading relation if selections only has id field.
|
|
||||||
entities.forEach((entity: any) => {
|
|
||||||
entity[field] = { id: entity[field] };
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (isDerived) {
|
||||||
const where: Where = {
|
const where: Where = {
|
||||||
id: [{
|
[foreignKey]: [{
|
||||||
value: entities.map((entity: any) => entity[field]),
|
value: entities.map((entity: any) => entity.id),
|
||||||
not: false,
|
not: false,
|
||||||
operator: 'in'
|
operator: 'in'
|
||||||
}]
|
}]
|
||||||
@ -759,20 +662,116 @@ export class Database {
|
|||||||
childSelections
|
childSelections
|
||||||
);
|
);
|
||||||
|
|
||||||
const relatedEntitiesMap = relatedEntities.reduce((acc: {[key:string]: any}, entity: any) => {
|
const relatedEntitiesMap = relatedEntities.reduce((acc: {[key:string]: any[]}, entity: any) => {
|
||||||
acc[entity.id] = entity;
|
// Related entity might be loaded with data.
|
||||||
|
const parentEntityId = entity[foreignKey].id ?? entity[foreignKey];
|
||||||
|
|
||||||
|
if (!acc[parentEntityId]) {
|
||||||
|
acc[parentEntityId] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (acc[parentEntityId].length < DEFAULT_LIMIT) {
|
||||||
|
acc[parentEntityId].push(entity);
|
||||||
|
}
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
entities.forEach((entity: any) => {
|
entities.forEach((entity: any) => {
|
||||||
if (relatedEntitiesMap[entity[field]]) {
|
if (relatedEntitiesMap[entity.id]) {
|
||||||
entity[field] = relatedEntitiesMap[entity[field]];
|
entity[field] = relatedEntitiesMap[entity.id];
|
||||||
|
} else {
|
||||||
|
entity[field] = [];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
await Promise.all(relationPromises);
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isArray) {
|
||||||
|
const relatedIds = entities.reduce((acc: Set<string>, entity: any) => {
|
||||||
|
entity[field].forEach((relatedEntityId: string) => acc.add(relatedEntityId));
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, new Set());
|
||||||
|
|
||||||
|
const where: Where = {
|
||||||
|
id: [{
|
||||||
|
value: Array.from(relatedIds),
|
||||||
|
not: false,
|
||||||
|
operator: 'in'
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
const relatedEntities = await this.getEntities(
|
||||||
|
queryRunner,
|
||||||
|
relationEntity,
|
||||||
|
relationsMap,
|
||||||
|
block,
|
||||||
|
where,
|
||||||
|
{},
|
||||||
|
childSelections
|
||||||
|
);
|
||||||
|
|
||||||
|
entities.forEach((entity: any) => {
|
||||||
|
const relatedEntityIds: Set<string> = entity[field].reduce((acc: Set<string>, id: string) => {
|
||||||
|
acc.add(id);
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, new Set());
|
||||||
|
|
||||||
|
entity[field] = [];
|
||||||
|
|
||||||
|
relatedEntities.forEach((relatedEntity: any) => {
|
||||||
|
if (relatedEntityIds.has(relatedEntity.id) && entity[field].length < DEFAULT_LIMIT) {
|
||||||
|
entity[field].push(relatedEntity);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// field is neither an array nor derivedFrom
|
||||||
|
if (childSelections.length === 1 && childSelections[0].kind === 'Field' && childSelections[0].name.value === 'id') {
|
||||||
|
// Avoid loading relation if selections only has id field.
|
||||||
|
entities.forEach((entity: any) => {
|
||||||
|
entity[field] = { id: entity[field] };
|
||||||
|
});
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const where: Where = {
|
||||||
|
id: [{
|
||||||
|
value: entities.map((entity: any) => entity[field]),
|
||||||
|
not: false,
|
||||||
|
operator: 'in'
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
const relatedEntities = await this.getEntities(
|
||||||
|
queryRunner,
|
||||||
|
relationEntity,
|
||||||
|
relationsMap,
|
||||||
|
block,
|
||||||
|
where,
|
||||||
|
{},
|
||||||
|
childSelections
|
||||||
|
);
|
||||||
|
|
||||||
|
const relatedEntitiesMap = relatedEntities.reduce((acc: {[key:string]: any}, entity: any) => {
|
||||||
|
acc[entity.id] = entity;
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
entities.forEach((entity: any) => {
|
||||||
|
if (relatedEntitiesMap[entity[field]]) {
|
||||||
|
entity[field] = relatedEntitiesMap[entity[field]];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return entities;
|
return entities;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user