Skip to content

Commit

Permalink
Allow for explicit "singular" requests (queries / transforms)
Browse files Browse the repository at this point in the history
`Query#expressions` now accepts either a single expression or an array of expressions.

Likewise, `Transform#operations` now accepts either a single operation or an array of operations.

This allows more explicit control over the form in which results will be returned. Data will always be returned in an array when an array is used to express expressions / operations.
  • Loading branch information
dgeb committed Jul 3, 2021
1 parent 662598b commit ed9735e
Show file tree
Hide file tree
Showing 37 changed files with 593 additions and 532 deletions.
20 changes: 12 additions & 8 deletions packages/@orbit/data/src/query.ts
Expand Up @@ -5,10 +5,14 @@ import { QueryExpression } from './query-expression';

/**
* Queries are used to extract data from a source.
*
* Each query's `expressions` must be a query expression or an array of
* expressions. This distinction allows for a clear distinction between queries
* that return singular vs. arrayed results.
*/
export interface Query<QE extends QueryExpression> {
id: string;
expressions: QE[];
expressions: QE | QE[];
options?: RequestOptions;
}

Expand Down Expand Up @@ -51,7 +55,7 @@ export function buildQuery<QE extends QueryExpression, QB = unknown>(
);
} else {
let query = queryOrExpressions as Query<QE>;
let expressions: QE[];
let expressions: QE | QE[];
let options: RequestOptions | undefined;
let id: string;

Expand All @@ -73,13 +77,13 @@ export function buildQuery<QE extends QueryExpression, QB = unknown>(
} else {
if (Array.isArray(queryOrExpressions)) {
expressions = [];
for (let queryOrExpression of queryOrExpressions) {
expressions.push(toQueryExpression<QE>(queryOrExpression));
for (let qe of queryOrExpressions) {
expressions.push(toQueryExpression<QE>(qe));
}
} else {
expressions = [
toQueryExpression(queryOrExpressions as QE | QueryTerm<QE>)
];
expressions = toQueryExpression(
queryOrExpressions as QE | QueryTerm<QE>
);
}
options = queryOptions;
id = queryId ?? Orbit.uuid();
Expand Down Expand Up @@ -109,5 +113,5 @@ export function isQuery<
QE extends QueryExpression = QueryExpression,
QB = unknown
>(query: QueryOrExpressions<QE, QB>): query is Query<QE> {
return Array.isArray((query as Query<QE>).expressions);
return (query as Query<QE>).expressions !== undefined;
}
12 changes: 6 additions & 6 deletions packages/@orbit/data/src/transform.ts
Expand Up @@ -21,7 +21,7 @@ export type TransformOrOperations<O extends Operation, TB> =
*/
export interface Transform<O extends Operation> {
id: string;
operations: O[];
operations: O | O[];
options?: RequestOptions;
}

Expand Down Expand Up @@ -55,7 +55,7 @@ export function buildTransform<O extends Operation, TB = unknown>(
);
} else {
let transform = transformOrOperations as Transform<O>;
let operations: O[];
let operations: O | O[];
let options: RequestOptions | undefined;
let id: string;

Expand All @@ -77,11 +77,11 @@ export function buildTransform<O extends Operation, TB = unknown>(
} else {
if (Array.isArray(transformOrOperations)) {
operations = [];
for (let transformOrOperation of transformOrOperations) {
operations.push(toOperation<O>(transformOrOperation));
for (let o of transformOrOperations) {
operations.push(toOperation<O>(o));
}
} else {
operations = [toOperation<O>(transformOrOperations as O)];
operations = toOperation<O>(transformOrOperations as O);
}
options = transformOptions;
id = transformId ?? Orbit.uuid();
Expand Down Expand Up @@ -110,5 +110,5 @@ function isOperationTerm<O extends Operation = Operation>(
function isTransform<O extends Operation = Operation>(
transform: TransformOrOperations<O, unknown>
): transform is Transform<O> {
return Array.isArray((transform as Transform<O>).operations);
return (transform as Transform<O>).operations !== undefined;
}
45 changes: 18 additions & 27 deletions packages/@orbit/data/test/query-test.ts
Expand Up @@ -39,9 +39,9 @@ module('buildQuery', function () {

assert.strictEqual(query.id, 'abc123', 'id was populated');
assert.strictEqual(
query.expressions[0],
query.expressions,
expression,
'expression was populated'
'expressions was populated'
);
assert.strictEqual(query.options, options, 'options was populated');
});
Expand All @@ -53,13 +53,13 @@ module('buildQuery', function () {
};
let expressions = [expression];
let options = { sources: { jsonapi: { include: 'comments' } } };
let query = buildQuery(expression, options, 'abc123');
let query = buildQuery(expressions, options, 'abc123');

assert.strictEqual(query.id, 'abc123', 'id was populated');
assert.deepEqual(
query.expressions,
expressions,
'expression was populated'
'expressions was populated'
);
assert.strictEqual(query.options, options, 'options was populated');
});
Expand All @@ -76,8 +76,8 @@ module('buildQuery', function () {
assert.strictEqual(query.id, 'abc123', 'id was populated');
assert.deepEqual(
query.expressions,
[{ op: 'findRecords', type: 'planet' }],
'expression was populated'
{ op: 'findRecords', type: 'planet' },
'expressions was populated'
);
assert.strictEqual(query.options, options, 'options was populated');
});
Expand Down Expand Up @@ -108,7 +108,7 @@ module('buildQuery', function () {
{ op: 'findRecords', type: 'planet' },
{ op: 'findRecords', type: 'moon' }
],
'expression was populated'
'expressions was populated'
);
assert.strictEqual(query.options, options, 'options was populated');
});
Expand All @@ -131,12 +131,10 @@ module('buildQuery', function () {
let query2 = buildQuery(query1, { a: '2', b: '2' }, '2');
assert.notStrictEqual(query1, query2);
assert.deepEqual(query2, {
expressions: [
{
op: 'findRecords',
type: 'planet'
}
],
expressions: {
op: 'findRecords',
type: 'planet'
},
options: {
a: '2',
b: '2',
Expand All @@ -160,8 +158,8 @@ module('buildQuery', function () {
);
assert.deepEqual(
query.expressions,
[expression],
'expression was populated'
expression,
'expressions was populated'
);
});

Expand All @@ -173,9 +171,9 @@ module('buildQuery', function () {
let queryFactory = new QueryTerm(expression);
let query = buildQuery<RecordQueryExpression>(queryFactory);
assert.strictEqual(
query.expressions[0],
query.expressions,
expression,
'expression was populated'
'expressions was populated'
);
});

Expand All @@ -189,15 +187,8 @@ module('buildQuery', function () {
type: 'moon'
};
let query = buildQuery<RecordQueryExpression>([expression1, expression2]);
assert.strictEqual(
query.expressions[0],
expression1,
'expression1 was populated'
);
assert.strictEqual(
query.expressions[1],
expression2,
'expression2 was populated'
);
let qe = query.expressions as RecordQueryExpression[];
assert.strictEqual(qe[0], expression1, 'expression1 was populated');
assert.strictEqual(qe[1], expression2, 'expression2 was populated');
});
});
24 changes: 12 additions & 12 deletions packages/@orbit/data/test/source-interfaces/pullable-test.ts
Expand Up @@ -96,7 +96,7 @@ module('@pullable', function (hooks) {

source._pull = async function (query) {
assert.equal(++order, 1, 'action performed after willPull');
assert.strictEqual(query.expressions[0], qe, 'query object matches');
assert.strictEqual(query.expressions, qe, 'query object matches');
return fullResponse;
};

Expand All @@ -116,7 +116,7 @@ module('@pullable', function (hooks) {
2,
'pull triggered after action performed successfully'
);
assert.strictEqual(query.expressions[0], qe, 'query matches');
assert.strictEqual(query.expressions, qe, 'query matches');
assert.strictEqual(result, fullResponse, 'result matches');
});

Expand Down Expand Up @@ -162,7 +162,7 @@ module('@pullable', function (hooks) {

source._pull = async function (query) {
assert.equal(++order, 4, 'action performed after willPull');
assert.strictEqual(query.expressions[0], qe, 'query object matches');
assert.strictEqual(query.expressions, qe, 'query object matches');
return fullResponse;
};

Expand All @@ -182,7 +182,7 @@ module('@pullable', function (hooks) {
5,
'pull triggered after action performed successfully'
);
assert.strictEqual(query.expressions[0], qe, 'query matches');
assert.strictEqual(query.expressions, qe, 'query matches');
assert.strictEqual(result, fullResponse, 'result matches');
});

Expand Down Expand Up @@ -226,7 +226,7 @@ module('@pullable', function (hooks) {
3,
'pullFail triggered after an unsuccessful beforePull'
);
assert.strictEqual(query.expressions[0], qe, 'query matches');
assert.strictEqual(query.expressions, qe, 'query matches');
assert.equal(error, ':(', 'error matches');
});

Expand All @@ -246,7 +246,7 @@ module('@pullable', function (hooks) {

source._pull = function (query) {
assert.equal(++order, 1, 'action performed after willPull');
assert.strictEqual(query.expressions[0], qe, 'query object matches');
assert.strictEqual(query.expressions, qe, 'query object matches');
return Promise.reject(':(');
};

Expand All @@ -256,7 +256,7 @@ module('@pullable', function (hooks) {

source.on('pullFail', (query, error) => {
assert.equal(++order, 2, 'pullFail triggered after an unsuccessful pull');
assert.strictEqual(query.expressions[0], qe, 'query matches');
assert.strictEqual(query.expressions, qe, 'query matches');
assert.equal(error, ':(', 'error matches');
});

Expand Down Expand Up @@ -385,7 +385,7 @@ module('@pullable', function (hooks) {

source._pull = async function (query) {
assert.equal(++order, 1, 'action performed after beforeQuery');
assert.strictEqual(query.expressions[0], qe, 'query object matches');
assert.strictEqual(query.expressions, qe, 'query object matches');
return fullResponse;
};

Expand All @@ -395,7 +395,7 @@ module('@pullable', function (hooks) {
2,
'pull triggered after action performed successfully'
);
assert.strictEqual(query.expressions[0], qe, 'query matches');
assert.strictEqual(query.expressions, qe, 'query matches');
assert.deepEqual(result, fullResponse, 'result matches');
});

Expand Down Expand Up @@ -444,14 +444,14 @@ module('@pullable', function (hooks) {

source.on('beforePull', async (query) => {
assert.equal(++order, 1, 'beforePull triggered first');
assert.strictEqual(query.expressions[0], qe, 'beforePull: query matches');
assert.strictEqual(query.expressions, qe, 'beforePull: query matches');

return ['remote', { details: details1 }];
});

source._pull = async function (query) {
assert.equal(++order, 2, 'action performed after beforeQuery');
assert.strictEqual(query.expressions[0], qe, '_pull: query matches');
assert.strictEqual(query.expressions, qe, '_pull: query matches');
return {
transforms: transforms1,
details: details1
Expand All @@ -464,7 +464,7 @@ module('@pullable', function (hooks) {
3,
'pull triggered after action performed successfully'
);
assert.strictEqual(query.expressions[0], qe, 'pull: query matches');
assert.strictEqual(query.expressions, qe, 'pull: query matches');
assert.deepEqual(result, expectedResult, 'pull: result matches');
});

Expand Down

0 comments on commit ed9735e

Please sign in to comment.