Skip to content

Commit 75b1c8a

Browse files
feat: can now query historical data (#752)
* 'at' to recordsAggregation pipeline * working at parameter * working at parameter --------- Co-authored-by: Antoine Hurard <[email protected]>
1 parent a76928a commit 75b1c8a

File tree

7 files changed

+75
-4
lines changed

7 files changed

+75
-4
lines changed

src/models/layer.model.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ export interface Layer extends Document {
131131
layerDefinition?: LayerDefinition;
132132
popupInfo?: PopupElement[];
133133
contextFilters: string;
134+
at: string;
134135
}
135136

136137
/** Mongoose layer schema declaration */
@@ -185,6 +186,7 @@ const layerSchema = new Schema(
185186
},
186187
},
187188
contextFilters: String,
189+
at: String,
188190
},
189191
{
190192
timestamps: { createdAt: 'createdAt', updatedAt: 'modifiedAt' },

src/routes/gis/index.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ router.get('/feature', async (req, res) => {
247247
const contextFilters = JSON.parse(
248248
decodeURIComponent(get(req, 'query.contextFilters', null))
249249
);
250+
const at = get(req, 'query.at') as string | undefined;
250251
// const tolerance = get(req, 'query.tolerance', 1);
251252
// const highQuality = get(req, 'query.highquality', true);
252253
// turf.simplify(geoJsonData, {
@@ -319,14 +320,15 @@ router.get('/feature', async (req, res) => {
319320
// const filterPolygon = getFilterPolygon(req.query);
320321

321322
if (aggregation) {
322-
query = `query recordsAggregation($resource: ID!, $aggregation: ID!, $contextFilters: JSON, $first: Int) {
323-
recordsAggregation(resource: $resource, aggregation: $aggregation, contextFilters: $contextFilters, first: $first)
323+
query = `query recordsAggregation($resource: ID!, $aggregation: ID!, $contextFilters: JSON, $first: Int, $at: Date) {
324+
recordsAggregation(resource: $resource, aggregation: $aggregation, contextFilters: $contextFilters, first: $first, at: $at)
324325
}`;
325326
variables = {
326327
resource: resourceData._id,
327328
aggregation: aggregation._id,
328329
contextFilters,
329330
first: 1000,
331+
at: at ? new Date(at) : undefined,
330332
};
331333
} else if (layout) {
332334
query = buildQuery(layout.query);
@@ -338,6 +340,7 @@ router.get('/feature', async (req, res) => {
338340
? [layout.query.filter, contextFilters]
339341
: [layout.query.filter],
340342
},
343+
at: at ? new Date(at) : undefined,
341344
};
342345
} else {
343346
return res.status(404).send(i18next.t('common.errors.dataNotFound'));

src/schema/inputs/layer.input.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ const LayerInputType = new GraphQLInputObjectType({
168168
},
169169
datasource: { type: LayerDataSourceInputType },
170170
contextFilters: { type: GraphQLString },
171+
at: { type: GraphQLString },
171172
}),
172173
});
173174

src/schema/query/recordsAggregation.query.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { logger } from '@services/logger.service';
2222
import buildCalculatedFieldPipeline from '../../utils/aggregation/buildCalculatedFieldPipeline';
2323
import checkPageSize from '@utils/schema/errors/checkPageSize.util';
2424
import { accessibleBy } from '@casl/mongoose';
25+
import { GraphQLDate } from 'graphql-scalars';
2526

2627
/** Pagination default items per query */
2728
const DEFAULT_FIRST = 10;
@@ -63,6 +64,66 @@ const extractSourceFields = (filter: any, fields: string[] = []) => {
6364
}
6465
};
6566

67+
/**
68+
* Build At aggregation, filtering out items created after this date, and using version that matches date
69+
*
70+
* @param at Date
71+
* @returns At aggregation
72+
*/
73+
const getAtAggregation = (at: Date) => {
74+
return [
75+
{
76+
$match: {
77+
createdAt: {
78+
$lte: at,
79+
},
80+
},
81+
},
82+
{
83+
$lookup: {
84+
from: 'versions',
85+
localField: 'versions',
86+
foreignField: '_id',
87+
pipeline: [
88+
{
89+
$match: {
90+
createdAt: {
91+
$lte: at,
92+
},
93+
},
94+
},
95+
{
96+
$sort: {
97+
createdAt: -1,
98+
},
99+
},
100+
{
101+
$limit: 1,
102+
},
103+
],
104+
as: '__version',
105+
},
106+
},
107+
{
108+
$unwind: {
109+
path: '$__version',
110+
preserveNullAndEmptyArrays: true,
111+
},
112+
},
113+
{
114+
$addFields: {
115+
data: {
116+
$cond: {
117+
if: { $ifNull: ['$__version', false] },
118+
then: '$__version.data',
119+
else: '$data',
120+
},
121+
},
122+
},
123+
},
124+
];
125+
};
126+
66127
/**
67128
* Take an aggregation configuration as parameter.
68129
* Return aggregated records data.
@@ -78,6 +139,7 @@ export default {
78139
skip: { type: GraphQLInt },
79140
sortField: { type: GraphQLString },
80141
sortOrder: { type: GraphQLString },
142+
at: { type: GraphQLDate },
81143
},
82144
async resolve(parent, args, context) {
83145
// Make sure that the page size is not too important
@@ -481,6 +543,7 @@ export default {
481543
$and: [mongooseFilter, permissionFilters],
482544
},
483545
},
546+
...(args.at ? getAtAggregation(new Date(args.at)) : []),
484547
]
485548
);
486549
// Build pipeline stages

src/schema/types/layer.type.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ export const LayerType = new GraphQLObjectType({
187187
layerType: { type: LayerTypeEnum },
188188
datasource: { type: LayerDatasource },
189189
contextFilters: { type: GraphQLString },
190+
at: { type: GraphQLString },
190191
}),
191192
});
192193

src/utils/query/queryBuilder.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,14 +146,15 @@ export const buildQuery = (query: any): any => {
146146
if (query && query.fields.length > 0) {
147147
const fields = ['canUpdate\ncanDelete\n'].concat(buildFields(query.fields));
148148
const gqlQuery = `
149-
query GetCustomQuery($first: Int, $skip: Int, $filter: JSON, $sortField: String, $sortOrder: String, $display: Boolean) {
149+
query GetCustomQuery($first: Int, $skip: Int, $filter: JSON, $sortField: String, $sortOrder: String, $display: Boolean, $at: Date) {
150150
${query.name}(
151151
first: $first,
152152
skip: $skip,
153153
sortField: $sortField,
154154
sortOrder: $sortOrder,
155155
filter: $filter,
156156
display: $display
157+
at: $at
157158
) {
158159
edges {
159160
node {

src/utils/schema/resolvers/Query/all.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ export default (entityName: string, fieldsByName: any, idsByName: any) =>
431431
if (skip || skip === 0) {
432432
const aggregation = await Record.aggregate([
433433
{ $match: basicFilters },
434-
...(at ? getAtAggregation(at) : []),
434+
...(at ? getAtAggregation(new Date(at)) : []),
435435
...linkedRecordsAggregation,
436436
...linkedReferenceDataAggregation,
437437
...defaultRecordAggregation,

0 commit comments

Comments
 (0)