Skip to content

Commit

Permalink
fix(datasource-mongoose): don't return records for null values of fla…
Browse files Browse the repository at this point in the history
…ttened fields when using asModel on object fields (#853)
  • Loading branch information
Guillaume Gautreau authored Oct 17, 2023
1 parent 5a86953 commit d4b3f0c
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 2 deletions.
18 changes: 16 additions & 2 deletions packages/datasource-mongoose/src/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
splitId,
unflattenRecord,
} from './utils/helpers';
import AsModelNotNullGenerator from './utils/pipeline/as-model-not-null';
import FilterGenerator from './utils/pipeline/filter';
import GroupGenerator from './utils/pipeline/group';
import LookupGenerator from './utils/pipeline/lookup';
Expand Down Expand Up @@ -54,13 +55,26 @@ export default class MongooseCollection extends BaseCollection {
caller: Caller,
filter: PaginatedFilter,
projection: Projection,
): Promise<RecordData[]> {
return this._list(
AsModelNotNullGenerator.asModelNotNull(this.model, this.stack),
filter,
projection,
);
}

private async _list(
pipelineBefore: PipelineStage[],
filter: PaginatedFilter,
projection: Projection,
): Promise<RecordData[]> {
const lookupProjection = projection.union(
filter.conditionTree?.projection,
filter.sort?.projection,
);

const records = await this.model.aggregate([
...(pipelineBefore || []),
...this.buildBasePipeline(filter, lookupProjection),
...ProjectionGenerator.project(projection),
]);
Expand Down Expand Up @@ -194,7 +208,7 @@ export default class MongooseCollection extends BaseCollection {
// Fetch the ids of the documents OR subdocuments that will be updated.
// We need to do that regardless of `this.prefix` because the filter may contain conditions on
// relationships.
const records = await this.list(caller, filter, new Projection('_id'));
const records = await this._list([], filter, new Projection('_id'));
const ids = records.map(record => record._id);

if (this.stack.length < 2) {
Expand Down Expand Up @@ -242,7 +256,7 @@ export default class MongooseCollection extends BaseCollection {
}

private async _delete(caller: Caller, filter: Filter): Promise<void> {
const records = await this.list(caller, filter, new Projection('_id'));
const records = await this._list([], filter, new Projection('_id'));
const ids = records.map(record => record._id);

if (this.stack.length < 2) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Model, PipelineStage } from 'mongoose';

/**
* Generate pipeline to query submodels.
*
* The operations make rotations in the documents so that the root is changed to the submodel
* without loosing the parent (which may be needed later on).
*/
export default class AsModelNotNullGenerator {
static asModelNotNull(
model: Model<unknown>,
stack: { prefix: string | null; asFields: string[]; asModels: string[] }[],
): PipelineStage[] {
return stack.flatMap(({ prefix, asModels }) => {
return asModels.map(
(asModel): PipelineStage => ({
$match: {
[[prefix, asModel].filter(Boolean).join('.')]: { $ne: null },
},
}),
);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ export default async function setupFlattener(dbName = 'test') {
name: String,
address: {
street: String,
city: String,
zipCode: String,
number: String,
},
}),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,30 @@ describe('Complex flattening', () => {
}),
]);
});

it('should not retrieve records for children models when the value is null', async () => {
connection = await setupFlattener('collection_flattener_list');
const dataSource = new MongooseDatasource(connection, {
flattenMode: 'manual',
flattenOptions: {
companies: { asModels: ['address'] },
},
});

const [company] = await dataSource
.getCollection('companies')
.create(caller, [{ name: 'Renault' }]);

const records = await dataSource.getCollection('companies_address').list(
caller,
new Filter({
conditionTree: new ConditionTreeLeaf('parent:_id', 'Equal', `${company._id}`),
}),
new Projection('_id', 'horsePower', 'parentId', 'parent:_id', 'parent:address:city'),
);

expect(records).toEqual([]);
});
});
});
});

0 comments on commit d4b3f0c

Please sign in to comment.