Skip to content

Commit

Permalink
refactor(generic): make schema async field; plugin installation is sync
Browse files Browse the repository at this point in the history
  • Loading branch information
matrunchyk committed May 25, 2020
1 parent fe83010 commit 8df9ec1
Show file tree
Hide file tree
Showing 7 changed files with 4,952 additions and 4,517 deletions.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "vue-oop",
"version": "1.0.1-beta.8",
"version": "1.1.1",
"description": "A library based on Model-Repository patterns for Vue components. Usable for GraphQL and REST APIs.",
"keywords": [
"collections",
Expand Down Expand Up @@ -43,7 +43,8 @@
"publish-github": "npm publish --registry https://npm.pkg.github.com/@matrunchyk",
"release": "release-it",
"test": "jest --config jest.config.json",
"test:watch": "jest -w"
"test:watch": "jest -w",
"prepublishOnly": "npm run build"
},
"husky": {
"hooks": {
Expand Down
35 changes: 16 additions & 19 deletions src/graphql/apolloClient.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import { ApolloLink } from 'apollo-link';
import { defaultDataIdFromObject } from 'apollo-cache-inmemory';
import { InStorageCache, PersistLink } from 'apollo-cache-instorage';
import { PersistLink } from 'apollo-cache-instorage';
import { createApolloClient } from 'vue-cli-plugin-apollo/graphql-client';
import { IdValue } from 'apollo-utilities'
import Pusher from 'pusher-js';
import CustomHeuristicFragmentMatcher from './CustomHeuristicFragmentMatcher';
import PusherLink from './PusherLink';

Pusher.logToConsole = process.env.NODE_ENV !== 'production';
Expand All @@ -31,20 +28,20 @@ const pusherLink = new PusherLink({

const persistLink = new PersistLink();

function shouldPersist(_, dataId, data?: { __persist: boolean } & IdValue) {
if (data && data.id.includes('password')) return false;

return dataId === 'ROOT_QUERY' || (!data || !!data.__persist)
}

const cache = new InStorageCache({
dataIdFromObject: result => (result.__typename && result.uuid ? `${result.__typename}:${result.uuid}` : defaultDataIdFromObject(result)),
fragmentMatcher: new CustomHeuristicFragmentMatcher(),
// addPersistField: true,
storage: window.localStorage,
prefix: 'vue-oop-apollo',
shouldPersist,
})
// function shouldPersist(_, dataId, data?: { __persist: boolean } & IdValue) {
// if (data?.id?.includes?.('password')) return false;
//
// return dataId === 'ROOT_QUERY' || (!data || !!data.__persist)
// }

// const cache = new InStorageCache({
// dataIdFromObject: result => (result.__typename && result.uuid ? `${result.__typename}:${result.uuid}` : defaultDataIdFromObject(result)),
// fragmentMatcher: new CustomHeuristicFragmentMatcher(),
// // addPersistField: true,
// storage: window.localStorage,
// prefix: 'vue-oop-apollo',
// shouldPersist,
// });

const link = ApolloLink.from([
persistLink,
Expand All @@ -56,7 +53,7 @@ const { apolloClient, wsClient } = createApolloClient({
tokenName: AUTH_TOKEN,
link,
connectToDevTools: process.env.NODE_ENV !== 'production',
cache,
// cache,
});

export {
Expand Down
40 changes: 25 additions & 15 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,12 @@
* Released under the MIT License.
*/
import _Vue from 'vue';
import Model from './models/Model';
import Repository from './repositories/Repository';
import Registry from './Registry';
import * as Utils from './utils';
import { DocumentNode, buildClientSchema, printSchema } from 'graphql';
import { parse } from 'graphql/language/parser';
import { fetchIntrospectionSchema } from './utils';

const registry = Registry.getInstance();

registry.set('Model', Model);
registry.set('Repository', Repository);

export interface IVueOOPOptions {
rest?: boolean;
graphql?: boolean;
Expand Down Expand Up @@ -66,7 +59,7 @@ export class VueOOPOptions implements IVueOOPOptions {
createProvider?: () => unknown;
}

async function VueOOP<VueOOPOptions>(Vue: typeof _Vue, options?: VueOOPOptions): Promise<void> {
function VueOOP<VueOOPOptions>(Vue: typeof _Vue, options?: VueOOPOptions) {
const config = {
rest: true,
graphql: false,
Expand All @@ -77,15 +70,32 @@ async function VueOOP<VueOOPOptions>(Vue: typeof _Vue, options?: VueOOPOptions):
...options,
} as IVueOOPOptions;

if (config.schemaUrl && config.debug) {
config.schema = await fetchIntrospectionSchema(config.schemaUrl)
.then(buildClientSchema.bind(null))
.then(printSchema.bind(null))
.then(parse.bind(null));
}

const registry = Registry.getInstance();
registry.set('Config', config);

Object.defineProperty(config, 'schema', {
async get() {
if (this._schema) {
return this._schema;
}

let { schema } = this;

if (this.schemaUrl) {
schema = await fetchIntrospectionSchema(config.schemaUrl)
.then(buildClientSchema.bind(null))
.then(printSchema.bind(null))
.then(parse.bind(null));
}

this._schema = schema;
}
});

// @ts-ignore
console.log(registry.entries)


Vue.mixin({
beforeCreate() {
// istanbul ignore else
Expand Down
16 changes: 8 additions & 8 deletions src/models/Model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,16 +115,16 @@ export default abstract class Model extends EventEmitter {
return this.constructor.name;
}

protected getInputFields() {
protected async getInputFields() {
return getSchemaTypeFields(`${this.getClassName()}Input`);
}

public getUpdateVariables() {
public async getUpdateVariables(): Promise<unknown> {
return stripObject(this.toCollection()
.only(this.getInputFields())
.only(await this.getInputFields())
.map(field => {
if (Array.isArray(field)) {
return field.map(model => ((model instanceof Model) ? model.getUpdateVariables() : model));
return Promise.all(field.map(async model => ((model instanceof Model) ? await model.getUpdateVariables() : model)));
}
if (field instanceof Model) {
return field.getUpdateVariables();
Expand Down Expand Up @@ -156,7 +156,7 @@ export default abstract class Model extends EventEmitter {

public async create(params?: unknown, mutation?: string | DocumentNode) {
const resolvedRequest = this.resolveRequest(mutation, this.createMutation);
const resolvedParams = this.resolveParams(params);
const resolvedParams = await this.resolveParams(params);

// istanbul ignore else
if (config().graphql) {
Expand All @@ -172,7 +172,7 @@ export default abstract class Model extends EventEmitter {

public async update(params?: unknown, mutation?: string | DocumentNode) {
const resolvedRequest = this.resolveRequest(mutation, this.updateMutation);
const resolvedParams = this.resolveParams(params);
const resolvedParams = await this.resolveParams(params);

// istanbul ignore else
if (config().graphql) {
Expand Down Expand Up @@ -265,9 +265,9 @@ export default abstract class Model extends EventEmitter {
return typeof defaultRequest === 'function' ? defaultRequest() : defaultRequest;
}

protected resolveParams(params: Object): Object {
protected async resolveParams(params: unknown): Promise<unknown> {
if (config().graphql) {
const model = this.getUpdateVariables();
const model = await this.getUpdateVariables();

return {
[to.camel(this.className)]: model,
Expand Down
41 changes: 29 additions & 12 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { ApolloQueryResult } from 'apollo-client';
import { FetchResult } from 'apollo-link';
import { ObjectTypeDefinitionNode, DocumentNode, IntrospectionQuery, OperationDefinitionNode } from 'graphql';
import { Config, KeyValueUnknown, ResolvingRESTOptions } from './typings';
import { getIntrospectionQuery } from 'graphql';
Expand Down Expand Up @@ -116,12 +118,27 @@ export function stripTypename(obj) {
*/
export async function performSafeRequestGraphql(query: DocumentNode, variables = {}) {
const queryName = query.definitions.map(def => (<OperationDefinitionNode>def).name).find(def => def.kind === 'Name').value;
const operation = (<OperationDefinitionNode>query.definitions.find(def => def.kind === 'OperationDefinition')).operation === 'query'
? performGqlQuery.bind(null, query, stripTypename(variables))
: performGqlMutation.bind(null, query, stripTypename(variables));
const isQuery = (<OperationDefinitionNode>query.definitions.find(def => def.kind === 'OperationDefinition')).operation === 'query';
if (isQuery) {
return performGqlQuery(query, stripTypename(variables))
.then((value: ApolloQueryResult<unknown>) => {
console.log(value);
return value.data[queryName];
});
}

return performGqlMutation(query, stripTypename(variables))
.then((value: FetchResult<unknown>) => {
console.log(value);
return value.data[queryName];
});

// @ts-ignore
return operation().then(({ data }) => data[queryName]);
return operation().then((result: ApolloQueryResult<T>) => {
console.log(result);

return result.data[queryName];
});
}

export function registryGet(key: string): unknown {
Expand All @@ -132,8 +149,8 @@ export function config(): Config {
return registryGet('Config');
}

export function getParsedSchema(): DocumentNode {
const schema = config().schema;
export async function getParsedSchema(): Promise<DocumentNode> {
const schema = await config().schema;

if (!schema) {
throw new UnexpectedException('Configuration error: \'schema\' must be passed as a config key, e.g\n\nimport schema from \'raw-loader!@/../schema.graphql\';\n\n//...\n\nVue.use(VueOOP, {\n //...,\n schema,\n})\n\n;');
Expand All @@ -142,24 +159,24 @@ export function getParsedSchema(): DocumentNode {
return schema;
}

export function getSchemaTypeFields(typeName): string[] {
return (getParsedSchema()
export async function getSchemaTypeFields(typeName): Promise<string[]> {
return ((await getParsedSchema())
.definitions as ReadonlyArray<ObjectTypeDefinitionNode>)
.find(def => (def.name || {}).value === typeName)
.fields
.map(f => f.name.value);
}

export function getSchemaMutation(mutationName) {
return (getParsedSchema()
export async function getSchemaMutation(mutationName) {
return ((await getParsedSchema())
.definitions as ReadonlyArray<ObjectTypeDefinitionNode>)
.find(def => (def.name || {}).value === 'Mutation')
.fields
.find(def => (def.name || {}).value === mutationName)
}

export function getSchemaQuery(queryName) {
return (getParsedSchema()
export async function getSchemaQuery(queryName) {
return ((await getParsedSchema())
.definitions as ReadonlyArray<ObjectTypeDefinitionNode>)
.find(def => (def.name || {}).value === 'Query')
.fields
Expand Down
3 changes: 1 addition & 2 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
/* Basic Options */
"incremental": true,
/* Enable incremental compilation */
"target": "esnext",
"target": "ES2019",
/* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"module": "commonjs",
/* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
// "lib": [], /* Specify library files to be included in the compilation. */
"lib": [
"esnext",
"scripthost",
Expand Down
Loading

0 comments on commit 8df9ec1

Please sign in to comment.