Skip to content

Commit 5814507

Browse files
committed
Alpha version
1 parent 38925f1 commit 5814507

File tree

10 files changed

+532
-146
lines changed

10 files changed

+532
-146
lines changed

package-lock.json

+238-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+11-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vue-model",
3-
"version": "0.0.2",
3+
"version": "0.1.0",
44
"description": "A library based on Model-Repository patterns for Vue components. Usable for GraphQL and RESTful APIs.",
55
"keywords": [
66
"collections",
@@ -33,7 +33,7 @@
3333
"bundlesize": "npm run build && bundlesize",
3434
"dev": "tsc -w",
3535
"test": "NODE_ENV=test nyc --reporter lcovonly --reporter=text --reporter=text-summary mocha && codecov",
36-
"test:watch": "mocha -w ./test/*.spec.js"
36+
"test:watch": "mocha -w"
3737
},
3838
"dependencies": {
3939
"clone": "^2.1.2",
@@ -51,6 +51,8 @@
5151
"@types/mocha": "^5.2.7",
5252
"@types/node": "^12.7.8",
5353
"@types/uuid": "^3.4.5",
54+
"@types/fetch-mock": "^7.3.1",
55+
"@types/vue": "^2.0.0",
5456
"bundlesize": "^0.18.0",
5557
"chai": "^4.2.0",
5658
"danger": "^9.2.1",
@@ -59,11 +61,16 @@
5961
"ts-node": "^8.4.1",
6062
"typescript": "^3.6.3",
6163
"vue": "^2.6.10",
62-
"vue-apollo": "^3.0.0-rc.7"
64+
"vue-apollo": "^3.0.0-rc.7",
65+
"apollo-client": "^2.4.1",
66+
"apollo-link-http-common": "^0.2.15",
67+
"chai-fetch-mock": "^2.0.0",
68+
"fetch-mock": "^7.4.0"
6369
},
6470
"peerDependencies": {
6571
"vue": "^2.6.10",
66-
"vue-apollo": "^3.0.0-rc.7"
72+
"vue-apollo": "^3.0.0-rc.7",
73+
"apollo-client": "^2.4.1"
6774
},
6875
"publishConfig": {
6976
"registry": "https://npm.pkg.github.com/@matrunchyk"

src/index.ts

+48-15
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,68 @@
1-
import Vue, {PluginObject} from 'vue';
1+
import _Vue from 'vue';
22
import BaseModel from './models/BaseModel';
33
import BaseRepository from './repositories/BaseRepository';
44
import Container from './Container';
5-
import {Config} from '@/typings';
5+
import * as Utils from './utils';
66

77
const container = Container.getInstance();
88

99
container.set('BaseModel', BaseModel);
1010
container.set('BaseRepository', BaseRepository);
1111

12-
export default class VueModel implements PluginObject<Config> {
13-
[key: string]: any;
12+
export class VueModelOptions {
13+
/**
14+
* Use REST plugin.
15+
*
16+
* @type {boolean}
17+
*/
18+
rest = true;
1419

15-
install(pVue: typeof Vue, defaultConfig: Config = {}) {
16-
const config = {
17-
rest: true,
18-
graphql: false,
19-
...defaultConfig,
20-
};
20+
/**
21+
* Use GraphQL plugin
22+
*
23+
* @type {boolean}
24+
*/
25+
graphql = false;
2126

22-
container.set('Vue', pVue);
23-
container.set('Config', config);
27+
/**
28+
* GraphQL Schema to parse for update variables guesser.
29+
*
30+
* @type {null}
31+
*/
32+
schema: string = null;
2433

25-
pVue.prototype.$container = container;
26-
}
27-
};
34+
/**
35+
* Debug mode
36+
*
37+
* @type {boolean}
38+
*/
39+
debug = false;
40+
}
2841

42+
function VueModel<VueModelOptions>(Vue: typeof _Vue, options?: VueModelOptions): void {
43+
const config = {
44+
rest: true,
45+
graphql: false,
46+
schema: null,
47+
debug: false,
48+
...options,
49+
};
50+
51+
container.set('Vue', Vue);
52+
container.set('Config', config);
53+
54+
Vue.prototype.$container = container;
55+
}
56+
57+
export default VueModel;
2958
export {default as Container} from './Container';
3059
export {default as BaseRepository} from './repositories/BaseRepository';
3160
export {default as BaseModel} from './models/BaseModel';
3261
export {default as Collection} from './models/Collection';
3362
export {default as BaseException} from './models/Exceptions/BaseException';
3463
export {default as InvalidArgumentException} from './models/Exceptions/InvalidArgumentException';
3564
export {default as UnexpectedException} from './models/Exceptions/UnexpectedException';
65+
export {default as UnauthorizedException} from './models/Exceptions/UnauthorizedException';
66+
export {default as ValidationException} from './models/Exceptions/ValidationException';
67+
export {Utils, VueModel};
68+

src/models/BaseModel.ts

+6-40
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,9 @@
11
import camelCase from 'lodash.camelcase';
22
import clone from 'clone';
33
import uuid from 'uuid';
4-
import {performSafeRequestREST, performSafeRequestGraphql, config, getSchemaTypeFields} from '@/utils';
4+
import getUrl, {performSafeRequestREST, performSafeRequestGraphql, config, getSchemaTypeFields} from '@/utils';
55
import Collection from './Collection';
6-
7-
type KeyValueString = { [key: string]: string };
8-
9-
type UrlResolver = (params?: KeyValueString, collection?: boolean) => string;
10-
11-
type ResolvingRESTOptions = {
12-
method: string;
13-
url: string | UrlResolver;
14-
params: unknown;
15-
}
6+
import {ResolvingRESTOptions} from '@/typings';
167

178
export default abstract class BaseModel {
189
public id: string;
@@ -31,7 +22,8 @@ export default abstract class BaseModel {
3122

3223
protected performSafeRequestREST = performSafeRequestREST;
3324

34-
protected constructor(props) {
25+
//noinspection TypeScriptAbstractClassConstructorCanBeMadeProtected
26+
public constructor(props = {}) {
3527
//@ts-ignore
3628
if (typeof this.defaults === 'function') {
3729
console.warn('Deprecated: Use property variables or constructor instead. `defaults` will be removed in the next versions.');
@@ -101,32 +93,6 @@ export default abstract class BaseModel {
10193
return null;
10294
}
10395

104-
protected async getUrl(_opts: ResolvingRESTOptions) {
105-
const {url, params} = _opts;
106-
let resolvedUrl = url;
107-
108-
if (typeof url === 'function') {
109-
resolvedUrl = await url();
110-
} else {
111-
resolvedUrl = (resolvedUrl as string).replace(
112-
/:([^\s\/]+)/gi,
113-
(_, m) => {
114-
const param = params[m];
115-
const hasParam = param !== undefined;
116-
117-
if (hasParam) {
118-
delete params[m];
119-
return param;
120-
}
121-
122-
return m;
123-
},
124-
);
125-
}
126-
127-
return resolvedUrl;
128-
}
129-
13096
public toCollection(skipEmpty = false) {
13197
return (new Collection(this)).filter(i => !!i || !skipEmpty);
13298
}
@@ -196,11 +162,11 @@ export default abstract class BaseModel {
196162
public async mutate(mutationOrUrl, params, method = this.defaultMethod) {
197163
if (config().graphql) {
198164
return this.beforeMutate()
199-
.then(this.performSafeRequestGraphql.bind(this, mutationOrUrl, params))
165+
.then(this.performSafeRequestGraphql.bind(this, mutationOrUrl, params, null))
200166
.finally(this.afterMutate.bind(this));
201167
}
202168

203-
const resolvedUrl = await this.getUrl({method, url: mutationOrUrl, params});
169+
const resolvedUrl = await getUrl({method, url: mutationOrUrl, params});
204170
const resolvedMethod = await this.getMethod({method, url: resolvedUrl, params});
205171

206172
return this.beforeMutate()

src/repositories/BaseRepository.ts

+9-74
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,11 @@
1-
import {GraphQLError} from 'graphql';
1+
import {GraphQLError, DocumentNode} from 'graphql';
22
import InvalidArgumentException from '../models/Exceptions/InvalidArgumentException';
33
import Collection from '../models/Collection';
4-
import {config, performSafeRequestREST, performSafeRequestGraphql} from '@/utils';
4+
import getUrl, {config, performSafeRequestREST, performSafeRequestGraphql} from '@/utils';
55
import UnexpectedException from '@/models/Exceptions/UnexpectedException';
66
import ValidationException from '@/models/Exceptions/ValidationException';
77
import UnauthorizedException from '@/models/Exceptions/UnauthorizedException';
8-
9-
type KeyValueString = { [key: string]: string };
10-
11-
type UrlResolver = (params?: KeyValueString, collection?: boolean) => string;
12-
13-
type ResolvingRESTOptions = {
14-
method: string;
15-
url: string | UrlResolver;
16-
params: unknown;
17-
}
18-
19-
type PropertyFunction<T> = () => T;
20-
21-
type HttpMethod = 'get' | 'post' | 'put' | 'delete' | 'patch';
22-
23-
type GraphQLErrorType = {
24-
extensions: {
25-
errorCode: number,
26-
message: string,
27-
},
28-
}
29-
30-
type GraphQLErrorBag = {
31-
graphQLErrors: GraphQLErrorType[];
32-
}
33-
34-
export type EventType = {
35-
type: string;
36-
target: unknown;
37-
payload?: unknown;
38-
};
39-
40-
type EventSubscriber = {
41-
fired?: boolean;
42-
immediate: boolean;
43-
callback: (event: EventType) => void;
44-
};
45-
46-
type EventListeners = {
47-
[key: string]: EventSubscriber[];
48-
}
8+
import {EventListeners, EventType, GraphQLErrorBag, KeyValueString, PropertyFunction, ResolvingRESTOptions, UrlResolver, HttpMethod} from '@/typings';
499

5010
export default abstract class BaseRepository<M = unknown> {
5111
/**
@@ -94,7 +54,8 @@ export default abstract class BaseRepository<M = unknown> {
9454
*/
9555
public queryParams: KeyValueString = {};
9656

97-
public subscriptions() {
57+
public subscriptions(): unknown[] {
58+
return [];
9859
}
9960

10061
/**
@@ -160,32 +121,6 @@ export default abstract class BaseRepository<M = unknown> {
160121
return null;
161122
}
162123

163-
protected async getUrl(_opts: ResolvingRESTOptions) {
164-
const {url, params} = _opts;
165-
let resolvedUrl = url;
166-
167-
if (typeof url === 'function') {
168-
resolvedUrl = await url();
169-
} else {
170-
resolvedUrl = (resolvedUrl as string).replace(
171-
/:([^\s\/]+)/gi,
172-
(_, m) => {
173-
const param = params[m];
174-
const hasParam = param !== undefined;
175-
176-
if (hasParam) {
177-
delete params[m];
178-
return param;
179-
}
180-
181-
return m;
182-
},
183-
);
184-
}
185-
186-
return resolvedUrl;
187-
}
188-
189124
public fromArray(array: unknown[], skipEmpty = true) {
190125
//@ts-ignore
191126
return new Collection(array.filter(i => i || !skipEmpty).map(i => new this.model(i)));
@@ -235,12 +170,12 @@ export default abstract class BaseRepository<M = unknown> {
235170
* @param {string} method
236171
* @returns {Promise<Collection|BaseModel>}
237172
*/
238-
public async query(queryOrUrl: string | UrlResolver, params: KeyValueString = {}, collection = false, method: HttpMethod = this.defaultMethod) {
173+
public async query(queryOrUrl: string | UrlResolver | DocumentNode, params: KeyValueString = {}, collection = false, method: HttpMethod = this.defaultMethod) {
239174
if (config().graphql) {
240-
let doc = queryOrUrl;
175+
let doc = queryOrUrl as unknown as DocumentNode;
241176

242177
if (typeof queryOrUrl === 'function') {
243-
doc = await queryOrUrl();
178+
doc = await queryOrUrl() as unknown as DocumentNode;
244179
}
245180

246181
return this.beforeQuery()
@@ -252,7 +187,7 @@ export default abstract class BaseRepository<M = unknown> {
252187

253188
this.method = method;
254189

255-
const resolvedUrl = await this.getUrl({method, url: queryOrUrl, params});
190+
const resolvedUrl = await getUrl({method, url: queryOrUrl as string, params});
256191
const resolvedMethod = await this.getMethod({method, url: resolvedUrl, params});
257192

258193
return this.beforeQuery()

src/typings.d.ts

+41
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,44 @@ export type Config = {
33
rest?: boolean;
44
}
55

6+
export type KeyValueString = { [key: string]: string };
7+
8+
export type UrlResolver = (params?: KeyValueString, collection?: boolean) => string;
9+
10+
export type ResolvingRESTOptions = {
11+
method: string;
12+
url: string | UrlResolver;
13+
params: unknown;
14+
}
15+
16+
export type PropertyFunction<T> = () => T;
17+
18+
export type HttpMethod = 'get' | 'post' | 'put' | 'delete' | 'patch';
19+
20+
export type GraphQLErrorType = {
21+
extensions: {
22+
errorCode: number,
23+
message: string,
24+
},
25+
}
26+
27+
export type GraphQLErrorBag = {
28+
graphQLErrors: GraphQLErrorType[];
29+
}
30+
31+
export type EventType = {
32+
type: string;
33+
target: unknown;
34+
payload?: unknown;
35+
};
36+
37+
export type EventSubscriber = {
38+
fired?: boolean;
39+
immediate: boolean;
40+
callback: (event: EventType) => void;
41+
};
42+
43+
export type EventListeners = {
44+
[key: string]: EventSubscriber[];
45+
}
46+

0 commit comments

Comments
 (0)