Skip to content

Commit 72c27ef

Browse files
committed
Change API for custom mutations and queries
and added multiple field
1 parent 5a0478c commit 72c27ef

File tree

7 files changed

+147
-77
lines changed

7 files changed

+147
-77
lines changed

dist/vuex-orm-apollo.esm.js

Lines changed: 54 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -10551,22 +10551,32 @@ var Mutate = /** @class */ (function (_super) {
1055110551
/**
1055210552
* @param {any} state The Vuex state
1055310553
* @param {DispatchFunction} dispatch Vuex Dispatch method for the model
10554+
* @param {string} name Name of the query
10555+
* @param {boolean} multiple Fetch one or multiple?
1055410556
* @param {Arguments} args Arguments for the mutation. Must contain a 'mutation' field.
1055510557
* @returns {Promise<Data>} The new record if any
1055610558
*/
10557-
Mutate.call = function (_a, args) {
10559+
Mutate.call = function (_a, _b) {
1055810560
var state = _a.state, dispatch = _a.dispatch;
10561+
var args = _b.args, multiple = _b.multiple, name = _b.name;
1055910562
return __awaiter$5(this, void 0, void 0, function () {
10560-
var model, mutationName;
10561-
return __generator$5(this, function (_b) {
10562-
model = this.getModelFromState(state);
10563-
mutationName = args['mutation'];
10564-
delete args['mutation'];
10565-
// There could be anything in the args, but we have to be sure that all records are gone through
10566-
// transformOutgoingData()
10567-
this.transformArgs(args);
10568-
// Send the mutation
10569-
return [2 /*return*/, Action.mutation(mutationName, args, dispatch, model, !args['id'])];
10563+
var model;
10564+
return __generator$5(this, function (_c) {
10565+
if (name) {
10566+
model = this.getModelFromState(state);
10567+
args = this.prepareArgs(args);
10568+
// There could be anything in the args, but we have to be sure that all records are gone through
10569+
// transformOutgoingData()
10570+
this.transformArgs(args);
10571+
if (multiple === undefined)
10572+
multiple = !args['id'];
10573+
// Send the mutation
10574+
return [2 /*return*/, Action.mutation(name, args, dispatch, model, multiple)];
10575+
}
10576+
else {
10577+
throw new Error("The mutate action requires the mutation name ('mutation') to be set");
10578+
}
10579+
return [2 /*return*/];
1057010580
});
1057110581
});
1057210582
};
@@ -10824,30 +10834,34 @@ var Query = /** @class */ (function (_super) {
1082410834
/**
1082510835
* @param {any} state The Vuex state
1082610836
* @param {DispatchFunction} dispatch Vuex Dispatch method for the model
10827-
* @param {ActionParams} params Optional params to send with the query
10837+
* @param {string} name Name of the query
10838+
* @param {boolean} multiple Fetch one or multiple?
10839+
* @param {object} filter Filter object (arguments)
10840+
* @param {boolean} bypassCache Whether to bypass the cache
1082810841
* @returns {Promise<Data>} The fetched records as hash
1082910842
*/
10830-
Query.call = function (_a, params) {
10843+
Query.call = function (_a, _b) {
1083110844
var state = _a.state, dispatch = _a.dispatch;
10845+
var name = _b.name, multiple = _b.multiple, filter = _b.filter, bypassCache = _b.bypassCache;
1083210846
return __awaiter$8(this, void 0, void 0, function () {
10833-
var context, model, filter, bypassCache, multiple, name_1, query, data;
10834-
return __generator$8(this, function (_b) {
10835-
switch (_b.label) {
10847+
var context, model, query, data;
10848+
return __generator$8(this, function (_c) {
10849+
switch (_c.label) {
1083610850
case 0:
10837-
if (!(params && params.query)) return [3 /*break*/, 2];
10851+
if (!name) return [3 /*break*/, 2];
1083810852
context = Context.getInstance();
1083910853
model = this.getModelFromState(state);
10840-
filter = params && params.filter ? Transformer.transformOutgoingData(model, params.filter) : {};
10841-
bypassCache = params && params.bypassCache;
10842-
multiple = !filter['id'];
10843-
name_1 = params.query;
10844-
query = QueryBuilder.buildQuery('query', model, name_1, filter, multiple, false);
10854+
// Filter
10855+
filter = filter ? Transformer.transformOutgoingData(model, filter) : {};
10856+
if (multiple === undefined)
10857+
multiple = !filter['id'];
10858+
query = QueryBuilder.buildQuery('query', model, name, filter, multiple, false);
1084510859
return [4 /*yield*/, context.apollo.request(model, query, filter, false, bypassCache)];
1084610860
case 1:
10847-
data = _b.sent();
10861+
data = _c.sent();
1084810862
// Insert incoming data into the store
1084910863
return [2 /*return*/, Store.insertData(data, dispatch)];
10850-
case 2: throw new Error("The customQuery action requires the query name ('query') to be set");
10864+
case 2: throw new Error("The customQuery action requires the query name ('name') to be set");
1085110865
}
1085210866
});
1085310867
});
@@ -11107,32 +11121,35 @@ var VuexORMApollo = /** @class */ (function () {
1110711121
});
1110811122
});
1110911123
};
11110-
context.components.Model.customQuery = function (query, filter, bypassCache) {
11111-
if (bypassCache === void 0) { bypassCache = false; }
11124+
context.components.Model.customQuery = function (_a) {
11125+
var name = _a.name, filter = _a.filter, multiple = _a.multiple, bypassCache = _a.bypassCache;
1111211126
return __awaiter$11(this, void 0, void 0, function () {
11113-
return __generator$11(this, function (_a) {
11114-
return [2 /*return*/, this.dispatch('query', { query: query, filter: filter, bypassCache: bypassCache })];
11127+
return __generator$11(this, function (_b) {
11128+
return [2 /*return*/, this.dispatch('query', { name: name, filter: filter, multiple: multiple, bypassCache: bypassCache })];
1111511129
});
1111611130
});
1111711131
};
1111811132
// Register model convenience methods
1111911133
var model = context.components.Model.prototype;
11120-
model.$mutate = function (params) {
11134+
model.$mutate = function (_a) {
11135+
var name = _a.name, args = _a.args, multiple = _a.multiple;
1112111136
return __awaiter$11(this, void 0, void 0, function () {
11122-
return __generator$11(this, function (_a) {
11123-
if (!params['id'])
11124-
params['id'] = this.id;
11125-
return [2 /*return*/, this.$dispatch('mutate', params)];
11137+
return __generator$11(this, function (_b) {
11138+
args = args || {};
11139+
if (!args['id'])
11140+
args['id'] = this.id;
11141+
return [2 /*return*/, this.$dispatch('mutate', { name: name, args: args, multiple: multiple })];
1112611142
});
1112711143
});
1112811144
};
11129-
model.$customQuery = function (query, filter, bypassCache) {
11130-
if (bypassCache === void 0) { bypassCache = false; }
11145+
model.$customQuery = function (_a) {
11146+
var name = _a.name, filter = _a.filter, multiple = _a.multiple, bypassCache = _a.bypassCache;
1113111147
return __awaiter$11(this, void 0, void 0, function () {
11132-
return __generator$11(this, function (_a) {
11148+
return __generator$11(this, function (_b) {
11149+
filter = filter || {};
1113311150
if (!filter['id'])
1113411151
filter['id'] = this.id;
11135-
return [2 /*return*/, this.$dispatch('query', { query: query, filter: filter, bypassCache: bypassCache })];
11152+
return [2 /*return*/, this.$dispatch('query', { name: name, filter: filter, multiple: multiple, bypassCache: bypassCache })];
1113611153
});
1113711154
});
1113811155
};

docs/guide/custom-queries/README.md

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ method Vuex-ORM.
2626

2727
```javascript
2828
const post = Post.query().first();
29-
await post.$customQuery({ query: 'example' });
29+
await post.$customQuery({ name: 'example' });
3030

3131
// is the same as
32-
await Post.customQuery({ query: 'example', id: post.id });
32+
await Post.customQuery({ name: 'example', filter: { id: post.id } });
3333

3434
// or
35-
await Post.dispatch('query', { query: 'example', id: post.id });
35+
await Post.dispatch('query', { name: 'example', filter: { id: post.id } });
3636
```
3737

3838
As you can see you have to provide the query name and any further arguments you want to pass. In this case we send
@@ -73,6 +73,13 @@ Variables:
7373
Like for all other operations, all records which are returned replace the respective existing records in the Vuex-ORM
7474
database.
7575

76+
Following fields are allowed:
77+
78+
- `name`: Required. The name of the query.
79+
- `multiple`: Whether the query is of a connection type (multiple records are returned) or not (single record is returned).
80+
- `filter`: Hash map with filters. These are passed as a filter typed variable like in fetch.
81+
- `bypassCache`: Whether to bypass the caching.
82+
7683

7784
## Model unrelated simple query
7885

@@ -104,20 +111,26 @@ The result contains a hash which is shaped like the request:
104111

105112
Nothing is inserted in the Vuex store.
106113

114+
Following fields are allowed:
115+
116+
- `query`: Required. The GraphQL query.
117+
- `variables`: Variables to pass
118+
- `bypassCache`: Whether to bypass the caching.
119+
107120

108121
## Model related custom mutation
109122

110123
Along with the CRUD mutations you may want to send custom GraphQL mutations. We support this via the `mutate` action:
111124

112125
```javascript
113126
const post = Post.query().first();
114-
await post.$mutate({ mutation: 'upvotePost' });
127+
await post.$mutate({ name: 'upvotePost' });
115128

116129
// is the same as
117-
await Post.mutate({ mutation: 'upvotePost', id: post.id });
130+
await Post.mutate({ name: 'upvotePost', args: { id: post.id } });
118131

119132
// or
120-
await Post.dispatch('mutate', { mutation: 'upvotePost', id: post.id });
133+
await Post.dispatch('mutate', { name: 'upvotePost', args: { id: post.id } });
121134
```
122135

123136
As you can see you have to provide the mutation name and any further arguments you want to pass. In this case we send
@@ -160,6 +173,13 @@ Like for all other operations, all records which are returned replace the respec
160173
database.
161174

162175

176+
Following fields are allowed:
177+
178+
- `name`: Required. The name of the mutation.
179+
- `multiple`: Whether the mutation is of a connection type (multiple records are returned) or not (single record is returned).
180+
- `args`: Hash map with arguments (variables).
181+
182+
163183
## Model unrelated simple mutation
164184

165185
Like simple custom queries, you can also send simple custom mutations. The action (`simpleQuery`) stays the same.
@@ -191,3 +211,23 @@ The result contains a hash which is shaped like the request:
191211
```
192212

193213
Nothing is inserted in the Vuex store.
214+
215+
Following fields are allowed:
216+
217+
- `query`: Required. The GraphQL mutation query.
218+
- `variables`: Hash map with variables to pass.
219+
220+
221+
## Multiple or single record
222+
223+
Vuex-ORM-Apollo tries to determine automatically if a single record or a connection (multiple records) is returned by
224+
a query/mutation via checking if a `id` field is set in the filter/args/variables. But sometimes you have a
225+
query/mutation without ID but it still returns a single record or vice versa. For this case you can manually set the
226+
`multiple` field to tell the plugin how the result is shaped:
227+
228+
```javascript
229+
await Post.customQuery({ name: 'example', multiple: true, filter: { id: post.id } });
230+
```
231+
232+
In future versions of this project this might be obsolete because it could consume and analyze the schema to know
233+
how the queries and mutations are shaped.

src/actions/mutate.ts

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,26 @@ export default class Mutate extends Action {
88
/**
99
* @param {any} state The Vuex state
1010
* @param {DispatchFunction} dispatch Vuex Dispatch method for the model
11+
* @param {string} name Name of the query
12+
* @param {boolean} multiple Fetch one or multiple?
1113
* @param {Arguments} args Arguments for the mutation. Must contain a 'mutation' field.
1214
* @returns {Promise<Data>} The new record if any
1315
*/
14-
public static async call ({ state, dispatch }: ActionParams, args: Arguments): Promise<Data> {
15-
const model = this.getModelFromState(state);
16-
const mutationName: string = args['mutation'];
17-
delete args['mutation'];
16+
public static async call ({ state, dispatch }: ActionParams, { args, multiple, name }: ActionParams): Promise<Data> {
17+
if (name) {
18+
const model = this.getModelFromState(state);
19+
args = this.prepareArgs(args);
1820

19-
// There could be anything in the args, but we have to be sure that all records are gone through
20-
// transformOutgoingData()
21-
this.transformArgs(args);
21+
// There could be anything in the args, but we have to be sure that all records are gone through
22+
// transformOutgoingData()
23+
this.transformArgs(args);
2224

23-
// Send the mutation
24-
return Action.mutation(mutationName, args, dispatch, model, !args['id']);
25+
if (multiple === undefined) multiple = !args['id'];
26+
27+
// Send the mutation
28+
return Action.mutation(name, args, dispatch, model, multiple);
29+
} else {
30+
throw new Error("The mutate action requires the mutation name ('mutation') to be set");
31+
}
2532
}
2633
}

src/actions/query.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,33 @@ export default class Query extends Action {
1313
/**
1414
* @param {any} state The Vuex state
1515
* @param {DispatchFunction} dispatch Vuex Dispatch method for the model
16-
* @param {ActionParams} params Optional params to send with the query
16+
* @param {string} name Name of the query
17+
* @param {boolean} multiple Fetch one or multiple?
18+
* @param {object} filter Filter object (arguments)
19+
* @param {boolean} bypassCache Whether to bypass the cache
1720
* @returns {Promise<Data>} The fetched records as hash
1821
*/
19-
public static async call ({ state, dispatch }: ActionParams, params?: ActionParams): Promise<Data> {
20-
if (params && params.query) {
22+
public static async call ({ state, dispatch }: ActionParams,
23+
{ name, multiple, filter, bypassCache }: ActionParams): Promise<Data> {
24+
if (name) {
2125
const context = Context.getInstance();
2226
const model = this.getModelFromState(state);
2327

2428
// Filter
25-
const filter = params && params.filter ? Transformer.transformOutgoingData(model, params.filter) : {};
26-
const bypassCache = params && params.bypassCache;
29+
filter = filter ? Transformer.transformOutgoingData(model, filter) : {};
2730

28-
// When the filter contains an id, we query in singular mode
29-
const multiple: boolean = !filter['id'];
30-
const name: string = params.query;
31-
const query = QueryBuilder.buildQuery('query', model, name, filter, multiple, false);
31+
if (multiple === undefined) multiple = !filter['id'];
32+
33+
// Build query
34+
const query = QueryBuilder.buildQuery('query', model, name, filter, multiple, false);
3235

3336
// Send the request to the GraphQL API
3437
const data = await context.apollo.request(model, query, filter, false, bypassCache as boolean);
3538

3639
// Insert incoming data into the store
3740
return Store.insertData(data, dispatch);
3841
} else {
39-
throw new Error("The customQuery action requires the query name ('query') to be set");
42+
throw new Error("The customQuery action requires the query name ('name') to be set");
4043
}
4144
}
4245
}

src/support/interfaces.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ export interface ActionParams {
2727
variables?: Arguments;
2828
bypassCache?: boolean;
2929
query?: string;
30+
multiple?: boolean;
31+
name?: string;
3032
}
3133

3234
export interface Data {
@@ -50,6 +52,6 @@ export interface Field {
5052

5153
export class PatchedModel extends ORMModel {
5254
static async fetch (filter: any, bypassCache: boolean = false): Promise<any> { return undefined; }
53-
static async mutate (params: any): Promise<any> { return undefined; }
54-
static async customQuery (query: string, params: any, bypassCache: boolean = false): Promise<any> { return undefined; }
55+
static async mutate (params: ActionParams): Promise<any> { return undefined; }
56+
static async customQuery (params: ActionParams): Promise<any> { return undefined; }
5557
}

src/vuex-orm-apollo.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { PatchedModel, Options } from './support/interfaces';
1+
import {PatchedModel, Options, ActionParams} from './support/interfaces';
22
import Context from './common/context';
33
import { Components } from '@vuex-orm/core/lib/plugins/use';
44
import { Destroy, Fetch, Mutate, Persist, Push } from './actions';
@@ -52,26 +52,27 @@ export default class VuexORMApollo {
5252
return this.dispatch('fetch', { filter: filterObj, bypassCache });
5353
};
5454

55-
(context.components.Model as (typeof PatchedModel)).mutate = async function (params: any) {
55+
(context.components.Model as (typeof PatchedModel)).mutate = async function (params: ActionParams) {
5656
return this.dispatch('mutate', params);
5757
};
5858

59-
(context.components.Model as (typeof PatchedModel)).customQuery = async function (query: string, filter: any,
60-
bypassCache = false) {
61-
return this.dispatch('query', { query, filter, bypassCache });
59+
(context.components.Model as (typeof PatchedModel)).customQuery = async function ({ name, filter, multiple, bypassCache }: ActionParams) {
60+
return this.dispatch('query', { name, filter, multiple, bypassCache });
6261
};
6362

6463
// Register model convenience methods
6564
const model = context.components.Model.prototype;
6665

67-
model.$mutate = async function (params: any) {
68-
if (!params['id']) params['id'] = this.id;
69-
return this.$dispatch('mutate', params);
66+
model.$mutate = async function ({ name, args, multiple }: ActionParams) {
67+
args = args || {};
68+
if (!args['id']) args['id'] = this.id;
69+
return this.$dispatch('mutate', { name, args, multiple });
7070
};
7171

72-
model.$customQuery = async function (query: string, filter: any, bypassCache: boolean = false) {
72+
model.$customQuery = async function ({ name, filter, multiple, bypassCache }: ActionParams) {
73+
filter = filter || {};
7374
if (!filter['id']) filter['id'] = this.id;
74-
return this.$dispatch('query', { query, filter, bypassCache });
75+
return this.$dispatch('query', { name, filter, multiple, bypassCache });
7576
};
7677

7778
model.$persist = async function (args: any) {

0 commit comments

Comments
 (0)