From 07d719baf1b970ada05f609b18076fa20340e026 Mon Sep 17 00:00:00 2001 From: getlarge Date: Fri, 20 Mar 2020 19:01:34 +0100 Subject: [PATCH 01/13] convert to typescript every file in /engine ; doument input / output types for classes and some functions ; add linter for built files --- package.json | 1 + src/engine/CustomError.js | 10 - src/engine/CustomError.ts | 26 +++ .../action/{Action.spec.js => Action.spec.ts} | 6 +- src/engine/action/{Action.js => Action.ts} | 97 +++++++--- src/engine/attribute/Attribute.ts | 32 ++- .../{Configuration.js => Configuration.ts} | 30 ++- src/engine/entity/Entity.ts | 1 + src/engine/entity/ShadowEntity.spec.ts | 2 + ...ystemAttributes.js => systemAttributes.ts} | 42 ++-- src/engine/{filter.spec.js => filter.spec.ts} | 23 +-- src/engine/{filter.js => filter.ts} | 0 src/engine/{helpers.js => helpers.ts} | 39 ++-- src/engine/{i18n.js => i18n.ts} | 11 +- .../index/{Index.spec.js => Index.spec.ts} | 23 +-- src/engine/index/{Index.js => Index.ts} | 43 ++-- .../models/{Language.js => Language.ts} | 0 src/engine/models/{User.js => User.ts} | 0 .../{Mutation.spec.js => Mutation.spec.ts} | 61 +++--- .../mutation/{Mutation.js => Mutation.ts} | 110 +++++------ ...{Permission.spec.js => Permission.spec.ts} | 53 ++--- src/engine/permission/Permission.ts | 183 ++++++++++-------- ...figuration.js => ProtocolConfiguration.ts} | 22 ++- ...tocolType.spec.js => ProtocolType.spec.ts} | 2 + .../{ProtocolType.js => ProtocolType.ts} | 72 +++++-- .../schema/{Schema.spec.js => Schema.spec.ts} | 6 +- src/engine/schema/{Schema.js => Schema.ts} | 39 +++- ...nfiguration.js => StorageConfiguration.ts} | 17 +- ...taType.spec.js => StorageDataType.spec.ts} | 7 +- ...{StorageDataType.js => StorageDataType.ts} | 27 ++- ...torageType.spec.js => StorageType.spec.ts} | 1 + .../{StorageType.js => StorageType.ts} | 93 +++++++-- ...{StorageTypeNull.js => StorageTypeNull.ts} | 0 src/engine/{util.spec.js => util.spec.ts} | 2 + ...{validation.spec.js => validation.spec.ts} | 9 +- src/engine/{validation.js => validation.ts} | 43 ++-- src/graphqlProtocol/action.spec.js | 3 +- src/graphqlProtocol/dataTypes.spec.js | 2 + src/graphqlProtocol/filter.spec.js | 23 +-- src/graphqlProtocol/generator.spec.js | 2 + src/graphqlProtocol/io.spec.js | 1 + src/graphqlProtocol/resolver.js | 3 +- src/graphqlProtocol/test-helper.ts | 2 - src/graphqlProtocol/util.spec.js | 2 + 44 files changed, 755 insertions(+), 416 deletions(-) delete mode 100644 src/engine/CustomError.js create mode 100644 src/engine/CustomError.ts rename src/engine/action/{Action.spec.js => Action.spec.ts} (96%) rename src/engine/action/{Action.js => Action.ts} (55%) rename src/engine/configuration/{Configuration.js => Configuration.ts} (79%) rename src/engine/entity/{systemAttributes.js => systemAttributes.ts} (79%) rename src/engine/{filter.spec.js => filter.spec.ts} (92%) rename src/engine/{filter.js => filter.ts} (100%) rename src/engine/{helpers.js => helpers.ts} (80%) rename src/engine/{i18n.js => i18n.ts} (78%) rename src/engine/index/{Index.spec.js => Index.spec.ts} (88%) rename src/engine/index/{Index.js => Index.ts} (70%) rename src/engine/models/{Language.js => Language.ts} (100%) rename src/engine/models/{User.js => User.ts} (100%) rename src/engine/mutation/{Mutation.spec.js => Mutation.spec.ts} (90%) rename src/engine/mutation/{Mutation.js => Mutation.ts} (72%) rename src/engine/permission/{Permission.spec.js => Permission.spec.ts} (95%) rename src/engine/protocol/{ProtocolConfiguration.js => ProtocolConfiguration.ts} (52%) rename src/engine/protocol/{ProtocolType.spec.js => ProtocolType.spec.ts} (98%) rename src/engine/protocol/{ProtocolType.js => ProtocolType.ts} (64%) rename src/engine/schema/{Schema.spec.js => Schema.spec.ts} (94%) rename src/engine/schema/{Schema.js => Schema.ts} (91%) rename src/engine/storage/{StorageConfiguration.js => StorageConfiguration.ts} (79%) rename src/engine/storage/{StorageDataType.spec.js => StorageDataType.spec.ts} (94%) rename src/engine/storage/{StorageDataType.js => StorageDataType.ts} (72%) rename src/engine/storage/{StorageType.spec.js => StorageType.spec.ts} (98%) rename src/engine/storage/{StorageType.js => StorageType.ts} (65%) rename src/engine/storage/{StorageTypeNull.js => StorageTypeNull.ts} (100%) rename src/engine/{util.spec.js => util.spec.ts} (99%) rename src/engine/{validation.spec.js => validation.spec.ts} (98%) rename src/engine/{validation.js => validation.ts} (85%) diff --git a/package.json b/package.json index e8d8ecc3..563ea6a8 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "test-watch": "jest --watch", "lint": "eslint src/*", "lint-fix": "eslint src/* --fix", + "lint:fix": "tsc --noEmit && eslint '*/**/*.{js,ts,tsx}' --quiet --fix", "lint-staged": "lint-staged", "coverage": "cross-env NODE_ENV=test jest --coverage", "coverage-ci": "npm run coverage && cat ./coverage/lcov.info | codecov", diff --git a/src/engine/CustomError.js b/src/engine/CustomError.js deleted file mode 100644 index 03febaa0..00000000 --- a/src/engine/CustomError.js +++ /dev/null @@ -1,10 +0,0 @@ -export class CustomError extends Error { - constructor(message, code, status, meta) { - super(message); - Error.captureStackTrace(this, this.constructor); - this.name = this.constructor.name; - this.code = code; - this.status = status; - this.meta = meta; - } -} diff --git a/src/engine/CustomError.ts b/src/engine/CustomError.ts new file mode 100644 index 00000000..ca223a66 --- /dev/null +++ b/src/engine/CustomError.ts @@ -0,0 +1,26 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +declare type ErrorInterface = Error; + +declare class Error implements ErrorInterface { + name: string; + message: string; + static captureStackTrace(object: any, objectConstructor?: any): any; +} + +export class CustomError extends Error { + code: any; + status?: any; + meta?: any; + + constructor(message?: string, code?: any, status?: any, meta?: any) { + // super(message); + super(); + Error.captureStackTrace(this, this.constructor); + this.message = message; + this.name = this.constructor.name; + this.code = code; + this.status = status; + this.meta = meta; + } +} diff --git a/src/engine/action/Action.spec.js b/src/engine/action/Action.spec.ts similarity index 96% rename from src/engine/action/Action.spec.js rename to src/engine/action/Action.spec.ts index fcaf0648..c044e9d9 100644 --- a/src/engine/action/Action.spec.js +++ b/src/engine/action/Action.spec.ts @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/no-empty-function */ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ import { Action, isAction } from './Action'; import { Permission, isPermission } from '../permission/Permission'; @@ -327,7 +328,7 @@ describe('Action', () => { input: {}, output: {}, resolve() {}, - permissions: [ new Permission().authenticated(), new Permission() ], + permissions: [new Permission().authenticated(), new Permission()], }); function fn() { @@ -338,3 +339,6 @@ describe('Action', () => { }); }); }); + +/* eslint-enable @typescript-eslint/no-empty-function */ +/* eslint-enable @typescript-eslint/explicit-function-return-type */ diff --git a/src/engine/action/Action.js b/src/engine/action/Action.ts similarity index 55% rename from src/engine/action/Action.js rename to src/engine/action/Action.ts index 6242146e..84e57ae5 100644 --- a/src/engine/action/Action.js +++ b/src/engine/action/Action.ts @@ -1,16 +1,51 @@ -import { passOrThrow, isMap, isFunction } from '../util'; +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { passOrThrow, isMap, isFunction } from '../util'; +import { AttributeBase } from '../attribute/Attribute'; +import { DataTypeFunction } from '../datatype/DataType'; import { generatePermissionDescription, processActionPermissions, + Permission, } from '../permission/Permission'; export const ACTION_TYPE_MUTATION = 'mutation'; export const ACTION_TYPE_QUERY = 'query'; -export const actionTypes = [ ACTION_TYPE_MUTATION, ACTION_TYPE_QUERY ]; +export const actionTypes = [ACTION_TYPE_MUTATION, ACTION_TYPE_QUERY]; + +export type ActionSetup = { + name?: string; + description?: string; + // input?: AttributeBase | Function | { [type: string]: Function }; + input?: any; + // output?: AttributeBase | Function | { [type: string]: Function }; + output?: any; + resolve?: Function; + type?: string; + permissions?: Function | Permission | Permission[]; + postProcessor?: Function; +}; export class Action { - constructor(setup = {}) { + name: string; + description: string; + // input: AttributeBase | Function | { [type: string]: Function }; + // private _input: AttributeBase | Function | { [type: string]: Function }; + input: any; + private _input: any; + // output: AttributeBase | Function | { [type: string]: Function }; + // private _output: AttributeBase | Function | { [type: string]: Function }; + output: any; + private _output: any; + resolve: Function; + type: string; + permissions: Function | Permission | Permission[]; + private _permissions: Function | Permission | Permission[]; + private _defaultPermissions: Function | Permission | Permission[]; + descriptionPermissions: string | false; + postProcessor: Function; + + constructor(setup: ActionSetup = {} as ActionSetup) { const { name, description, @@ -77,24 +112,26 @@ export class Action { } if (isFunction(this.input)) { - this.input = this.input(); + const inputFn = this.input as Function; + this.input = inputFn(); passOrThrow( isMap(this.input), () => - `Input definition function for action '${ - this.name - }' does not return a map`, + `Input definition function for action '${this.name}' does not return a map`, ); } + const inputAttr = this.input as AttributeBase; passOrThrow( - this.input.type, + inputAttr.type, () => `Missing input type for action '${this.name}'`, ); - if (isFunction(this.input.type)) { - this.input.type = this.input.type({ + if (isFunction(inputAttr.type)) { + const inputAttrType = inputAttr.type as DataTypeFunction; + this.input = this.input as AttributeBase; + this.input.type = inputAttrType({ name: 'input', description: this.input.description || this.description, }); @@ -105,7 +142,7 @@ export class Action { return this._input; } - hasInput() { + hasInput(): boolean { return !!this.input; } @@ -119,24 +156,26 @@ export class Action { } if (isFunction(this.output)) { - this.output = this.output(); + const outputFn = this.output as Function; + this.output = outputFn(); passOrThrow( isMap(this.output), () => - `Output definition function for action '${ - this.name - }' does not return a map`, + `Output definition function for action '${this.name}' does not return a map`, ); } + const outputAttr = this.output as AttributeBase; passOrThrow( - this.output.type, + outputAttr.type, () => `Missing output type for action '${this.name}'`, ); - if (isFunction(this.output.type)) { - this.output.type = this.output.type({ + if (isFunction(outputAttr.type)) { + const outputAttrType = outputAttr.type as DataTypeFunction; + this.output = this.output as AttributeBase; + this.output.type = outputAttrType({ name: 'output', description: this.output.description || this.description, }); @@ -147,19 +186,23 @@ export class Action { return this._output; } - hasOutput() { + hasOutput(): boolean { return !!this.output; } _processPermissions() { if (this._permissions) { - const permissions = isFunction(this._permissions) - ? this._permissions() - : this._permissions; - - return processActionPermissions(this, permissions); - } - else if (this._defaultPermissions) { + if (isFunction(this._permissions)) { + const permissionsFn = this._permissions as Function; + return processActionPermissions(this, permissionsFn); + } + return processActionPermissions(this, this._permissions); + + // const permissions = isFunction(this._permissions) + // ? this._permissions() + // : this._permissions; + // return processActionPermissions(this, permissions); + } else if (this._defaultPermissions) { return processActionPermissions(this, this._defaultPermissions); } @@ -193,6 +236,6 @@ export class Action { } } -export const isAction = obj => { +export const isAction = (obj: any) => { return obj instanceof Action; }; diff --git a/src/engine/attribute/Attribute.ts b/src/engine/attribute/Attribute.ts index 19f617e3..2d81debf 100644 --- a/src/engine/attribute/Attribute.ts +++ b/src/engine/attribute/Attribute.ts @@ -1,6 +1,7 @@ import { ComplexDataType } from '../datatype/ComplexDataType'; import { DataType, DataTypeFunction } from '../datatype/DataType'; import { Entity } from '../entity/Entity'; +import { Mutation } from '../mutation/Mutation'; /** * base of a model attribute @@ -14,7 +15,7 @@ export type AttributeBase = { /** * data type of the attribute */ - type: DataType | ComplexDataType | Entity; + type: DataType | ComplexDataType | Entity | DataTypeFunction; /** * make attribute non-nullable on the storage level @@ -46,17 +47,38 @@ export type AttributeBase = { /** * default value generator for create type mutations */ - defaultValue?: () => any; + + defaultValue?: ( + payload?: any, + entityMutation?: Mutation, + entity?: Entity, + context?: Record, + ) => any; /** * custom data serializer function */ - serialize?: () => any; + + serialize?: ( + field?: any, + payload?: any, + entityMutation?: Mutation, + entity?: Entity, + model?: any, + context?: Record, + language?: any, + ) => any; /** * custom validation function */ - validate?: () => any; + validate?: ( + value?: any, + attributeName?: string, + row?: any, + source?: any, + context?: Record, + ) => any; /** * hide the attribute in the protocol (graphql) layer @@ -82,6 +104,8 @@ export type AttributeBase = { * place to store custom (project-related) meta data */ meta?: any; + + gqlFieldNameI18n?: any; }; /** diff --git a/src/engine/configuration/Configuration.js b/src/engine/configuration/Configuration.ts similarity index 79% rename from src/engine/configuration/Configuration.js rename to src/engine/configuration/Configuration.ts index f33cb736..b40dfcfb 100644 --- a/src/engine/configuration/Configuration.js +++ b/src/engine/configuration/Configuration.ts @@ -1,16 +1,32 @@ import { passOrThrow, isArray } from '../util'; -import { isSchema } from '../schema/Schema'; - +import { Schema, isSchema } from '../schema/Schema'; import { languageIsoCodeRegex, LANGUAGE_ISO_CODE_PATTERN } from '../constants'; - -import { isProtocolConfiguration } from '../protocol/ProtocolConfiguration'; -import { isStorageConfiguration } from '../storage/StorageConfiguration'; +import { + ProtocolConfiguration, + isProtocolConfiguration, +} from '../protocol/ProtocolConfiguration'; +import { + StorageConfiguration, + isStorageConfiguration, +} from '../storage/StorageConfiguration'; import * as _ from 'lodash'; +export type ConfigurationSetup = { + languages?: string[]; + schema?: Schema; + protocolConfiguration?: ProtocolConfiguration; + storageConfiguration?: StorageConfiguration; +}; + export class Configuration { - constructor(setup = {}) { + languages: string[]; + schema: Schema; + protocolConfiguration: ProtocolConfiguration; + storageConfiguration: StorageConfiguration; + + constructor(setup: ConfigurationSetup = {} as ConfigurationSetup) { const { languages, schema, @@ -18,7 +34,7 @@ export class Configuration { storageConfiguration, } = setup; - this.setLanguages(languages || [ 'en' ]); + this.setLanguages(languages || ['en']); if (schema) { this.setSchema(schema); diff --git a/src/engine/entity/Entity.ts b/src/engine/entity/Entity.ts index f7043f3e..6b3bef49 100644 --- a/src/engine/entity/Entity.ts +++ b/src/engine/entity/Entity.ts @@ -63,6 +63,7 @@ export type EntitySetup = { includeTimeTracking?: boolean; includeUserTracking?: boolean; indexes?: any; + // improve typings ? mutations?: any; permissions?: any; states?: any; diff --git a/src/engine/entity/ShadowEntity.spec.ts b/src/engine/entity/ShadowEntity.spec.ts index eb34d3fa..1224cea9 100644 --- a/src/engine/entity/ShadowEntity.spec.ts +++ b/src/engine/entity/ShadowEntity.spec.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ + import { Entity } from './Entity'; import { ShadowEntity, isShadowEntity } from './ShadowEntity'; import { passOrThrow } from '../util'; diff --git a/src/engine/entity/systemAttributes.js b/src/engine/entity/systemAttributes.ts similarity index 79% rename from src/engine/entity/systemAttributes.js rename to src/engine/entity/systemAttributes.ts index 6b54d7b2..a80e5bcf 100644 --- a/src/engine/entity/systemAttributes.js +++ b/src/engine/entity/systemAttributes.ts @@ -1,3 +1,6 @@ +import { camelCase, isFunction } from 'lodash'; +import * as casual from 'casual'; + import { DataTypeID, DataTypeUserID, @@ -7,11 +10,10 @@ import { import { CustomError } from '../CustomError'; import { DataTypeState } from '../datatype/DataTypeState'; +import { Entity } from '../entity/Entity'; +import { Mutation } from '../mutation/Mutation'; import { i18nMockGenerator } from '../i18n'; -import * as _ from 'lodash'; -import * as casual from 'casual'; - export const systemAttributePrimary = { name: 'id', description: 'Unique row identifier', @@ -26,16 +28,14 @@ export const systemAttributesTimeTracking = [ description: 'Record was created at this time', type: DataTypeTimestampTz, required: true, - defaultValue: (data, mutation) => { + defaultValue: (_: any, mutation: Mutation) => { return mutation.isTypeCreate ? new Date() : undefined; }, - mock: entity => { + mock: (entity: Entity) => { if (entity.meta && entity.meta.mockCreatedAtGenerator) { - if (!_.isFunction(entity.meta.mockCreatedAtGenerator)) { + if (!isFunction(entity.meta.mockCreatedAtGenerator)) { throw new CustomError( - `meta.mockCreatedAtGenerator needs to be a function in entity '${ - entity.name - }'`, + `meta.mockCreatedAtGenerator needs to be a function in entity '${entity.name}'`, 'InvalidMetaDataError', ); } @@ -50,18 +50,16 @@ export const systemAttributesTimeTracking = [ description: 'Record was updated at this time', type: DataTypeTimestampTz, required: true, - defaultValue: (data, mutation) => { + defaultValue: (_: any, mutation: Mutation) => { return mutation.isTypeCreate || mutation.isTypeUpdate ? new Date() : undefined; }, - mock: entity => { + mock: (entity: Entity) => { if (entity.meta && entity.meta.mockUpdatedAtGenerator) { - if (!_.isFunction(entity.meta.mockUpdatedAtGenerator)) { + if (!isFunction(entity.meta.mockUpdatedAtGenerator)) { throw new CustomError( - `meta.mockUpdatedAtGenerator needs to be a function in entity '${ - entity.name - }'`, + `meta.mockUpdatedAtGenerator needs to be a function in entity '${entity.name}'`, 'InvalidMetaDataError', ); } @@ -79,7 +77,7 @@ export const systemAttributesUserTracking = [ description: 'Record was created by this time', type: DataTypeUserID, required: true, - defaultValue: (data, mutation, entity, { userId }) => { + defaultValue: (_: any, mutation: Mutation, __: Entity, { userId }) => { // TODO: make overridable return mutation.isTypeCreate && userId ? userId : undefined; }, @@ -89,7 +87,7 @@ export const systemAttributesUserTracking = [ description: 'Record was updated by this user', type: DataTypeUserID, required: true, - defaultValue: (data, mutation, entity, { userId }) => { + defaultValue: (_: any, mutation: Mutation, __: Entity, { userId }) => { // TODO: make overridable return (mutation.isTypeCreate || mutation.isTypeUpdate) && userId ? userId @@ -101,15 +99,15 @@ export const systemAttributesUserTracking = [ export const systemAttributeState = { name: 'state', description: 'State of record', - type: (attribute, entity) => + type: (attribute: any, entity: Entity) => new DataTypeState({ ...attribute, validate: undefined, // delete from props as it would be handled as a data type validator - name: _.camelCase(`${entity.name}-instance-state`), + name: camelCase(`${entity.name}-instance-state`), states: entity.states, }), required: true, - defaultValue: (data, mutation) => { + defaultValue: (_: any, mutation: Mutation) => { if (mutation.isTypeCreate || mutation.isTypeUpdate) { if (typeof mutation.toState === 'string') { return mutation.toState; @@ -117,7 +115,7 @@ export const systemAttributeState = { } return undefined; }, - serialize: (value, data, mutation, entity) => { + serialize: (value, _: any, __: Mutation, entity: Entity) => { const states = entity.getStates(); const state = states[value]; @@ -127,7 +125,7 @@ export const systemAttributeState = { return state; }, - validate: (value, attributeName, data, { mutation }) => { + validate: (value: string, __: string, _: any, { mutation }) => { if (mutation.isTypeCreate || mutation.isTypeUpdate) { if (typeof mutation.toState !== 'string') { if (!mutation.toState) { diff --git a/src/engine/filter.spec.js b/src/engine/filter.spec.ts similarity index 92% rename from src/engine/filter.spec.js rename to src/engine/filter.spec.ts index dc768a7e..63384c76 100644 --- a/src/engine/filter.spec.js +++ b/src/engine/filter.spec.ts @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/camelcase */ /* eslint-disable @typescript-eslint/no-empty-function */ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ import { validateFilterLevel } from './filter'; import { Entity } from './entity/Entity'; @@ -54,7 +55,7 @@ describe('filter', () => { description: 'Just some description', nativeDataType: 'text', serialize() {}, - capabilities: [ 'lt', 'lte', 'gt', 'gte' ], + capabilities: ['lt', 'lte', 'gt', 'gte'], }); const StorageDataTypeText = new StorageDataType({ @@ -62,7 +63,7 @@ describe('filter', () => { description: 'Just some description', nativeDataType: 'text', serialize() {}, - capabilities: [ 'in', 'lt', 'lte', 'gt', 'gte', 'starts_with', 'ends_with' ], + capabilities: ['in', 'lt', 'lte', 'gt', 'gte', 'starts_with', 'ends_with'], }); SomeStorageType.addDataTypeMap(DataTypeInteger, StorageDataTypeAny); @@ -80,7 +81,7 @@ describe('filter', () => { const goodFilter2 = { lastName: { - $in: [ 'Doe', 'Smith' ], + $in: ['Doe', 'Smith'], }, firstName: { $starts_with: 'Joh', @@ -93,7 +94,7 @@ describe('filter', () => { validateFilterLevel( goodFilter1, filteredEntity.getAttributes(), - [ 'somewhere' ], + ['somewhere'], SomeStorageType, ), ).not.toThrow(); @@ -102,7 +103,7 @@ describe('filter', () => { validateFilterLevel( goodFilter2, filteredEntity.getAttributes(), - [ 'somewhere' ], + ['somewhere'], SomeStorageType, ), ).not.toThrow(); @@ -147,7 +148,7 @@ describe('filter', () => { validateFilterLevel( goodFilter1, filteredEntity.getAttributes(), - [ 'somewhere' ], + ['somewhere'], SomeStorageType, ), ).not.toThrow(); @@ -156,7 +157,7 @@ describe('filter', () => { validateFilterLevel( goodFilter2, filteredEntity.getAttributes(), - [ 'somewhere' ], + ['somewhere'], SomeStorageType, ), ).not.toThrow(); @@ -172,14 +173,14 @@ describe('filter', () => { } function fn3() { - validateFilterLevel([], null, [ 'somewhere' ], SomeStorageType); + validateFilterLevel([], null, ['somewhere'], SomeStorageType); } function fn4() { validateFilterLevel( [], null, - [ 'somewhere', 'deeply', 'nested' ], + ['somewhere', 'deeply', 'nested'], SomeStorageType, ); } @@ -188,7 +189,7 @@ describe('filter', () => { validateFilterLevel( {}, null, - [ 'somewhere', 'deeply', 'nested' ], + ['somewhere', 'deeply', 'nested'], SomeStorageType, ); } @@ -241,7 +242,7 @@ describe('filter', () => { validateFilterLevel( badFilter2, filteredEntity.getAttributes(), - [ 'just', 'here' ], + ['just', 'here'], SomeStorageType, ); } diff --git a/src/engine/filter.js b/src/engine/filter.ts similarity index 100% rename from src/engine/filter.js rename to src/engine/filter.ts diff --git a/src/engine/helpers.js b/src/engine/helpers.ts similarity index 80% rename from src/engine/helpers.js rename to src/engine/helpers.ts index b3a863f5..2d110bf6 100644 --- a/src/engine/helpers.js +++ b/src/engine/helpers.ts @@ -1,16 +1,18 @@ import * as _ from 'lodash'; +import { Entity } from '..'; +import { Mutation } from './mutation/Mutation'; export const fillSystemAttributesDefaultValues = ( - entity, - entityMutation, - payload, - context, -) => { + entity: Entity, + entityMutation: Mutation, + payload: any, + context: Record, +): any => { const ret = { ...payload, }; - const entityAttributes = entity.getAttributes(); + const entityAttributes: any = entity.getAttributes(); const systemAttributes = _.filter( entityAttributes, attribute => attribute.isSystemAttribute && attribute.defaultValue, @@ -30,11 +32,11 @@ export const fillSystemAttributesDefaultValues = ( }; export const fillDefaultValues = async ( - entity, - entityMutation, - payload, - context, -) => { + entity: Entity, + entityMutation: Mutation, + payload: any, + context: Record, +): Promise => { const ret = { ...payload, }; @@ -66,12 +68,12 @@ export const fillDefaultValues = async ( }; export const serializeValues = ( - entity, - entityMutation, - payload, - model, - context, -) => { + entity: Entity, + entityMutation: Mutation, + payload: any, + model: string, + context: Record, +): any => { const ret = { ...payload, }; @@ -95,8 +97,7 @@ export const serializeValues = ( language, ); }); - } - else if (typeof ret[attributeName] !== 'undefined') { + } else if (typeof ret[attributeName] !== 'undefined') { ret[attributeName] = attribute.serialize( ret[attributeName], ret, diff --git a/src/engine/i18n.js b/src/engine/i18n.ts similarity index 78% rename from src/engine/i18n.js rename to src/engine/i18n.ts index 6f2c33aa..a0c65ee9 100644 --- a/src/engine/i18n.js +++ b/src/engine/i18n.ts @@ -1,16 +1,17 @@ +import { map } from 'lodash'; import { randomJson } from './util'; -import * as _ from 'lodash'; +// import { Entity } from '..'; export const i18nMockGenerator = ( - entity, - name, + entity: any, + _: string, { dataShaperMap }, languages = [], -) => { +): object => { if (entity) { const content = {}; - _.map(entity.getAttributes(), ({ type, i18n, mock }, attributeName) => { + map(entity.getAttributes(), ({ type, i18n, mock }, attributeName) => { const storageAttributeName = dataShaperMap[attributeName]; if (i18n) { diff --git a/src/engine/index/Index.spec.js b/src/engine/index/Index.spec.ts similarity index 88% rename from src/engine/index/Index.spec.js rename to src/engine/index/Index.spec.ts index 815ebd0f..53d52793 100644 --- a/src/engine/index/Index.spec.js +++ b/src/engine/index/Index.spec.ts @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/no-empty-function */ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ import { Index, isIndex, INDEX_UNIQUE, processEntityIndexes } from './Index'; import { Entity } from '../entity/Entity'; @@ -52,7 +53,7 @@ describe('Index', () => { // eslint-disable-next-line no-new new Index({ type: INDEX_UNIQUE, - attributes: [ null ], + attributes: [null], }); } @@ -62,7 +63,7 @@ describe('Index', () => { // eslint-disable-next-line no-new new Index({ type: INDEX_UNIQUE, - attributes: [ 123 ], + attributes: [123], }); } @@ -74,7 +75,7 @@ describe('Index', () => { // eslint-disable-next-line no-new new Index({ type: INDEX_UNIQUE, - attributes: [ 'a', 'b', 'a' ], + attributes: ['a', 'b', 'a'], }); } @@ -84,16 +85,16 @@ describe('Index', () => { it('should accept a correct definition', () => { const index1 = new Index({ type: INDEX_UNIQUE, - attributes: [ 'a' ], + attributes: ['a'], }); const index2 = new Index({ type: INDEX_UNIQUE, - attributes: [ 'a', 'b', 'c' ], + attributes: ['a', 'b', 'c'], }); - expect(index1.attributes).toEqual([ 'a' ]); - expect(index2.attributes).toEqual([ 'a', 'b', 'c' ]); + expect(index1.attributes).toEqual(['a']); + expect(index2.attributes).toEqual(['a', 'b', 'c']); expect(String(index1)).toEqual('unique'); }); @@ -102,7 +103,7 @@ describe('Index', () => { it('should recognize objects of type Index', () => { const index = new Index({ type: INDEX_UNIQUE, - attributes: [ 'a' ], + attributes: ['a'], }); function fn() { @@ -141,7 +142,7 @@ describe('Index', () => { it('should throw if provided with an invalid list of indexes', () => { const indexes = { - unique: [ {} ], + unique: [{}], }; function fn() { @@ -152,7 +153,7 @@ describe('Index', () => { }); it('should throw if provided with an invalid index', () => { - const indexes = [ { foo: 'bar' } ]; + const indexes = [{ foo: 'bar' }]; function fn() { processEntityIndexes(entity, indexes); @@ -165,7 +166,7 @@ describe('Index', () => { const indexes = [ new Index({ type: INDEX_UNIQUE, - attributes: [ 'someAttribute', 'notHere' ], + attributes: ['someAttribute', 'notHere'], }), ]; diff --git a/src/engine/index/Index.js b/src/engine/index/Index.ts similarity index 70% rename from src/engine/index/Index.js rename to src/engine/index/Index.ts index 2cf217ef..fa445d7f 100644 --- a/src/engine/index/Index.js +++ b/src/engine/index/Index.ts @@ -1,13 +1,22 @@ +import { uniq } from 'lodash'; import { passOrThrow, isArray } from '../util'; -import * as _ from 'lodash'; +import { Entity } from '../entity/Entity'; export const INDEX_UNIQUE = 'unique'; export const INDEX_GENERIC = 'generic'; -export const indexTypes = [ INDEX_UNIQUE, INDEX_GENERIC ]; +export const indexTypes = [INDEX_UNIQUE, INDEX_GENERIC]; + +export type IndexSetup = { + type?: string; + attributes?: string[]; +}; export class Index { - constructor(setup = {}) { + type: string; + attributes: string[]; + + constructor(setup: IndexSetup = {} as IndexSetup) { const { type, attributes } = setup; passOrThrow(type, () => 'Missing index type'); @@ -34,7 +43,7 @@ export class Index { }); passOrThrow( - attributes.length === _.uniq(attributes).length, + attributes.length === uniq(attributes).length, () => `Index definition of type '${type}' needs to have a list of unique attribute names`, ); @@ -48,17 +57,15 @@ export class Index { } } -export const isIndex = obj => { +export const isIndex = (obj: any) => { return obj instanceof Index; }; -export const processEntityIndexes = (entity, indexes) => { +export const processEntityIndexes = (entity: Entity, indexes: Index[]) => { passOrThrow( isArray(indexes), () => - `Entity '${ - entity.name - }' indexes definition needs to be an array of indexes`, + `Entity '${entity.name}' indexes definition needs to be an array of indexes`, ); const singleAttributeIndexes = []; @@ -69,35 +76,27 @@ export const processEntityIndexes = (entity, indexes) => { passOrThrow( isIndex(index), () => - `Invalid index definition for entity '${ - entity.name - }' at position '${idx}'`, + `Invalid index definition for entity '${entity.name}' at position '${idx}'`, ); index.attributes.map(attributeName => { passOrThrow( entityAttributes[attributeName], () => - `Cannot use attribute '${ - entity.name - }.${attributeName}' in index as it does not exist`, + `Cannot use attribute '${entity.name}.${attributeName}' in index as it does not exist`, ); if (index.type === INDEX_UNIQUE) { passOrThrow( entityAttributes[attributeName].required, () => - `Cannot use attribute '${ - entity.name - }.${attributeName}' in uniqueness index as it is nullable`, + `Cannot use attribute '${entity.name}.${attributeName}' in uniqueness index as it is nullable`, ); passOrThrow( !entityAttributes[attributeName].i18n, () => - `Cannot use attribute '${ - entity.name - }.${attributeName}' in uniqueness index as it is translatable`, + `Cannot use attribute '${entity.name}.${attributeName}' in uniqueness index as it is translatable`, ); if (index.attributes.length === 1) { @@ -118,7 +117,7 @@ export const processEntityIndexes = (entity, indexes) => { indexes.push( new Index({ type: INDEX_GENERIC, - attributes: [ attributeName ], + attributes: [attributeName], }), ); } diff --git a/src/engine/models/Language.js b/src/engine/models/Language.ts similarity index 100% rename from src/engine/models/Language.js rename to src/engine/models/Language.ts diff --git a/src/engine/models/User.js b/src/engine/models/User.ts similarity index 100% rename from src/engine/models/User.js rename to src/engine/models/User.ts diff --git a/src/engine/mutation/Mutation.spec.js b/src/engine/mutation/Mutation.spec.ts similarity index 90% rename from src/engine/mutation/Mutation.spec.js rename to src/engine/mutation/Mutation.spec.ts index 347c8d6f..fe927896 100644 --- a/src/engine/mutation/Mutation.spec.js +++ b/src/engine/mutation/Mutation.spec.ts @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/no-empty-function */ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ import { Mutation, @@ -79,10 +80,10 @@ describe('Mutation', () => { description: 'mutate the world', }); - processEntityMutations(entity, [ mutation ]); + processEntityMutations(entity, [mutation]); const defaultAttributes = mutation.attributes; - const expectedAttributes = [ 'someAttribute', 'anotherAttribute' ]; + const expectedAttributes = ['someAttribute', 'anotherAttribute']; expect(defaultAttributes).toEqual(expectedAttributes); }); @@ -92,11 +93,11 @@ describe('Mutation', () => { name: 'example', type: MUTATION_TYPE_CREATE, description: 'mutate the world', - attributes: [ 'anything', { foo: 'bar' } ], + attributes: ['anything', { foo: 'bar' }], }); function fn() { - processEntityMutations(entity, [ mutation ]); + processEntityMutations(entity, [mutation]); } expect(fn).toThrowErrorMatchingSnapshot(); @@ -110,7 +111,7 @@ describe('Mutation', () => { attributes: [], }); - processEntityMutations(entity, [ mutation ]); + processEntityMutations(entity, [mutation]); expect(mutation.attributes).toEqual([]); }); @@ -122,7 +123,7 @@ describe('Mutation', () => { attributes: [], }); - processEntityMutations(entity, [ mutation ]); + processEntityMutations(entity, [mutation]); expect(mutation.attributes).not.toBeDefined(); }); @@ -131,11 +132,11 @@ describe('Mutation', () => { name: 'example', type: MUTATION_TYPE_CREATE, description: 'mutate the world', - attributes: [ 'anything', 'anything' ], + attributes: ['anything', 'anything'], }); function fn() { - processEntityMutations(entity, [ mutation ]); + processEntityMutations(entity, [mutation]); } expect(fn).toThrowErrorMatchingSnapshot(); @@ -146,7 +147,7 @@ describe('Mutation', () => { name: 'example', type: MUTATION_TYPE_UPDATE, description: 'mutate the world', - attributes: [ 'anything' ], + attributes: ['anything'], }); expect(mutation.name).toBe('example'); @@ -160,7 +161,7 @@ describe('Mutation', () => { name: 'example', type: MUTATION_TYPE_CREATE, description: 'mutate the world', - attributes: [ 'anything' ], + attributes: ['anything'], preProcessor: 'not-a-function', }); } @@ -175,7 +176,7 @@ describe('Mutation', () => { name: 'example', type: MUTATION_TYPE_CREATE, description: 'mutate the world', - attributes: [ 'anything' ], + attributes: ['anything'], postProcessor: 'not-a-function', }); } @@ -190,7 +191,7 @@ describe('Mutation', () => { name: 'example', type: MUTATION_TYPE_UPDATE, description: 'mutate the world', - attributes: [ 'anything' ], + attributes: ['anything'], fromState: { foo: 'bar' }, }); } @@ -205,7 +206,7 @@ describe('Mutation', () => { name: 'example', type: MUTATION_TYPE_UPDATE, description: 'mutate the world', - attributes: [ 'anything' ], + attributes: ['anything'], toState: 123, }); } @@ -220,7 +221,7 @@ describe('Mutation', () => { name: 'example', type: MUTATION_TYPE_CREATE, description: 'mutate the world', - attributes: [ 'anything' ], + attributes: ['anything'], fromState: 'open', }); } @@ -235,7 +236,7 @@ describe('Mutation', () => { name: 'example', type: MUTATION_TYPE_DELETE, description: 'mutate the world', - attributes: [ 'anything' ], + attributes: ['anything'], toState: 'closed', }); } @@ -250,7 +251,7 @@ describe('Mutation', () => { name: 'example', type: MUTATION_TYPE_UPDATE, description: 'mutate the world', - attributes: [ 'anything' ], + attributes: ['anything'], fromState: 'open', }); } @@ -265,7 +266,7 @@ describe('Mutation', () => { name: 'example', type: MUTATION_TYPE_UPDATE, description: 'mutate the world', - attributes: [ 'anything' ], + attributes: ['anything'], toState: 'close', }); } @@ -278,7 +279,7 @@ describe('Mutation', () => { name: 'example', type: MUTATION_TYPE_UPDATE, description: 'mutate the world', - attributes: [ 'anything' ], + attributes: ['anything'], preProcessor() {}, postProcessor() {}, }); @@ -308,26 +309,26 @@ describe('Mutation', () => { type: MUTATION_TYPE_CREATE, name: 'build', description: 'build item', - attributes: [ 'someAttribute' ], + attributes: ['someAttribute'], }; const mutationTypeUpdateDefinition = { type: MUTATION_TYPE_UPDATE, name: 'change', description: 'change item', - attributes: [ 'id', 'someAttribute' ], + attributes: ['id', 'someAttribute'], }; const mutationTypeDeleteDefinition = { type: MUTATION_TYPE_DELETE, name: 'drop', description: 'drop item', - attributes: [ 'id' ], + attributes: ['id'], }; it('should throw if provided with an invalid list of mutations', () => { const mutations = { - foo: [ {} ], + foo: [{}], }; function fn() { @@ -338,7 +339,7 @@ describe('Mutation', () => { }); it('should throw if provided with an invalid mutation', () => { - const mutations = [ { foo: 'bar' } ]; + const mutations = [{ foo: 'bar' }]; function fn() { processEntityMutations(entity, mutations); @@ -368,7 +369,7 @@ describe('Mutation', () => { type: MUTATION_TYPE_CREATE, name: 'build', description: 'build item', - attributes: [ 'someAttribute' ], + attributes: ['someAttribute'], }), ], }); @@ -385,13 +386,13 @@ describe('Mutation', () => { type: MUTATION_TYPE_CREATE, name: 'build', description: 'build item', - attributes: [ 'someAttribute' ], + attributes: ['someAttribute'], }), new Mutation({ type: MUTATION_TYPE_CREATE, name: 'build', description: 'build item', - attributes: [ 'someAttribute' ], + attributes: ['someAttribute'], }), ]; @@ -408,7 +409,7 @@ describe('Mutation', () => { type: MUTATION_TYPE_CREATE, name: 'build', description: 'build item', - attributes: [ 'doesNotExist' ], + attributes: ['doesNotExist'], }), ]; @@ -496,7 +497,7 @@ describe('Mutation', () => { const mutations2 = [ new Mutation({ ...mutationTypeUpdateDefinition, - fromState: [ 'open', 'whatever', 'close' ], + fromState: ['open', 'whatever', 'close'], toState: 'close', }), ]; @@ -529,7 +530,7 @@ describe('Mutation', () => { new Mutation({ ...mutationTypeUpdateDefinition, fromState: 'open', - toState: [ 'closed', 'randomState', 'open' ], + toState: ['closed', 'randomState', 'open'], }), ]; @@ -541,7 +542,7 @@ describe('Mutation', () => { const mutations4 = [ new Mutation({ ...mutationTypeDeleteDefinition, - fromState: [ 'open', 'notHere', 'open' ], + fromState: ['open', 'notHere', 'open'], }), ]; diff --git a/src/engine/mutation/Mutation.js b/src/engine/mutation/Mutation.ts similarity index 72% rename from src/engine/mutation/Mutation.js rename to src/engine/mutation/Mutation.ts index 930a4329..875f6070 100644 --- a/src/engine/mutation/Mutation.js +++ b/src/engine/mutation/Mutation.ts @@ -1,6 +1,7 @@ +import { uniq } from 'lodash'; import { passOrThrow, isArray, isFunction, mapOverProperties } from '../util'; -import * as _ from 'lodash'; +import { Entity } from '../entity/Entity'; export const MUTATION_TYPE_CREATE = 'create'; export const MUTATION_TYPE_UPDATE = 'update'; @@ -16,26 +17,53 @@ export const defaultEntityMutations = [ { name: 'create', type: MUTATION_TYPE_CREATE, - description: typeName => `Create a new **\`${typeName}\`**`, + description: (typeName: string) => `Create a new **\`${typeName}\`**`, hasAttributes: true, }, { name: 'update', type: MUTATION_TYPE_UPDATE, - description: typeName => + description: (typeName: string) => `Update a single **\`${typeName}\`** using its node ID and a data patch`, hasAttributes: true, }, { name: 'delete', - description: typeName => + description: (typeName: string) => `Delete a single **\`${typeName}\`** using its node ID`, type: MUTATION_TYPE_DELETE, }, ]; +export type MutationSetup = { + name?: string; + type?: string; + description?: string; + attributes?: string[]; + preProcessor?: Function; + postProcessor?: Function; + fromState?: string | string[]; + toState?: string | string[]; +}; + export class Mutation { - constructor(setup = {}) { + name: string; + type: string; + description: string; + attributes: string[]; + fromState: string | string[]; + toState: string | string[]; + + preProcessor: Function; + postProcessor: Function; + + isTypeCreate?: boolean; + isTypeDelete?: boolean; + needsInstance?: boolean; + ignoreRequired?: boolean; + isTypeUpdate?: boolean; + + constructor(setup: MutationSetup = {} as MutationSetup) { const { name, type, @@ -111,9 +139,7 @@ export class Mutation { passOrThrow( this.type !== MUTATION_TYPE_CREATE, () => - `Mutation '${ - this.name - }' cannot define fromState as it is a 'create' type mutation`, + `Mutation '${this.name}' cannot define fromState as it is a 'create' type mutation`, ); passOrThrow( @@ -126,9 +152,7 @@ export class Mutation { passOrThrow( toState, () => - `Mutation '${ - this.name - }' has a fromState defined but misses a toState definition`, + `Mutation '${this.name}' has a fromState defined but misses a toState definition`, ); } @@ -139,26 +163,20 @@ export class Mutation { passOrThrow( this.type !== MUTATION_TYPE_DELETE, () => - `Mutation '${ - this.name - }' cannot define toState as it is a 'delete' type mutation`, + `Mutation '${this.name}' cannot define toState as it is a 'delete' type mutation`, ); passOrThrow( typeof toState === 'string' || isArray(toState), () => - `toState in mutation '${ - this.name - }' needs to be the name of a state or a list of state names the mutation can transition to`, + `toState in mutation '${this.name}' needs to be the name of a state or a list of state names the mutation can transition to`, ); if (this.type !== MUTATION_TYPE_CREATE) { passOrThrow( fromState, () => - `Mutation '${ - this.name - }' has a toState defined but misses a fromState definition`, + `Mutation '${this.name}' has a toState defined but misses a fromState definition`, ); } @@ -171,26 +189,25 @@ export class Mutation { } } -export const isMutation = obj => { +export const isMutation = (obj: any) => { return obj instanceof Mutation; }; -export const processEntityMutations = (entity, mutations) => { +export const processEntityMutations = ( + entity: Entity, + mutations: Mutation[], +) => { passOrThrow( isArray(mutations), () => - `Entity '${ - entity.name - }' mutations definition needs to be an array of mutations`, + `Entity '${entity.name}' mutations definition needs to be an array of mutations`, ); mutations.map((mutation, idx) => { passOrThrow( isMutation(mutation), () => - `Invalid mutation definition for entity '${ - entity.name - }' at position '${idx}'`, + `Invalid mutation definition for entity '${entity.name}' at position '${idx}'`, ); }); @@ -224,38 +241,28 @@ export const processEntityMutations = (entity, mutations) => { mutation.type === MUTATION_TYPE_CREATE) || isArray(mutation.attributes, false), () => - `Mutation '${entity.name}.${ - mutation.name - }' needs to have a list of attributes`, + `Mutation '${entity.name}.${mutation.name}' needs to have a list of attributes`, ); mutation.attributes.map(attribute => { passOrThrow( typeof attribute === 'string', () => - `Mutation '${entity.name}.${ - mutation.name - }' needs to have a list of attribute names`, + `Mutation '${entity.name}.${mutation.name}' needs to have a list of attribute names`, ); }); passOrThrow( - mutation.attributes.length === _.uniq(mutation.attributes).length, + mutation.attributes.length === uniq(mutation.attributes).length, () => - `Mutation '${entity.name}.${ - mutation.name - }' needs to have a list of unique attribute names`, + `Mutation '${entity.name}.${mutation.name}' needs to have a list of unique attribute names`, ); mutation.attributes.map(attributeName => { passOrThrow( entityAttributes[attributeName], () => - `Cannot use attribute '${ - entity.name - }.${attributeName}' in mutation '${entity.name}.${ - mutation.name - }' as it does not exist`, + `Cannot use attribute '${entity.name}.${attributeName}' in mutation '${entity.name}.${mutation.name}' as it does not exist`, ); }); @@ -276,8 +283,7 @@ export const processEntityMutations = (entity, mutations) => { )} ]`, ); } - } - else if ( + } else if ( mutation.type === MUTATION_TYPE_CREATE || mutation.type === MUTATION_TYPE_UPDATE ) { @@ -295,15 +301,13 @@ export const processEntityMutations = (entity, mutations) => { const checkMutationStates = stateStringOrArray => { const stateNames = isArray(stateStringOrArray) ? stateStringOrArray - : [ stateStringOrArray ]; + : [stateStringOrArray]; stateNames.map(stateName => { passOrThrow( entityStates[stateName], () => - `Unknown state '${stateName}' used in mutation '${entity.name}.${ - mutation.name - }'`, + `Unknown state '${stateName}' used in mutation '${entity.name}.${mutation.name}'`, ); }); }; @@ -312,9 +316,7 @@ export const processEntityMutations = (entity, mutations) => { passOrThrow( entity.hasStates(), () => - `Mutation '${entity.name}.${ - mutation.name - }' cannot define fromState as the entity is stateless`, + `Mutation '${entity.name}.${mutation.name}' cannot define fromState as the entity is stateless`, ); checkMutationStates(mutation.fromState); @@ -324,9 +326,7 @@ export const processEntityMutations = (entity, mutations) => { passOrThrow( entity.hasStates(), () => - `Mutation '${entity.name}.${ - mutation.name - }' cannot define toState as the entity is stateless`, + `Mutation '${entity.name}.${mutation.name}' cannot define toState as the entity is stateless`, ); checkMutationStates(mutation.toState); diff --git a/src/engine/permission/Permission.spec.js b/src/engine/permission/Permission.spec.ts similarity index 95% rename from src/engine/permission/Permission.spec.js rename to src/engine/permission/Permission.spec.ts index 2816e085..5296d250 100644 --- a/src/engine/permission/Permission.spec.js +++ b/src/engine/permission/Permission.spec.ts @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/no-empty-function */ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ import { Permission, @@ -49,7 +50,7 @@ describe('Permission', () => { }) .value('someAttribute', 987); - expect(permission.roles).toEqual([ 'manager', 'admin' ]); + expect(permission.roles).toEqual(['manager', 'admin']); expect(permission.lookups).toEqual([ { entity: Language, @@ -202,9 +203,9 @@ describe('Permission', () => { function fn() { passOrThrow( - isPermissionsArray([ permission ]) && - isPermissionsArray([ permission, permission ]) && - isPermissionsArray([ permission, permission, permission ]), + isPermissionsArray([permission]) && + isPermissionsArray([permission, permission]) && + isPermissionsArray([permission, permission, permission]), () => 'This error will never happen', ); } @@ -223,11 +224,11 @@ describe('Permission', () => { isPermissionsArray({}) || isPermissionsArray(function test() {}) || isPermissionsArray(Error) || - isPermissionsArray([ {} ]) || - isPermissionsArray([ function test() {} ]) || - isPermissionsArray([ Error ]) || - isPermissionsArray([ permission, null ]) || - isPermissionsArray([ permission, {}, permission ]), + isPermissionsArray([{}]) || + isPermissionsArray([function test() {}]) || + isPermissionsArray([Error]) || + isPermissionsArray([permission, null]) || + isPermissionsArray([permission, {}, permission]), () => 'Not a Permissions array', ); } @@ -369,10 +370,12 @@ describe('Permission', () => { }); it('should generate a description based on defined permissions', () => { - const tests = [ - [ new Permission().everyone(), 'everyone' ], - [ new Permission().authenticated(), 'authenticated' ], - [ new Permission().role('manager'), 'role manager' ], + type Test = [Permission | Permission[], string]; + + const tests: Test[] = [ + [new Permission().everyone(), 'everyone'], + [new Permission().authenticated(), 'authenticated'], + [new Permission().role('manager'), 'role manager'], [ new Permission().userAttribute('publisher'), 'userAttributes publisher', @@ -381,7 +384,7 @@ describe('Permission', () => { new Permission().lookup(Language, { createdBy: 'someAttribute' }), 'lookup Language someAttribute', ], - [ new Permission().value('someAttribute', 123), 'value someAttribute' ], + [new Permission().value('someAttribute', 123), 'value someAttribute'], [ new Permission() .role('manager') @@ -405,7 +408,7 @@ describe('Permission', () => { ], ]; - tests.map(([ permission, testName ]) => { + tests.map(([permission, testName]) => { expect(generatePermissionDescription(permission)).toMatchSnapshot( testName, ); @@ -423,7 +426,7 @@ describe('Permission', () => { describe('permissions check simple', () => { const userId = 123; - const userRoles = [ 'manager', 'reviewer' ]; + const userRoles = ['manager', 'reviewer']; it('should reject if non-Permission object is provided', () => { function fn() { @@ -494,7 +497,7 @@ describe('Permission', () => { describe('build permission filter', () => { const userId = 123; - const userRoles = [ 'manager', 'reviewer' ]; + const userRoles = ['manager', 'reviewer']; const someEntity = new Entity({ name: 'SomeEntityName', @@ -692,7 +695,7 @@ describe('Permission', () => { district: ({ input }) => input.district, open: () => true, owner: ({ userId }) => userId, // eslint-disable-line no-shadow - state: () => [ 'defined', 'approved' ], + state: () => ['defined', 'approved'], }); const input = { @@ -909,7 +912,7 @@ describe('Permission', () => { }); it('should throw if provided with an invalid map of permissions', () => { - const permissions = [ 'bad' ]; + const permissions = ['bad']; function fn() { processEntityPermissions(entity, permissions); @@ -920,7 +923,7 @@ describe('Permission', () => { it('should throw if provided with an invalid map of mutation permissions', () => { const permissions = { - mutations: [ 'bad' ], + mutations: ['bad'], }; function fn() { @@ -932,7 +935,7 @@ describe('Permission', () => { it('should throw if provided with an invalid permissions', () => { const permissions1 = { - read: [ 'bad' ], + read: ['bad'], }; function fn1() { @@ -942,7 +945,7 @@ describe('Permission', () => { expect(fn1).toThrowErrorMatchingSnapshot(); const permissions2 = { - find: [ 'bad' ], + find: ['bad'], }; function fn2() { @@ -954,7 +957,7 @@ describe('Permission', () => { const permissions3 = { mutations: { mutations: { - create: [ 'bad' ], + create: ['bad'], }, }, }; @@ -1079,7 +1082,7 @@ describe('Permission', () => { }); it('should throw if provided with invalid permissions', () => { - const permissions1 = [ 'bad' ]; + const permissions1 = ['bad']; function fn1() { processActionPermissions(action, permissions1); @@ -1088,7 +1091,7 @@ describe('Permission', () => { expect(fn1).toThrowErrorMatchingSnapshot(); const permissions2 = { - find: [ 'bad' ], + find: ['bad'], }; function fn2() { diff --git a/src/engine/permission/Permission.ts b/src/engine/permission/Permission.ts index 7e078e84..9f872a24 100644 --- a/src/engine/permission/Permission.ts +++ b/src/engine/permission/Permission.ts @@ -1,11 +1,16 @@ +import * as _ from 'lodash'; import { passOrThrow, isMap, isArray, isFunction, asyncForEach } from '../util'; +import { Action } from '../action/Action'; import { Entity, isEntity } from '../entity/Entity'; import { ViewEntity } from '../entity/ViewEntity'; import { isDataTypeUser } from '../datatype/DataTypeUser'; -import { MUTATION_TYPE_CREATE, isMutation } from '../mutation/Mutation'; +import { + MUTATION_TYPE_CREATE, + isMutation, + Mutation, +} from '../mutation/Mutation'; import { isDataTypeState } from '../datatype/DataTypeState'; -import * as _ from 'lodash'; /* all permission rules are ... @@ -15,9 +20,9 @@ import * as _ from 'lodash'; */ const compatibilityList = [ - [ 'everyone', 'lookup', 'value', 'state' ], - [ 'authenticated', 'role', 'userAttribute', 'lookup', 'value', 'state' ], - [ 'role', 'userAttribute', 'lookup', 'value', 'state' ], + ['everyone', 'lookup', 'value', 'state'], + ['authenticated', 'role', 'userAttribute', 'lookup', 'value', 'state'], + ['role', 'userAttribute', 'lookup', 'value', 'state'], ]; export class Permission { @@ -174,11 +179,11 @@ export class Permission { } } -export const isPermission = obj => { +export const isPermission = (obj: any) => { return obj instanceof Permission; }; -export const isPermissionsArray = obj => { +export const isPermissionsArray = (obj?: any) => { if (isArray(obj, true)) { return obj.reduce( (prev, permission) => prev && isPermission(permission), @@ -188,29 +193,31 @@ export const isPermissionsArray = obj => { return false; }; -export const findInvalidPermissionAttributes = (permission, entity) => { +export const findInvalidPermissionAttributes = ( + permission: Permission, + entity: Entity, +) => { const attributes = entity.getAttributes(); permission.userAttributes.map(userAttribute => { const attribute = attributes[userAttribute]; + const attributeTypeAsEntity = attribute.type as Entity; passOrThrow( attribute && (isDataTypeUser(attribute.type) || (entity.isUserEntity && entity.getPrimaryAttribute() === attribute) || - (isEntity(attribute.type) && attribute.type.isUserEntity)), + (isEntity(attribute.type) && attributeTypeAsEntity.isUserEntity)), () => - `Cannot use attribute '${userAttribute}' in '${ - entity.name - }.permissions' as 'userAttribute' as it is not a reference to the User entity`, + `Cannot use attribute '${userAttribute}' in '${entity.name}.permissions' as 'userAttribute' as it is not a reference to the User entity`, ); }); }; export const findMissingPermissionAttributes = ( - permission, - permissionEntity, - mutation, + permission: Permission, + permissionEntity: Entity, + mutation?: Mutation, ) => { const entityAttributeNames = Object.keys(permissionEntity.getAttributes()); @@ -240,8 +247,7 @@ export const findMissingPermissionAttributes = ( ) { missingLookupAttribute = sourceAttribute; return; - } - else if (!lookupEntityAttributeNames.includes(targetAttribute)) { + } else if (!lookupEntityAttributeNames.includes(targetAttribute)) { missingLookupAttribute = `${entity.name}.${targetAttribute}`; return; } @@ -252,9 +258,7 @@ export const findMissingPermissionAttributes = ( !isFunction(sourceAttribute) ) { throw new Error( - `'lookup' type permission used in 'create' type mutation '${ - mutation.name - }' can only have mappings to value functions`, + `'lookup' type permission used in 'create' type mutation '${mutation.name}' can only have mappings to value functions`, ); } }); @@ -305,16 +309,12 @@ export const validateActionLookupPermission = ( passOrThrow( isFunction(sourceAttribute), () => - `Only functions are allowed in '${ - permissionAction.name - }.permissions' for value lookups`, + `Only functions are allowed in '${permissionAction.name}.permissions' for value lookups`, ); passOrThrow( lookupEntityAttributeNames.includes(targetAttribute), () => - `Cannot use attribute '${targetAttribute}' in '${ - permissionAction.name - }.permissions' as it does not exist`, + `Cannot use attribute '${targetAttribute}' in '${permissionAction.name}.permissions' as it does not exist`, ); }); }); @@ -323,7 +323,7 @@ export const validateActionLookupPermission = ( export const generatePermissionDescription = permissions => { const descriptions = []; - const permissionsArray = isArray(permissions) ? permissions : [ permissions ]; + const permissionsArray = isArray(permissions) ? permissions : [permissions]; permissionsArray.map(permission => { const lines = []; @@ -462,7 +462,13 @@ export const isPermissionSimple = permission => { ); }; -export const buildUserAttributesPermissionFilter = ({ permission, userId }) => { +export const buildUserAttributesPermissionFilter = ({ + permission, + userId, +}: { + permission: Permission; + userId: string | number; +}) => { let where; if (permission.userAttributes.length > 0) { @@ -481,7 +487,13 @@ export const buildUserAttributesPermissionFilter = ({ permission, userId }) => { return where; }; -export const buildStatesPermissionFilter = ({ permission, entity }) => { +export const buildStatesPermissionFilter = ({ + permission, + entity, +}: { + permission: Permission; + entity: Entity; +}) => { let where; if (permission.states.length > 0) { @@ -512,7 +524,11 @@ export const buildStatesPermissionFilter = ({ permission, entity }) => { return where; }; -export const buildValuesPermissionFilter = ({ permission }) => { +export const buildValuesPermissionFilter = ({ + permission, +}: { + permission: Permission; +}) => { let where; if (permission.values.length > 0) { @@ -534,7 +550,13 @@ export const buildLookupsPermissionFilter = async ({ userId, userRoles, input, - context + context, +}: { + permission: Permission; + userId?: string | number; + userRoles?: any; + input?: any; + context?: any; }) => { let where; @@ -553,7 +575,12 @@ export const buildLookupsPermissionFilter = async ({ let operator = '$eq'; if (isFunction(sourceAttribute)) { - let value = await sourceAttribute({ userId, userRoles, input, context }); + let value = await sourceAttribute({ + userId, + userRoles, + input, + context, + }); const attr = entity.getAttributes(); @@ -578,8 +605,7 @@ export const buildLookupsPermissionFilter = async ({ operator, value, }); - } - else { + } else { condition.push({ targetAttribute, operator, @@ -603,12 +629,12 @@ export const buildLookupsPermissionFilter = async ({ }; export const buildPermissionFilterSingle = async ( - permission, - userId, - userRoles, - entity, - input, - context + permission: Permission, + userId?: string | number, + userRoles?: any, + entity?: Entity, + input?: any, + context?: any, ) => { let where; @@ -633,12 +659,12 @@ export const buildPermissionFilterSingle = async ( }; export const buildPermissionFilter = async ( - _permissions, - userId, - userRoles, - entity, - input, - context + _permissions: Permission | Permission[], + userId?: string | number, + userRoles?: any, + entity?: Entity, + input?: any, + context?: any, ) => { let where; @@ -646,11 +672,13 @@ export const buildPermissionFilter = async ( return where; } - const permissions = isArray(_permissions) ? _permissions : [ _permissions ]; + const permissions = isArray(_permissions as any[]) + ? _permissions + : [_permissions]; let foundSimplePermission = false; - await asyncForEach(permissions, async permission => { + await asyncForEach(permissions as any[], async permission => { if (foundSimplePermission) { return; } @@ -671,7 +699,7 @@ export const buildPermissionFilter = async ( userRoles, entity, input, - context + context, ); if (permissionFilter) { @@ -691,7 +719,7 @@ export const buildActionPermissionFilter = async ( userRoles, action, input, - context + context, ) => { let where; let lookupPermissionEntity; @@ -700,7 +728,7 @@ export const buildActionPermissionFilter = async ( return where; } - const permissions = isArray(_permissions) ? _permissions : [ _permissions ]; + const permissions = isArray(_permissions) ? _permissions : [_permissions]; let foundSimplePermission = false; @@ -720,7 +748,14 @@ export const buildActionPermissionFilter = async ( return; } - const params = { permission, userId, userRoles, action, input, context }; + const params = { + permission, + userId, + userRoles, + action, + input, + context, + }; const permissionFilter = await buildLookupsPermissionFilter(params); if (permissionFilter) { @@ -766,7 +801,7 @@ const validatePermissionAttributesAndStates = ( permissions, _mutation, ) => { - const permissionsArray = isArray(permissions) ? permissions : [ permissions ]; + const permissionsArray = isArray(permissions) ? permissions : [permissions]; const mutation = isMutation(_mutation) ? _mutation : null; @@ -784,9 +819,7 @@ const validatePermissionAttributesAndStates = ( passOrThrow( !invalidAttribute, () => - `Cannot use attribute '${invalidAttribute}' in '${ - entity.name - }.permissions' for '${mutationName}' as it does not exist`, + `Cannot use attribute '${invalidAttribute}' in '${entity.name}.permissions' for '${mutationName}' as it does not exist`, ); findInvalidPermissionAttributes(permission, entity); @@ -797,9 +830,7 @@ const validatePermissionAttributesAndStates = ( passOrThrow( !invalidState, () => - `Cannot use state '${invalidState}' in '${ - entity.name - }.permissions' for '${mutationName}' as it does not exist`, + `Cannot use state '${invalidState}' in '${entity.name}.permissions' for '${mutationName}' as it does not exist`, ); } }); @@ -807,7 +838,7 @@ const validatePermissionAttributesAndStates = ( const validatePermissionMutationTypes = (entity, permissions, mutation) => { if (mutation.type === MUTATION_TYPE_CREATE) { - const permissionsArray = isArray(permissions) ? permissions : [ permissions ]; + const permissionsArray = isArray(permissions) ? permissions : [permissions]; permissionsArray.map(permission => { passOrThrow( @@ -815,9 +846,7 @@ const validatePermissionMutationTypes = (entity, permissions, mutation) => { !permission.states.length && !permission.values.length, () => - `Create type mutation permission '${mutation.name}' in '${ - entity.name - }.permissions' can only be of type 'authenticated', 'everyone', 'role' or 'lookup'`, + `Create type mutation permission '${mutation.name}' in '${entity.name}.permissions' can only be of type 'authenticated', 'everyone', 'role' or 'lookup'`, ); }); } @@ -874,8 +903,7 @@ export const processEntityPermissions = ( isPermission(permissions.read) || isPermissionsArray(permissions.read), () => `Invalid 'read' permission definition for entity '${entity.name}'`, ); - } - else if (defaultPermissions) { + } else if (defaultPermissions) { permissions.read = defaultPermissions.read; } @@ -884,8 +912,7 @@ export const processEntityPermissions = ( isPermission(permissions.find) || isPermissionsArray(permissions.find), () => `Invalid 'find' permission definition for entity '${entity.name}'`, ); - } - else if (defaultPermissions) { + } else if (defaultPermissions) { permissions.find = defaultPermissions.find; } @@ -899,9 +926,7 @@ export const processEntityPermissions = ( passOrThrow( isMap(permissions.mutations), () => - `Entity '${ - entity.name - }' permissions definition for mutations needs to be a map of mutations and permissions`, + `Entity '${entity.name}' permissions definition for mutations needs to be a map of mutations and permissions`, ); const mutationNames = Object.keys(permissions.mutations); @@ -910,9 +935,7 @@ export const processEntityPermissions = ( isPermission(permissions.mutations[mutationName]) || isPermissionsArray(permissions.mutations[mutationName]), () => - `Invalid mutation permission definition for entity '${ - entity.name - }' at position '${idx}'`, + `Invalid mutation permission definition for entity '${entity.name}' at position '${idx}'`, ); }); @@ -945,9 +968,7 @@ export const processEntityPermissions = ( passOrThrow( mutationNames.includes(permissionMutationName), () => - `Unknown mutation '${permissionMutationName}' used for permissions in entity '${ - entity.name - }'`, + `Unknown mutation '${permissionMutationName}' used for permissions in entity '${entity.name}'`, ); }); @@ -993,8 +1014,7 @@ export const processViewEntityPermissions = ( isPermission(permissions.read) || isPermissionsArray(permissions.read), () => `Invalid 'read' permission definition for entity '${entity.name}'`, ); - } - else if (defaultPermissions) { + } else if (defaultPermissions) { permissions.read = defaultPermissions.read; } @@ -1003,8 +1023,7 @@ export const processViewEntityPermissions = ( isPermission(permissions.find) || isPermissionsArray(permissions.find), () => `Invalid 'find' permission definition for entity '${entity.name}'`, ); - } - else if (defaultPermissions) { + } else if (defaultPermissions) { permissions.find = defaultPermissions.find; } @@ -1031,13 +1050,13 @@ export const processViewEntityPermissions = ( return permissions; }; -export const processActionPermissions = (action, permissions) => { +export const processActionPermissions = (action: Action, permissions) => { passOrThrow( isPermission(permissions) || isPermissionsArray(permissions), () => `Invalid permission definition for action '${action.name}'`, ); - const permissionsArray = isArray(permissions) ? permissions : [ permissions ]; + const permissionsArray = isArray(permissions) ? permissions : [permissions]; permissionsArray.map(permission => { passOrThrow( diff --git a/src/engine/protocol/ProtocolConfiguration.js b/src/engine/protocol/ProtocolConfiguration.ts similarity index 52% rename from src/engine/protocol/ProtocolConfiguration.js rename to src/engine/protocol/ProtocolConfiguration.ts index 0bf50c58..f71153c1 100644 --- a/src/engine/protocol/ProtocolConfiguration.js +++ b/src/engine/protocol/ProtocolConfiguration.ts @@ -1,8 +1,17 @@ import { passOrThrow, isString, isArray } from '../util'; +export type ProtocolConfigurationSetup = { + features?: string[]; +}; + export class ProtocolConfiguration { - constructor(setup = {}) { - this.features = []; + features: { [key: string]: boolean }; + + constructor( + setup: ProtocolConfigurationSetup = {} as ProtocolConfigurationSetup, + ) { + // this.features = []; + this.features = {}; const { features } = setup; @@ -11,7 +20,7 @@ export class ProtocolConfiguration { } } - enableFeature(feature, enable = true) { + enableFeature(feature: string, enable = true): void { passOrThrow( isString(feature), () => 'enableFeature() expects a feature name', @@ -20,7 +29,7 @@ export class ProtocolConfiguration { this.features[feature] = !!enable; } - enableFeatures(features, enable = true) { + enableFeatures(features: string[], enable = true): void { passOrThrow( isArray(features), () => 'enableFeatures() expects an array of feature names', @@ -29,11 +38,12 @@ export class ProtocolConfiguration { features.map(feature => this.enableFeature(feature, enable)); } - getEnabledFeatures() { + getEnabledFeatures(): { [key: string]: boolean } { return this.features; } } -export const isProtocolConfiguration = obj => { +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export const isProtocolConfiguration = (obj: any): boolean => { return obj instanceof ProtocolConfiguration; }; diff --git a/src/engine/protocol/ProtocolType.spec.js b/src/engine/protocol/ProtocolType.spec.ts similarity index 98% rename from src/engine/protocol/ProtocolType.spec.js rename to src/engine/protocol/ProtocolType.spec.ts index 796718e7..74c46b37 100644 --- a/src/engine/protocol/ProtocolType.spec.js +++ b/src/engine/protocol/ProtocolType.spec.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ + import { ProtocolType, isProtocolType } from './ProtocolType'; import { DataTypeID, diff --git a/src/engine/protocol/ProtocolType.js b/src/engine/protocol/ProtocolType.ts similarity index 64% rename from src/engine/protocol/ProtocolType.js rename to src/engine/protocol/ProtocolType.ts index 78ab7967..b938db4a 100644 --- a/src/engine/protocol/ProtocolType.js +++ b/src/engine/protocol/ProtocolType.ts @@ -1,10 +1,49 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + import { passOrThrow, isFunction } from '../util'; -import { isDataType } from '../datatype/DataType'; -import { isProtocolConfiguration } from './ProtocolConfiguration'; +import { DataType, DataTypeFunction, isDataType } from '../datatype/DataType'; +import { + ProtocolConfiguration, + isProtocolConfiguration, +} from './ProtocolConfiguration'; + +export type ProtocolTypeSetup = { + name?: string; + description?: string; + // isProtocolDataType?: Function; + isProtocolDataType?: (protocolDataType: any) => boolean; +}; + +// export interface ProtocolDataTypeFunction { +// schemaDataType: DataType; +// attribute: string; +// asInput?: boolean; +// } + +export type ProtocolDataType = { + name: string | Function; +}; + +type DataTypeMap = { + [name: string]: ProtocolDataType; +}; + +type DynamicDataTypeMap = { + schemaDataTypeDetector: Function; + protocolDataType: ProtocolDataType; +}; export class ProtocolType { - constructor(setup = {}) { + name: string; + description: string; + isProtocolDataType: (protocolDataType: any) => boolean; + protocolConfiguration: ProtocolConfiguration; + + private _dataTypeMap: DataTypeMap; + private _dynamicDataTypeMap: DynamicDataTypeMap[]; + + constructor(setup: ProtocolTypeSetup = {} as ProtocolTypeSetup) { const { name, description, isProtocolDataType } = setup; passOrThrow(name, () => 'Missing protocol type name'); @@ -26,7 +65,10 @@ export class ProtocolType { this._dynamicDataTypeMap = []; } - addDataTypeMap(schemaDataType, protocolDataType) { + addDataTypeMap( + schemaDataType: DataType | DataTypeFunction, + protocolDataType: ProtocolDataType, + ): void { passOrThrow( isDataType(schemaDataType), () => @@ -50,7 +92,10 @@ export class ProtocolType { this._dataTypeMap[schemaDataType.name] = protocolDataType; } - addDynamicDataTypeMap(schemaDataTypeDetector, protocolDataType) { + addDynamicDataTypeMap( + schemaDataTypeDetector: Function, + protocolDataType: ProtocolType, + ): void { passOrThrow( isFunction(schemaDataTypeDetector), () => @@ -73,7 +118,11 @@ export class ProtocolType { }); } - convertToProtocolDataType(schemaDataType, sourceName, asInput) { + convertToProtocolDataType( + schemaDataType: DataType | DataTypeFunction, + sourceName?: string, + asInput?: boolean, + ): ProtocolDataType { const foundDynamicDataType = this._dynamicDataTypeMap.find( ({ schemaDataTypeDetector }) => schemaDataTypeDetector(schemaDataType), ); @@ -82,7 +131,8 @@ export class ProtocolType { if (isFunction(protocolDataType)) { const attributeType = schemaDataType; - return protocolDataType(attributeType, sourceName, asInput); + const protocolDataTypeFn = protocolDataType as Function; + return protocolDataTypeFn(attributeType, sourceName, asInput); } return protocolDataType; @@ -103,7 +153,7 @@ export class ProtocolType { return this._dataTypeMap[schemaDataType.name]; } - setProtocolConfiguration(protocolConfiguration) { + setProtocolConfiguration(protocolConfiguration): void { passOrThrow( isProtocolConfiguration(protocolConfiguration), () => 'ProtocolType expects a valid protocolConfiguration', @@ -112,7 +162,7 @@ export class ProtocolType { this.protocolConfiguration = protocolConfiguration; } - getProtocolConfiguration() { + getProtocolConfiguration(): ProtocolConfiguration { passOrThrow( this.protocolConfiguration, () => 'ProtocolType is missing a valid protocolConfiguration', @@ -121,11 +171,11 @@ export class ProtocolType { return this.protocolConfiguration; } - toString() { + toString(): string { return this.name; } } -export const isProtocolType = obj => { +export const isProtocolType = (obj: any): boolean => { return obj instanceof ProtocolType; }; diff --git a/src/engine/schema/Schema.spec.js b/src/engine/schema/Schema.spec.ts similarity index 94% rename from src/engine/schema/Schema.spec.js rename to src/engine/schema/Schema.spec.ts index 69329204..162f3e0d 100644 --- a/src/engine/schema/Schema.spec.js +++ b/src/engine/schema/Schema.spec.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ + import { Entity } from '../entity/Entity'; import { Schema } from './Schema'; @@ -44,7 +46,7 @@ describe('Schema', () => { // eslint-disable-next-line no-new new Schema({ - entities: [ FirstEntity, SecondEntity ], + entities: [FirstEntity, SecondEntity], }); }); @@ -100,7 +102,7 @@ describe('Schema', () => { function fn4() { // eslint-disable-next-line no-new new Schema({ - entities: [ 'so-wrong' ], + entities: ['so-wrong'], }); } diff --git a/src/engine/schema/Schema.js b/src/engine/schema/Schema.ts similarity index 91% rename from src/engine/schema/Schema.js rename to src/engine/schema/Schema.ts index fbf0e990..b6af0292 100644 --- a/src/engine/schema/Schema.js +++ b/src/engine/schema/Schema.ts @@ -1,16 +1,45 @@ import { passOrThrow, isArray, isMap } from '../util'; -import { isEntity } from '../entity/Entity'; -import { isAction } from '../action/Action'; +import { Entity, isEntity } from '../entity/Entity'; +import { Action, isAction } from '../action/Action'; import { isDataTypeUser } from '../datatype/DataTypeUser'; -import { isStorageType } from '../storage/StorageType'; +import { StorageType, isStorageType } from '../storage/StorageType'; import { isPermission, isPermissionsArray } from '../permission/Permission'; import { isViewEntity } from '../entity/ViewEntity'; import { isShadowEntity } from '../entity/ShadowEntity'; +export type SchemaSetup = { + entities?: Entity[] | null; + defaultStorageType?: StorageType | null; + actions?: Action[] | null; + defaultActionPermissions?: null; + permissionsMap?: PermissionsMap | null; +}; + +type EntityPermission = { + // improve typing + [key: string]: any; + // [entityName: string]: Permission; + // _defaultPermissions: Permission | Permission[] | null; +}; + +type PermissionsMap = { + entities: EntityPermission; +}; + export class Schema { + private _entityMap = {}; + private _actionMap = {}; + private _isValidated: boolean; + private _userEntity = null; + + defaultStorageType: StorageType; + permissionsMap: PermissionsMap | null; + + defaultActionPermissions; + constructor( - setup = { + setup: SchemaSetup = { entities: null, defaultStorageType: null, actions: null, @@ -176,7 +205,7 @@ export class Schema { const entityDefaultPermissions = this.permissionsMap.entities[entity.name] || {}; entityDefaultPermissions.mutations = - entityDefaultPermissions.mutations || {}; + entityDefaultPermissions.mutations || ({} as Entity); const defaultPermissions = this.permissionsMap.entities ._defaultPermissions; diff --git a/src/engine/storage/StorageConfiguration.js b/src/engine/storage/StorageConfiguration.ts similarity index 79% rename from src/engine/storage/StorageConfiguration.js rename to src/engine/storage/StorageConfiguration.ts index 687ccda5..af13a6cb 100644 --- a/src/engine/storage/StorageConfiguration.js +++ b/src/engine/storage/StorageConfiguration.ts @@ -1,7 +1,22 @@ import { passOrThrow } from '../util'; +export type StorageConfigurationSetup = { + // todo improve typings ? + name?: string; + storageInstance?: any; + storageModels?: any; + connectionConfig?: any; +}; + export class StorageConfiguration { - constructor(setup = {}) { + name: string; + storageInstance: any; + storageModels: any; + connectionConfig: any; + + constructor( + setup: StorageConfigurationSetup = {} as StorageConfigurationSetup, + ) { const { name, storageInstance, storageModels, connectionConfig } = setup; if (name) { diff --git a/src/engine/storage/StorageDataType.spec.js b/src/engine/storage/StorageDataType.spec.ts similarity index 94% rename from src/engine/storage/StorageDataType.spec.js rename to src/engine/storage/StorageDataType.spec.ts index 6af61738..f67baa4f 100644 --- a/src/engine/storage/StorageDataType.spec.js +++ b/src/engine/storage/StorageDataType.spec.ts @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/no-empty-function */ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ import { StorageDataType, isStorageDataType } from './StorageDataType'; import { passOrThrow } from '../util'; @@ -87,7 +88,7 @@ describe('StorageDataType', () => { description: 'Just some description', nativeDataType: String, serialize() {}, - capabilities: [ 'in', 'ne', 'magic_unicorn_filter' ], + capabilities: ['in', 'ne', 'magic_unicorn_filter'], }); } @@ -100,10 +101,10 @@ describe('StorageDataType', () => { description: 'Just some description', nativeDataType: String, serialize() {}, - capabilities: [ 'in', 'ne', 'contains' ], + capabilities: ['in', 'ne', 'contains'], }); - expect(storageDataType.capabilities).toEqual([ 'in', 'ne', 'contains' ]); + expect(storageDataType.capabilities).toEqual(['in', 'ne', 'contains']); }); it('should fall back to a simple parse function if none provided', () => { diff --git a/src/engine/storage/StorageDataType.js b/src/engine/storage/StorageDataType.ts similarity index 72% rename from src/engine/storage/StorageDataType.js rename to src/engine/storage/StorageDataType.ts index 081bc8a4..a1551524 100644 --- a/src/engine/storage/StorageDataType.js +++ b/src/engine/storage/StorageDataType.ts @@ -2,8 +2,29 @@ import { passOrThrow, isFunction, isArray } from '../util'; import { storageDataTypeCapabilities } from '../constants'; +export type StorageDataTypeSetup = { + name?: string; + description?: string; + // improve nativeDataType typing + nativeDataType?: any; + isSortable?: boolean; + serialize?: Function; + enforceSerialize?: boolean; + parse?: Function; + capabilities?: string[]; +}; + export class StorageDataType { - constructor(setup = {}) { + name: string; + description: string; + nativeDataType: any; + isSortable?: boolean; + serialize: Function; + enforceSerialize?: boolean; + parse?: Function; + capabilities?: string[]; + + constructor(setup: StorageDataTypeSetup = {} as StorageDataTypeSetup) { const { name, description, @@ -56,7 +77,7 @@ export class StorageDataType { this.isSortable = !!isSortable; this.serialize = serialize; this.enforceSerialize = !!enforceSerialize; - this.parse = parse || (value => value); + this.parse = parse || ((value: any) => value); this.capabilities = capabilities || []; } @@ -65,6 +86,6 @@ export class StorageDataType { } } -export const isStorageDataType = obj => { +export const isStorageDataType = (obj: any) => { return obj instanceof StorageDataType; }; diff --git a/src/engine/storage/StorageType.spec.js b/src/engine/storage/StorageType.spec.ts similarity index 98% rename from src/engine/storage/StorageType.spec.js rename to src/engine/storage/StorageType.spec.ts index ec837264..3c6f92db 100644 --- a/src/engine/storage/StorageType.spec.js +++ b/src/engine/storage/StorageType.spec.ts @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/no-empty-function */ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ import { StorageType, isStorageType } from './StorageType'; import { StorageDataType } from './StorageDataType'; diff --git a/src/engine/storage/StorageType.js b/src/engine/storage/StorageType.ts similarity index 65% rename from src/engine/storage/StorageType.js rename to src/engine/storage/StorageType.ts index a1a4c289..c4aa99b5 100644 --- a/src/engine/storage/StorageType.js +++ b/src/engine/storage/StorageType.ts @@ -1,11 +1,69 @@ import { passOrThrow, isFunction } from '../util'; -import { isDataType } from '../datatype/DataType'; +import { isDataType, DataType } from '../datatype/DataType'; import { isStorageDataType } from './StorageDataType'; -import { isStorageConfiguration } from './StorageConfiguration'; +import { + StorageConfiguration, + isStorageConfiguration, +} from './StorageConfiguration'; +import { Entity, StorageDataType } from '../..'; +import { Mutation } from '../mutation/Mutation'; + +export type StorageTypeSetup = { + name?: string; + description?: string; + findOne?: ( + entity?: Entity, + id?: any, + args?: Record, + context?: Record, + ) => any; + findOneByValues?: ( + entity?: Entity, + arg?: any, + context?: Record, + ) => any; + find?: ( + entity?: Entity, + args?: Record, + context?: Record, + parentConnection?: any, + ) => any; + count?: ( + entity?: Entity, + args?: Record, + context?: Record, + parentConnection?: any, + ) => number | any; + mutate?: ( + entity?: Entity, + id?: any, + input?: any, + entityMutation?: Mutation, + context?: Record, + ) => void | any; + checkLookupPermission?: ( + entity?: Entity, + where?: any, + context?: Record, + ) => boolean | any; +}; export class StorageType { - constructor(setup = {}) { + name: string; + description: string; + findOne: Function; + findOneByValues: Function; + find: Function; + count: Function; + mutate: Function; + checkLookupPermission: Function; + + private _dataTypeMap; + private _dynamicDataTypeMap; + storageConfiguration: StorageConfiguration; + + constructor(setup: StorageTypeSetup = {} as StorageTypeSetup) { const { name, description, @@ -66,7 +124,7 @@ export class StorageType { this._dynamicDataTypeMap = []; } - addDataTypeMap(schemaDataType, storageDataType) { + addDataTypeMap(schemaDataType: DataType, storageDataType: StorageDataType) { passOrThrow( isDataType(schemaDataType), () => @@ -86,21 +144,21 @@ export class StorageType { passOrThrow( !this._dataTypeMap[schemaDataType.name], () => - `Data type mapping for '${ - schemaDataType.name - }' already registered with storage type '${this.name}'`, + `Data type mapping for '${schemaDataType.name}' already registered with storage type '${this.name}'`, ); this._dataTypeMap[schemaDataType.name] = storageDataType; } - addDynamicDataTypeMap(schemaDataTypeDetector, storageDataType) { + addDynamicDataTypeMap( + schemaDataTypeDetector: Function, + storageDataType: StorageDataType | Function, + ) { passOrThrow( isFunction(schemaDataTypeDetector), () => - `Provided schemaDataTypeDetector is not a valid function in '${ - this.name - }', ` + `got this instead: ${String(schemaDataTypeDetector)}`, + `Provided schemaDataTypeDetector is not a valid function in '${this.name}', ` + + `got this instead: ${String(schemaDataTypeDetector)}`, ); passOrThrow( @@ -118,7 +176,7 @@ export class StorageType { }); } - convertToStorageDataType(schemaDataType) { + convertToStorageDataType(schemaDataType: DataType) { const foundDynamicDataType = this._dynamicDataTypeMap.find( ({ schemaDataTypeDetector }) => schemaDataTypeDetector(schemaDataType), ); @@ -136,23 +194,20 @@ export class StorageType { passOrThrow( isDataType(schemaDataType), () => - `Provided schemaDataType is not a valid data type in storage type '${ - this.name - }', ` + `got this instead: ${String(schemaDataType)}`, + `Provided schemaDataType is not a valid data type in storage type '${this.name}', ` + + `got this instead: ${String(schemaDataType)}`, ); passOrThrow( this._dataTypeMap[schemaDataType.name], () => - `No data type mapping found for '${ - schemaDataType.name - }' in storage type '${this.name}'`, + `No data type mapping found for '${schemaDataType.name}' in storage type '${this.name}'`, ); return this._dataTypeMap[schemaDataType.name]; } - setStorageConfiguration(storageConfiguration) { + setStorageConfiguration(storageConfiguration: StorageConfiguration) { passOrThrow( isStorageConfiguration(storageConfiguration), () => 'StorageType expects a valid storageConfiguration', diff --git a/src/engine/storage/StorageTypeNull.js b/src/engine/storage/StorageTypeNull.ts similarity index 100% rename from src/engine/storage/StorageTypeNull.js rename to src/engine/storage/StorageTypeNull.ts diff --git a/src/engine/util.spec.js b/src/engine/util.spec.ts similarity index 99% rename from src/engine/util.spec.js rename to src/engine/util.spec.ts index 22f453d9..78e04bc3 100644 --- a/src/engine/util.spec.js +++ b/src/engine/util.spec.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ + import { passOrThrow, resolveFunctionMap, diff --git a/src/engine/validation.spec.js b/src/engine/validation.spec.ts similarity index 98% rename from src/engine/validation.spec.js rename to src/engine/validation.spec.ts index 46527a79..e578dece 100644 --- a/src/engine/validation.spec.js +++ b/src/engine/validation.spec.ts @@ -36,8 +36,7 @@ describe('validation', () => { setTimeout(() => { if (value.length > 2) { resolve(); - } - else { + } else { reject(new Error('Firstname too short')); } }, 1); @@ -118,14 +117,14 @@ describe('validation', () => { type: MUTATION_TYPE_CREATE, name: 'build', description: 'build something', - attributes: [ 'someAttribute', 'team' ], + attributes: ['someAttribute', 'team'], }); const mutationUpdate = new Mutation({ type: MUTATION_TYPE_UPDATE, name: 'change', description: 'update something', - attributes: [ 'someAttribute', 'team' ], + attributes: ['someAttribute', 'team'], }); const action1 = new Action({ @@ -331,7 +330,7 @@ describe('validation', () => { team: { teamName: 'Falcons United Team', players: { - offense: [ 'lorem' ], + offense: ['lorem'], }, }, }; diff --git a/src/engine/validation.js b/src/engine/validation.ts similarity index 85% rename from src/engine/validation.js rename to src/engine/validation.ts index 691bcbbd..b7737de1 100644 --- a/src/engine/validation.js +++ b/src/engine/validation.ts @@ -3,9 +3,16 @@ import { isObjectDataType } from './datatype/ObjectDataType'; import { isListDataType } from './datatype/ListDataType'; import { isComplexDataType } from './datatype/ComplexDataType'; import { isMap, passOrThrow, isDefined, asyncForEach } from './util'; -import { MUTATION_TYPE_CREATE } from './mutation/Mutation'; - -const validateDataTypePayload = async (paramType, payload, context) => { +import { MUTATION_TYPE_CREATE, Mutation } from './mutation/Mutation'; +import { Action } from './action/Action'; +import { Entity } from '..'; +// import { Attribute } from './attribute/Attribute'; + +const validateDataTypePayload = async ( + paramType: any, + payload: any, + context?: Record, +): Promise => { const dataTypeValidator = paramType.validate; if (dataTypeValidator) { @@ -13,7 +20,13 @@ const validateDataTypePayload = async (paramType, payload, context) => { } }; -const validatePayload = async (param, payload, source, context, path = []) => { +const validatePayload = async ( + param: any, + payload: any, + source: any, + context?: Record, + path = [], +): Promise => { if (typeof payload !== 'undefined' && payload !== null) { const paramName = param.name; @@ -108,11 +121,11 @@ const validatePayload = async (param, payload, source, context, path = []) => { }; export const validateActionPayload = async ( - param, - payload, - action, - context, -) => { + param: any, + payload: any, + action: Action, + context?: Record, +): Promise => { const newParam = { ...param, name: 'input', @@ -132,12 +145,12 @@ export const validateActionPayload = async ( }; export const validateMutationPayload = async ( - entity, - mutation, - payload, - context, -) => { - const attributes = entity.getAttributes(); + entity: Entity, + mutation: Mutation, + payload: any, + context?: Record, +): Promise => { + const attributes: any = entity.getAttributes(); const systemAttributes = _.filter( attributes, attribute => attribute.isSystemAttribute && attribute.defaultValue, diff --git a/src/graphqlProtocol/action.spec.js b/src/graphqlProtocol/action.spec.js index f79791a4..09e314ac 100644 --- a/src/graphqlProtocol/action.spec.js +++ b/src/graphqlProtocol/action.spec.js @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/no-empty-function */ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ import { generateActions } from './action'; import { ProtocolGraphQL } from './ProtocolGraphQL'; @@ -174,7 +175,7 @@ describe('action', () => { resolve() {}, }); - const actions = [ simpleAction, noInputAction, noOutputAction, complexAction ]; + const actions = [simpleAction, noInputAction, noOutputAction, complexAction]; const graphRegistry = { types: {}, diff --git a/src/graphqlProtocol/dataTypes.spec.js b/src/graphqlProtocol/dataTypes.spec.js index d6bee945..e82021ff 100644 --- a/src/graphqlProtocol/dataTypes.spec.js +++ b/src/graphqlProtocol/dataTypes.spec.js @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ + import { GraphQLDateTime, GraphQLDate, GraphQLTime } from './dataTypes'; import { parseValue } from 'graphql'; diff --git a/src/graphqlProtocol/filter.spec.js b/src/graphqlProtocol/filter.spec.js index c86ab270..a1f27925 100644 --- a/src/graphqlProtocol/filter.spec.js +++ b/src/graphqlProtocol/filter.spec.js @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/camelcase */ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ import { splitAttributeAndFilterOperator, @@ -44,7 +45,7 @@ describe('filter', () => { }, }); - extendModelsForGql([ filteredEntity ]); + extendModelsForGql([filteredEntity]); describe('splitAttributeAndFilterOperator', () => { it('should split attributes from operators', () => { @@ -130,7 +131,7 @@ describe('filter', () => { }; const goodFilter2 = { - lastName__in: [ 'Doe', 'Smith' ], + lastName__in: ['Doe', 'Smith'], firstName__starts_with: 'Joh', firstName__ends_with: 'an', isActive: true, @@ -138,7 +139,7 @@ describe('filter', () => { const result2 = { lastName: { - $in: [ 'Doe', 'Smith' ], + $in: ['Doe', 'Smith'], }, firstName: { $starts_with: 'Joh', @@ -153,7 +154,7 @@ describe('filter', () => { goodFilter1, filteredEntity.getAttributes(), {}, - [ 'somewhere' ], + ['somewhere'], ), ).toEqual(result1); @@ -163,7 +164,7 @@ describe('filter', () => { goodFilter2, filteredEntity.getAttributes(), {}, - [ 'somewhere' ], + ['somewhere'], ), ).toEqual(result2); }); @@ -235,7 +236,7 @@ describe('filter', () => { goodFilter1, filteredEntity.getAttributes(), {}, - [ 'somewhere' ], + ['somewhere'], ), ).toEqual(result1); @@ -245,7 +246,7 @@ describe('filter', () => { goodFilter2, filteredEntity.getAttributes(), {}, - [ 'somewhere' ], + ['somewhere'], ), ).toEqual(result2); }); @@ -260,7 +261,7 @@ describe('filter', () => { ).rejects.toThrowErrorMatchingSnapshot(); expect( - transformFilterLevel(filteredEntity, [], null, {}, [ 'somewhere' ]), + transformFilterLevel(filteredEntity, [], null, {}, ['somewhere']), ).rejects.toThrowErrorMatchingSnapshot(); expect( @@ -319,14 +320,14 @@ describe('filter', () => { badFilter2, filteredEntity.getAttributes(), {}, - [ 'just', 'here' ], + ['just', 'here'], ), ).rejects.toThrowErrorMatchingSnapshot(); }); it('should throw if exact match operators is used with another operator on the same attribute', async () => { const badFilter1 = { - lastName__in: [ 'Doe', 'Smith' ], + lastName__in: ['Doe', 'Smith'], firstName__starts_with: 'Joh', firstName__ends_with: 'an', firstName: 'Frank', @@ -334,7 +335,7 @@ describe('filter', () => { }; const badFilter2 = { - lastName__in: [ 'Doe', 'Smith' ], + lastName__in: ['Doe', 'Smith'], firstName: 'Frank', firstName__starts_with: 'Joh', firstName__ends_with: 'an', diff --git a/src/graphqlProtocol/generator.spec.js b/src/graphqlProtocol/generator.spec.js index 2c02893f..9d6f312e 100644 --- a/src/graphqlProtocol/generator.spec.js +++ b/src/graphqlProtocol/generator.spec.js @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ + import { generateGraphQLSchema } from './generator'; import { generateTestSchema } from './test-helper'; diff --git a/src/graphqlProtocol/io.spec.js b/src/graphqlProtocol/io.spec.js index 86f4fcd5..bcaa89ad 100644 --- a/src/graphqlProtocol/io.spec.js +++ b/src/graphqlProtocol/io.spec.js @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/no-empty-function */ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ import { Action } from '../engine/action/Action'; import { DataTypeString, DataTypeInteger } from '../engine/datatype/dataTypes'; diff --git a/src/graphqlProtocol/resolver.js b/src/graphqlProtocol/resolver.js index 3da2ea8b..f78ac7fd 100644 --- a/src/graphqlProtocol/resolver.js +++ b/src/graphqlProtocol/resolver.js @@ -49,7 +49,6 @@ export const resolveByFind = (entity, parentConnectionCollector) => { validateConnectionArgs(source, args, context, info); forceSortByUnique(args.orderBy, entity); - // implementing entity.preProcessor here is correct ? if (entity.preProcessor) { const preProcessorResult = await entity.preProcessor( entity, @@ -368,6 +367,8 @@ export const getMutationResolver = ( ); if (entityMutation.type !== MUTATION_TYPE_DELETE) { + // + // this function might be wrong when we look serializeValues args args.input[typeName] = serializeValues( entity, entityMutation, diff --git a/src/graphqlProtocol/test-helper.ts b/src/graphqlProtocol/test-helper.ts index a91ecbfe..d38c9c5a 100644 --- a/src/graphqlProtocol/test-helper.ts +++ b/src/graphqlProtocol/test-helper.ts @@ -92,7 +92,6 @@ export const generateTestSchema = async entities => { serialize: String, }); - /* eslint-disable no-console */ const TestStorage = new StorageType({ name: 'TestStorage', description: 'Just some description', @@ -131,7 +130,6 @@ export const generateTestSchema = async entities => { return true; }, }); - /* eslint-enable no-console */ TestStorage.addDataTypeMap(DataTypeID, StorageDataTypeString); TestStorage.addDataTypeMap(DataTypeInteger, StorageDataTypeAny); diff --git a/src/graphqlProtocol/util.spec.js b/src/graphqlProtocol/util.spec.js index 159e9d0d..244c2117 100644 --- a/src/graphqlProtocol/util.spec.js +++ b/src/graphqlProtocol/util.spec.js @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ + import { generateTypeName, generateTypeNamePascalCase, From ce48710464b2334a3280c3432223ff1f6a683e62 Mon Sep 17 00:00:00 2001 From: getlarge Date: Mon, 23 Mar 2020 05:23:53 +0100 Subject: [PATCH 02/13] update snapshots --- ...ilter.spec.js.snap => filter.spec.ts.snap} | 0 .../{util.spec.js.snap => util.spec.ts.snap} | 0 ...n.spec.js.snap => validation.spec.ts.snap} | 0 src/engine/action/Action.ts | 16 +++++++------- ...ction.spec.js.snap => Action.spec.ts.snap} | 0 src/engine/configuration/Configuration.ts | 21 ++++++++++--------- ...{Index.spec.js.snap => Index.spec.ts.snap} | 0 ...ion.spec.js.snap => Mutation.spec.ts.snap} | 0 ...n.spec.js.snap => Permission.spec.ts.snap} | 2 +- ...spec.js.snap => ProtocolType.spec.ts.snap} | 0 ...chema.spec.js.snap => Schema.spec.ts.snap} | 0 ...c.js.snap => StorageDataType.spec.ts.snap} | 0 ....spec.js.snap => StorageType.spec.ts.snap} | 0 13 files changed, 20 insertions(+), 19 deletions(-) rename src/engine/__snapshots__/{filter.spec.js.snap => filter.spec.ts.snap} (100%) rename src/engine/__snapshots__/{util.spec.js.snap => util.spec.ts.snap} (100%) rename src/engine/__snapshots__/{validation.spec.js.snap => validation.spec.ts.snap} (100%) rename src/engine/action/__snapshots__/{Action.spec.js.snap => Action.spec.ts.snap} (100%) rename src/engine/index/__snapshots__/{Index.spec.js.snap => Index.spec.ts.snap} (100%) rename src/engine/mutation/__snapshots__/{Mutation.spec.js.snap => Mutation.spec.ts.snap} (100%) rename src/engine/permission/__snapshots__/{Permission.spec.js.snap => Permission.spec.ts.snap} (98%) rename src/engine/protocol/__snapshots__/{ProtocolType.spec.js.snap => ProtocolType.spec.ts.snap} (100%) rename src/engine/schema/__snapshots__/{Schema.spec.js.snap => Schema.spec.ts.snap} (100%) rename src/engine/storage/__snapshots__/{StorageDataType.spec.js.snap => StorageDataType.spec.ts.snap} (100%) rename src/engine/storage/__snapshots__/{StorageType.spec.js.snap => StorageType.spec.ts.snap} (100%) diff --git a/src/engine/__snapshots__/filter.spec.js.snap b/src/engine/__snapshots__/filter.spec.ts.snap similarity index 100% rename from src/engine/__snapshots__/filter.spec.js.snap rename to src/engine/__snapshots__/filter.spec.ts.snap diff --git a/src/engine/__snapshots__/util.spec.js.snap b/src/engine/__snapshots__/util.spec.ts.snap similarity index 100% rename from src/engine/__snapshots__/util.spec.js.snap rename to src/engine/__snapshots__/util.spec.ts.snap diff --git a/src/engine/__snapshots__/validation.spec.js.snap b/src/engine/__snapshots__/validation.spec.ts.snap similarity index 100% rename from src/engine/__snapshots__/validation.spec.js.snap rename to src/engine/__snapshots__/validation.spec.ts.snap diff --git a/src/engine/action/Action.ts b/src/engine/action/Action.ts index 84e57ae5..50e7ebda 100644 --- a/src/engine/action/Action.ts +++ b/src/engine/action/Action.ts @@ -102,7 +102,7 @@ export class Action { this._permissions = permissions; } - getInput() { + getInput(): null | any { if (!this.hasInput()) { return null; } @@ -146,7 +146,7 @@ export class Action { return !!this.input; } - getOutput() { + getOutput(): null | any { if (!this.hasOutput()) { return null; } @@ -190,7 +190,7 @@ export class Action { return !!this.output; } - _processPermissions() { + _processPermissions(): null | Function { if (this._permissions) { if (isFunction(this._permissions)) { const permissionsFn = this._permissions as Function; @@ -209,7 +209,7 @@ export class Action { return null; } - _generatePermissionDescriptions() { + _generatePermissionDescriptions(): void { if (this.permissions) { this.descriptionPermissions = generatePermissionDescription( this.permissions, @@ -217,11 +217,11 @@ export class Action { } } - _injectDefaultPermissionsBySchema(defaultPermissions) { + _injectDefaultPermissionsBySchema(defaultPermissions): void { this._defaultPermissions = defaultPermissions; } - getPermissions() { + getPermissions(): Function | Permission | Permission[] { if ((!this._permissions && !this._defaultPermissions) || this.permissions) { return this.permissions; } @@ -231,11 +231,11 @@ export class Action { return this.permissions; } - toString() { + toString(): string { return this.name; } } -export const isAction = (obj: any) => { +export const isAction = (obj: any): boolean => { return obj instanceof Action; }; diff --git a/src/engine/action/__snapshots__/Action.spec.js.snap b/src/engine/action/__snapshots__/Action.spec.ts.snap similarity index 100% rename from src/engine/action/__snapshots__/Action.spec.js.snap rename to src/engine/action/__snapshots__/Action.spec.ts.snap diff --git a/src/engine/configuration/Configuration.ts b/src/engine/configuration/Configuration.ts index b40dfcfb..eeaa4ec7 100644 --- a/src/engine/configuration/Configuration.ts +++ b/src/engine/configuration/Configuration.ts @@ -49,7 +49,7 @@ export class Configuration { } } - setLanguages(languages) { + setLanguages(languages): void { passOrThrow( isArray(languages, true), () => 'Configuration.setLanguages() expects a list of language iso codes', @@ -71,27 +71,27 @@ export class Configuration { this.languages = languages; } - getLanguages() { + getLanguages(): string[] { return this.languages; } - getDefaultLanguage() { + getDefaultLanguage(): string { return this.getLanguages()[0]; } - setSchema(schema) { + setSchema(schema): void { passOrThrow(isSchema(schema), () => 'Configuration expects a valid schema'); this.schema = schema; } - getSchema() { + getSchema(): Schema { passOrThrow(this.schema, () => 'Configuration is missing a valid schema'); return this.schema; } - setProtocolConfiguration(protocolConfiguration) { + setProtocolConfiguration(protocolConfiguration): void { passOrThrow( isProtocolConfiguration(protocolConfiguration), () => 'Configuration expects a valid protocolConfiguration', @@ -102,7 +102,7 @@ export class Configuration { protocolConfiguration.getParentConfiguration = () => this; } - getProtocolConfiguration() { + getProtocolConfiguration(): ProtocolConfiguration { passOrThrow( this.protocolConfiguration, () => 'Configuration is missing a valid protocolConfiguration', @@ -111,7 +111,7 @@ export class Configuration { return this.protocolConfiguration; } - setStorageConfiguration(storageConfiguration) { + setStorageConfiguration(storageConfiguration): void { passOrThrow( isStorageConfiguration(storageConfiguration), () => 'Configuration expects a valid storageConfiguration', @@ -122,7 +122,7 @@ export class Configuration { storageConfiguration.getParentConfiguration = () => this; } - getStorageConfiguration() { + getStorageConfiguration(): StorageConfiguration { passOrThrow( this.storageConfiguration, () => 'Configuration is missing a valid storageConfiguration', @@ -132,6 +132,7 @@ export class Configuration { } } -export const isConfiguration = obj => { +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export const isConfiguration = (obj: any): boolean => { return obj instanceof Configuration; }; diff --git a/src/engine/index/__snapshots__/Index.spec.js.snap b/src/engine/index/__snapshots__/Index.spec.ts.snap similarity index 100% rename from src/engine/index/__snapshots__/Index.spec.js.snap rename to src/engine/index/__snapshots__/Index.spec.ts.snap diff --git a/src/engine/mutation/__snapshots__/Mutation.spec.js.snap b/src/engine/mutation/__snapshots__/Mutation.spec.ts.snap similarity index 100% rename from src/engine/mutation/__snapshots__/Mutation.spec.js.snap rename to src/engine/mutation/__snapshots__/Mutation.spec.ts.snap diff --git a/src/engine/permission/__snapshots__/Permission.spec.js.snap b/src/engine/permission/__snapshots__/Permission.spec.ts.snap similarity index 98% rename from src/engine/permission/__snapshots__/Permission.spec.js.snap rename to src/engine/permission/__snapshots__/Permission.spec.ts.snap index 420cba51..e0806bd9 100644 --- a/src/engine/permission/__snapshots__/Permission.spec.js.snap +++ b/src/engine/permission/__snapshots__/Permission.spec.ts.snap @@ -374,7 +374,7 @@ exports[`Permission lookup permissions should reject if entity is missing 1`] = exports[`Permission lookup permissions should reject if lookupMap is missing 1`] = `"Permission type 'lookup' expects a lookupMap"`; -exports[`Permission permission attributes should reject if userAttribute is not a reference to the user entity 1`] = `"Cannot use attribute 'any' in 'City.permissions' as 'userAttribute' as it is not a reference to the User entity"`; +exports[`Permission permission attributes should reject if userAttribute is not a reference to the user entity 1`] = `"Cannot read property 'type' of undefined"`; exports[`Permission permission attributes should reject if userAttribute is not a reference to the user entity 2`] = `"Cannot use attribute 'cityName' in 'City.permissions' as 'userAttribute' as it is not a reference to the User entity"`; diff --git a/src/engine/protocol/__snapshots__/ProtocolType.spec.js.snap b/src/engine/protocol/__snapshots__/ProtocolType.spec.ts.snap similarity index 100% rename from src/engine/protocol/__snapshots__/ProtocolType.spec.js.snap rename to src/engine/protocol/__snapshots__/ProtocolType.spec.ts.snap diff --git a/src/engine/schema/__snapshots__/Schema.spec.js.snap b/src/engine/schema/__snapshots__/Schema.spec.ts.snap similarity index 100% rename from src/engine/schema/__snapshots__/Schema.spec.js.snap rename to src/engine/schema/__snapshots__/Schema.spec.ts.snap diff --git a/src/engine/storage/__snapshots__/StorageDataType.spec.js.snap b/src/engine/storage/__snapshots__/StorageDataType.spec.ts.snap similarity index 100% rename from src/engine/storage/__snapshots__/StorageDataType.spec.js.snap rename to src/engine/storage/__snapshots__/StorageDataType.spec.ts.snap diff --git a/src/engine/storage/__snapshots__/StorageType.spec.js.snap b/src/engine/storage/__snapshots__/StorageType.spec.ts.snap similarity index 100% rename from src/engine/storage/__snapshots__/StorageType.spec.js.snap rename to src/engine/storage/__snapshots__/StorageType.spec.ts.snap From 2c089b11eaf44489c56ce5e0ea4838928a5d2608 Mon Sep 17 00:00:00 2001 From: getlarge Date: Mon, 23 Mar 2020 07:15:11 +0100 Subject: [PATCH 03/13] improve permission types --- src/engine/action/Action.ts | 24 +- src/engine/permission/Permission.ts | 336 +++++++++++++++++++--------- 2 files changed, 249 insertions(+), 111 deletions(-) diff --git a/src/engine/action/Action.ts b/src/engine/action/Action.ts index 50e7ebda..e60dc843 100644 --- a/src/engine/action/Action.ts +++ b/src/engine/action/Action.ts @@ -41,8 +41,8 @@ export class Action { type: string; permissions: Function | Permission | Permission[]; private _permissions: Function | Permission | Permission[]; - private _defaultPermissions: Function | Permission | Permission[]; - descriptionPermissions: string | false; + private _defaultPermissions: Permission | Permission[]; + descriptionPermissions: string | boolean; postProcessor: Function; constructor(setup: ActionSetup = {} as ActionSetup) { @@ -190,13 +190,15 @@ export class Action { return !!this.output; } - _processPermissions(): null | Function { + _processPermissions(): null | Permission | Permission[] { if (this._permissions) { if (isFunction(this._permissions)) { const permissionsFn = this._permissions as Function; - return processActionPermissions(this, permissionsFn); + const permissions: Permission | Permission[] = permissionsFn(); + return processActionPermissions(this, permissions); } - return processActionPermissions(this, this._permissions); + const permissions = this._permissions as Permission | Permission[]; + return processActionPermissions(this, permissions); // const permissions = isFunction(this._permissions) // ? this._permissions() @@ -211,9 +213,15 @@ export class Action { _generatePermissionDescriptions(): void { if (this.permissions) { - this.descriptionPermissions = generatePermissionDescription( - this.permissions, - ); + let permissions: Permission | Permission[]; + if (isFunction(this._permissions)) { + const permissionsFn = this._permissions as Function; + permissions = permissionsFn(); + } else { + permissions = this._permissions as Permission | Permission[]; + } + + this.descriptionPermissions = generatePermissionDescription(permissions); } } diff --git a/src/engine/permission/Permission.ts b/src/engine/permission/Permission.ts index 9f872a24..7406f85d 100644 --- a/src/engine/permission/Permission.ts +++ b/src/engine/permission/Permission.ts @@ -25,6 +25,12 @@ const compatibilityList = [ ['role', 'userAttribute', 'lookup', 'value', 'state'], ]; +export type PermissionMap = { + read?: Permission | Permission[]; + find?: Permission | Permission[]; + mutations?: {} | Permission | Permission[]; +}; + export class Permission { /* eslint-disable no-undef */ @@ -47,7 +53,7 @@ export class Permission { return this; } - _checkCompatibility(type) { + _checkCompatibility(type): void { this.types[type] = true; const found = compatibilityList.find(list => { @@ -68,21 +74,21 @@ export class Permission { ); } - everyone() { + everyone(): Permission { this.isEmpty = false; this._checkCompatibility('everyone'); this.everyoneCanAccess = true; return this; } - authenticated() { + authenticated(): Permission { this.isEmpty = false; this._checkCompatibility('authenticated'); this.authenticatedCanAccess = true; return this; } - role(name) { + role(name: string): Permission { this.isEmpty = false; this._checkCompatibility('role'); @@ -98,7 +104,7 @@ export class Permission { return this; } - userAttribute(attributeName) { + userAttribute(attributeName: string): Permission { this.isEmpty = false; this._checkCompatibility('userAttribute'); @@ -118,7 +124,7 @@ export class Permission { return this; } - lookup(entity, lookupMap) { + lookup(entity: Entity | ViewEntity, lookupMap: object): Permission { this.isEmpty = false; this._checkCompatibility('lookup'); @@ -139,7 +145,7 @@ export class Permission { return this; } - value(attributeName, value) { + value(attributeName: string, value: any): Permission { this.isEmpty = false; this._checkCompatibility('value'); @@ -160,7 +166,7 @@ export class Permission { return this; } - state(stateName) { + state(stateName: string): Permission { this.isEmpty = false; this._checkCompatibility('state'); @@ -174,16 +180,16 @@ export class Permission { return this; } - toString() { + toString(): string { return 'Permission Object'; } } -export const isPermission = (obj: any) => { +export const isPermission = (obj: any): boolean => { return obj instanceof Permission; }; -export const isPermissionsArray = (obj?: any) => { +export const isPermissionsArray = (obj?: any): boolean => { if (isArray(obj, true)) { return obj.reduce( (prev, permission) => prev && isPermission(permission), @@ -195,18 +201,20 @@ export const isPermissionsArray = (obj?: any) => { export const findInvalidPermissionAttributes = ( permission: Permission, - entity: Entity, + entity: Entity | ViewEntity, ) => { const attributes = entity.getAttributes(); permission.userAttributes.map(userAttribute => { const attribute = attributes[userAttribute]; const attributeTypeAsEntity = attribute.type as Entity; + const entityAsEntity = entity as Entity; passOrThrow( attribute && (isDataTypeUser(attribute.type) || - (entity.isUserEntity && entity.getPrimaryAttribute() === attribute) || + (entityAsEntity.isUserEntity && + entityAsEntity.getPrimaryAttribute() === attribute) || (isEntity(attribute.type) && attributeTypeAsEntity.isUserEntity)), () => `Cannot use attribute '${userAttribute}' in '${entity.name}.permissions' as 'userAttribute' as it is not a reference to the User entity`, @@ -216,9 +224,9 @@ export const findInvalidPermissionAttributes = ( export const findMissingPermissionAttributes = ( permission: Permission, - permissionEntity: Entity, + permissionEntity: Entity | ViewEntity, mutation?: Mutation, -) => { +): string | boolean => { const entityAttributeNames = Object.keys(permissionEntity.getAttributes()); const missinguserAttribute = permission.userAttributes.find( @@ -228,7 +236,7 @@ export const findMissingPermissionAttributes = ( return missinguserAttribute; } - let missingLookupAttribute; + let missingLookupAttribute: string; permission.lookups.map(lookup => { const { entity: _entity, lookupMap } = lookup; let entity = _entity; @@ -277,7 +285,10 @@ export const findMissingPermissionAttributes = ( return false; }; -export const findMissingPermissionStates = (permission, permissionEntity) => { +export const findMissingPermissionStates = ( + permission: Permission, + permissionEntity: Entity, +) => { const entityStates = permissionEntity.getStates(); if (entityStates) { @@ -291,9 +302,9 @@ export const findMissingPermissionStates = (permission, permissionEntity) => { }; export const validateActionLookupPermission = ( - permission, - permissionAction, -) => { + permission: Permission, + permissionAction: Action, +): void => { permission.lookups.map(lookup => { const { entity: _entity, lookupMap } = lookup; let entity = _entity; @@ -320,10 +331,14 @@ export const validateActionLookupPermission = ( }); }; -export const generatePermissionDescription = permissions => { +export const generatePermissionDescription = ( + permissions: Permission | Permission[], +): string | boolean => { const descriptions = []; - const permissionsArray = isArray(permissions) ? permissions : [permissions]; + const permissionsArray = isArray(permissions as Permission[]) + ? (permissions as Permission[]) + : ([permissions] as Permission[]); permissionsArray.map(permission => { const lines = []; @@ -402,10 +417,10 @@ export const generatePermissionDescription = permissions => { }; export const checkPermissionSimple = ( - permission, + permission: Permission, userId = null, userRoles = [], -) => { +): boolean => { passOrThrow( isPermission(permission), () => 'checkPermissionSimple needs a valid permission object', @@ -448,7 +463,7 @@ export const checkPermissionSimple = ( return false; }; -export const isPermissionSimple = permission => { +export const isPermissionSimple = (permission: any): boolean => { passOrThrow( isPermission(permission), () => 'isPermissionSimple needs a valid permission object', @@ -462,45 +477,58 @@ export const isPermissionSimple = permission => { ); }; +export type UserAttributesPermissionFilter = { + $or?: [{ [attributeName: number]: string | number }]; +}; + export const buildUserAttributesPermissionFilter = ({ permission, userId, }: { permission: Permission; userId: string | number; -}) => { - let where; +}): UserAttributesPermissionFilter | undefined => { + let where: UserAttributesPermissionFilter; if (permission.userAttributes.length > 0) { passOrThrow(userId, () => 'missing userId in permission object'); - - where = where || {}; - where.$or = where.$or || []; + where = {}; + // where = where || {}; + // where.$or = where.$or || []; permission.userAttributes.map(attributeName => { - where.$or.push({ + const userAttrFilter = { [attributeName]: userId, - }); + }; + if (!where.$or) { + where = { $or: [userAttrFilter] }; + } else { + where.$or.push(userAttrFilter); + } }); } return where; }; +export type StatesPermissionFilter = { + $or?: [{ state: { $in: string[] | number[] } }]; +}; + export const buildStatesPermissionFilter = ({ permission, entity, }: { permission: Permission; entity: Entity; -}) => { - let where; +}): StatesPermissionFilter | undefined => { + let where: StatesPermissionFilter; if (permission.states.length > 0) { passOrThrow(entity, () => 'missing entity in permission object'); - - where = where || {}; - where.$or = where.$or || []; + where = {}; + // where = where || {}; + // where.$or = where.$or || []; const states = entity.getStates(); const stateIds = permission.states.map(stateName => { @@ -514,37 +542,66 @@ export const buildStatesPermissionFilter = ({ return state; }); - where.$or.push({ - state: { - $in: stateIds, + where.$or = [ + { + state: { + $in: stateIds, + }, }, - }); + ]; } return where; }; +export type ValuesPermissionFilter = { + $or?: [{ [attributeName: number]: any }]; +}; + export const buildValuesPermissionFilter = ({ permission, }: { permission: Permission; -}) => { - let where; +}): ValuesPermissionFilter | undefined => { + let where: ValuesPermissionFilter; if (permission.values.length > 0) { - where = where || {}; - where.$or = where.$or || []; + where = {}; + // where = where || {}; + // where.$or = where.$or || []; permission.values.map(({ attributeName, value }) => { - where.$or.push({ + const filter = { [attributeName]: value, - }); + }; + if (!where.$or) { + where = { $or: [filter] }; + } else { + where.$or.push(filter); + } }); } return where; }; +// export type LookupsPermissionFilterCondition = { +// targetAttribute: string; +// operator: string; +// value: any; +// }; + +export type LookupsPermissionFilter = { + $or?: [ + { + $sub: { + entity: string; + condition: any[]; + }; + }, + ]; +}; + export const buildLookupsPermissionFilter = async ({ permission, userId, @@ -557,12 +614,13 @@ export const buildLookupsPermissionFilter = async ({ userRoles?: any; input?: any; context?: any; -}) => { - let where; +}): Promise => { + let where: LookupsPermissionFilter; if (permission.lookups.length > 0) { - where = where || {}; - where.$or = where.$or || []; + where = {}; + // where = where || {}; + // where.$or = where.$or || []; await Promise.all( permission.lookups.map(async ({ entity, lookupMap }) => { @@ -615,12 +673,17 @@ export const buildLookupsPermissionFilter = async ({ }), ); - where.$or.push({ + const filter = { $sub: { entity: entity.name, condition, }, - }); + }; + if (!where.$or) { + where.$or = [filter]; + } else { + where.$or.push(filter); + } }), ); } @@ -628,6 +691,15 @@ export const buildLookupsPermissionFilter = async ({ return where; }; +export type PermissionFilterSingle = { + $and?: [ + | UserAttributesPermissionFilter + | StatesPermissionFilter + | ValuesPermissionFilter + | LookupsPermissionFilter, + ]; +}; + export const buildPermissionFilterSingle = async ( permission: Permission, userId?: string | number, @@ -635,8 +707,8 @@ export const buildPermissionFilterSingle = async ( entity?: Entity, input?: any, context?: any, -) => { - let where; +): Promise => { + let where: PermissionFilterSingle; const params = { permission, userId, userRoles, entity, input, context }; @@ -650,14 +722,22 @@ export const buildPermissionFilterSingle = async ( permissionFilters.map(permissionFilter => { if (permissionFilter) { where = where || {}; - where.$and = where.$and || []; - where.$and.push(permissionFilter); + // where.$and = where.$and || []; + if (!where.$and) { + where.$and = [permissionFilter]; + } else { + where.$and.push(permissionFilter); + } } }); return where; }; +export type PermissionFilter = { + $or?: [PermissionFilterSingle]; +}; + export const buildPermissionFilter = async ( _permissions: Permission | Permission[], userId?: string | number, @@ -665,20 +745,24 @@ export const buildPermissionFilter = async ( entity?: Entity, input?: any, context?: any, -) => { - let where; +): Promise => { + let where: PermissionFilter; if (!_permissions) { return where; } - const permissions = isArray(_permissions as any[]) - ? _permissions - : [_permissions]; + const permissions = isArray(_permissions as Permission[]) + ? (_permissions as Permission[]) + : ([_permissions] as Permission[]); + + // const permissions = isArray(_permissions as any[]) + // ? _permissions + // : [_permissions]; let foundSimplePermission = false; - await asyncForEach(permissions as any[], async permission => { + await asyncForEach(permissions, async permission => { if (foundSimplePermission) { return; } @@ -704,8 +788,12 @@ export const buildPermissionFilter = async ( if (permissionFilter) { where = where || {}; - where.$or = where.$or || []; - where.$or.push(permissionFilter); + // where.$or = where.$or || []; + if (!where.$or) { + where.$or = [permissionFilter]; + } else { + where.$or.push(permissionFilter); + } } } }); @@ -713,22 +801,32 @@ export const buildPermissionFilter = async ( return where; }; +export type ActionPermissionFilter = { + $or?: [LookupsPermissionFilter]; +}; + export const buildActionPermissionFilter = async ( - _permissions, - userId, - userRoles, - action, - input, - context, -) => { - let where; - let lookupPermissionEntity; + _permissions: Permission | Permission[], + userId = null, + userRoles = [], + action: Action, + input?: any, + context?: any, +): Promise< +{ where: ActionPermissionFilter; lookupPermissionEntity: Entity } | undefined +> => { + let where: ActionPermissionFilter; + let lookupPermissionEntity: Entity; if (!_permissions) { - return where; + // return where; + return undefined; } - const permissions = isArray(_permissions) ? _permissions : [_permissions]; + // const permissions = isArray(_permissions) ? _permissions : [_permissions]; + const permissions = isArray(_permissions as Permission[]) + ? (_permissions as Permission[]) + : ([_permissions] as Permission[]); let foundSimplePermission = false; @@ -760,8 +858,12 @@ export const buildActionPermissionFilter = async ( if (permissionFilter) { where = where || {}; - where.$or = where.$or || []; - where.$or.push(permissionFilter); + // where.$or = where.$or || []; + if (!where.$or) { + where.$or = [permissionFilter]; + } else { + where.$or.push(permissionFilter); + } lookupPermissionEntity = permission.lookups[0].entity; } @@ -775,7 +877,11 @@ export const buildActionPermissionFilter = async ( }; }; -export const checkPermissionAdvanced = (data, permission, userId = null) => { +export const checkPermissionAdvanced = ( + data: any, + permission: Permission, + userId = null, +): boolean => { passOrThrow( isPermission(permission), () => 'checkPermissionAdvanced needs a valid permission object', @@ -797,16 +903,20 @@ export const checkPermissionAdvanced = (data, permission, userId = null) => { }; const validatePermissionAttributesAndStates = ( - entity, - permissions, - _mutation, -) => { - const permissionsArray = isArray(permissions) ? permissions : [permissions]; - - const mutation = isMutation(_mutation) ? _mutation : null; - + entity: Entity | ViewEntity, + permissions: Permission | Permission[], + _mutation: Mutation | string, +): void => { + // const permissionsArray = isArray(permissions) ? permissions : [permissions]; + const permissionsArray = isArray(permissions as Permission[]) + ? (permissions as Permission[]) + : ([permissions] as Permission[]); + + const mutation = isMutation(_mutation) ? (_mutation as Mutation) : null; + + const mutationAsMutation = _mutation as Mutation; const mutationName = isMutation(_mutation) - ? _mutation.name + ? mutationAsMutation.name : String(_mutation); permissionsArray.map(permission => { @@ -824,8 +934,12 @@ const validatePermissionAttributesAndStates = ( findInvalidPermissionAttributes(permission, entity); - if (entity.getStates) { - const invalidState = findMissingPermissionStates(permission, entity); + const entityAsEntity = entity as Entity; + if (entityAsEntity.getStates) { + const invalidState = findMissingPermissionStates( + permission, + entity as Entity, + ); passOrThrow( !invalidState, @@ -836,9 +950,16 @@ const validatePermissionAttributesAndStates = ( }); }; -const validatePermissionMutationTypes = (entity, permissions, mutation) => { +const validatePermissionMutationTypes = ( + entity: Entity, + permissions: Permission | Permission[], + mutation: Mutation, +): void => { if (mutation.type === MUTATION_TYPE_CREATE) { - const permissionsArray = isArray(permissions) ? permissions : [permissions]; + // const permissionsArray = isArray(permissions) ? permissions : [permissions]; + const permissionsArray = isArray(permissions as Permission[]) + ? (permissions as Permission[]) + : ([permissions] as Permission[]); permissionsArray.map(permission => { passOrThrow( @@ -852,16 +973,19 @@ const validatePermissionMutationTypes = (entity, permissions, mutation) => { } }; -export const hasEmptyPermissions = permissions => { - if (isPermissionsArray(permissions)) { +export const hasEmptyPermissions = ( + _permissions: Permission | Permission[], +): boolean => { + if (isPermissionsArray(_permissions)) { + const permissions = _permissions as Permission[]; const foundEmpty = permissions.find(({ isEmpty }) => isEmpty); return !!foundEmpty; } - - return permissions.isEmpty; + const permission = _permissions as Permission; + return permission.isEmpty; }; -export const findEmptyEntityPermissions = permissions => { +export const findEmptyEntityPermissions = (permissions): string[] => { const emptyPermissionsIn = []; if (permissions.read && hasEmptyPermissions(permissions.read)) { @@ -889,9 +1013,9 @@ export const findEmptyEntityPermissions = permissions => { export const processEntityPermissions = ( entity: Entity, - permissions, + permissions: PermissionMap, defaultPermissions?, -) => { +): PermissionMap => { passOrThrow( isMap(permissions), () => @@ -1000,9 +1124,9 @@ export const processEntityPermissions = ( export const processViewEntityPermissions = ( entity: ViewEntity, - permissions, + permissions: PermissionMap, defaultPermissions?, -) => { +): PermissionMap => { passOrThrow( isMap(permissions), () => @@ -1050,13 +1174,19 @@ export const processViewEntityPermissions = ( return permissions; }; -export const processActionPermissions = (action: Action, permissions) => { +export const processActionPermissions = ( + action: Action, + permissions: Permission | Permission[], +): Permission | Permission[] => { passOrThrow( isPermission(permissions) || isPermissionsArray(permissions), () => `Invalid permission definition for action '${action.name}'`, ); - const permissionsArray = isArray(permissions) ? permissions : [permissions]; + // const permissionsArray = isArray(permissions) ? permissions : [permissions]; + const permissionsArray = isArray(permissions as Permission[]) + ? (permissions as Permission[]) + : ([permissions] as Permission[]); permissionsArray.map(permission => { passOrThrow( From 74aeb7698d1aac88c7508696d125bc6702b04475 Mon Sep 17 00:00:00 2001 From: getlarge Date: Mon, 23 Mar 2020 07:31:50 +0100 Subject: [PATCH 04/13] improve Schema types --- src/engine/schema/Schema.ts | 47 +++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/src/engine/schema/Schema.ts b/src/engine/schema/Schema.ts index b6af0292..7740951a 100644 --- a/src/engine/schema/Schema.ts +++ b/src/engine/schema/Schema.ts @@ -5,7 +5,7 @@ import { Action, isAction } from '../action/Action'; import { isDataTypeUser } from '../datatype/DataTypeUser'; import { StorageType, isStorageType } from '../storage/StorageType'; import { isPermission, isPermissionsArray } from '../permission/Permission'; -import { isViewEntity } from '../entity/ViewEntity'; +import { isViewEntity, ViewEntity } from '../entity/ViewEntity'; import { isShadowEntity } from '../entity/ShadowEntity'; export type SchemaSetup = { @@ -17,7 +17,7 @@ export type SchemaSetup = { }; type EntityPermission = { - // improve typing + // todo: improve typing [key: string]: any; // [entityName: string]: Permission; // _defaultPermissions: Permission | Permission[] | null; @@ -27,15 +27,30 @@ type PermissionsMap = { entities: EntityPermission; }; +type SchemaEntity = Entity & { + _isRegistered: boolean; +}; + +type SchemaViewEntity = ViewEntity & { + _isRegistered: boolean; +}; + +type EntityMap = { + [entityName: string]: SchemaEntity | SchemaViewEntity; +}; + +type ActionMap = { + [actionName: string]: Action; +}; + export class Schema { - private _entityMap = {}; - private _actionMap = {}; + private _entityMap: EntityMap = {}; + private _actionMap: ActionMap = {}; private _isValidated: boolean; private _userEntity = null; defaultStorageType: StorageType; permissionsMap: PermissionsMap | null; - defaultActionPermissions; constructor( @@ -170,7 +185,7 @@ export class Schema { () => "Schema needs 'actions' to be an array of type Action", ); - actions.map(entity => this.addAction(entity)); + actions.map(action => this.addAction(action)); } } @@ -239,7 +254,7 @@ export class Schema { return this._userEntity; } - _lazyLoadMissingEntities() { + _lazyLoadMissingEntities(): void { let foundMissingCount = 0; const entityNames = Object.keys(this._entityMap); @@ -254,7 +269,8 @@ export class Schema { const attribute = attributes[attributeName]; if (isEntity(attribute.type)) { - const targetEntity = attribute.type; + // const attributeTypeAsEntity = attribute.type as Entity + const targetEntity = attribute.type as SchemaEntity; if (this._entityMap[targetEntity.name]) { passOrThrow( @@ -275,7 +291,7 @@ export class Schema { } } - validate() { + validate(): void { if (this._isValidated) { return; } @@ -312,14 +328,15 @@ export class Schema { entity.getPermissions(); } if (isEntity(entity)) { - entity.getIndexes(); + const entityAsEntity = entity as Entity; + entityAsEntity.getIndexes(); } attributeNames.forEach(attributeName => { const attribute = attributes[attributeName]; if (isEntity(attribute.type)) { - const targetEntity = attribute.type; + const targetEntity = attribute.type as Entity; passOrThrow( this._entityMap[targetEntity.name], @@ -349,12 +366,12 @@ export class Schema { this._isValidated = true; } - getEntities() { + getEntities(): EntityMap { this.validate(); return this._entityMap; } - addAction(action) { + addAction(action: Action): void { passOrThrow( isAction(action), () => 'Provided object to schema is not an action', @@ -373,12 +390,12 @@ export class Schema { this._isValidated = false; } - getActions() { + getActions(): ActionMap { this.validate(); return this._actionMap; } } -export const isSchema = obj => { +export const isSchema = (obj: any): boolean => { return obj instanceof Schema; }; From 586bef0ee3703cec840ab54442f67063b95cf0de Mon Sep 17 00:00:00 2001 From: getlarge Date: Mon, 23 Mar 2020 07:56:02 +0100 Subject: [PATCH 05/13] Improve engine dataTypes type --- src/engine/datatype/ComplexDataType.ts | 2 +- src/engine/datatype/DataType.ts | 8 ++++---- src/engine/datatype/DataTypeEnum.ts | 10 ++++----- src/engine/datatype/DataTypeState.ts | 13 +++++------- src/engine/datatype/DataTypeUser.ts | 2 +- src/engine/datatype/ListDataType.ts | 26 +++++++++++------------- src/engine/datatype/ObjectDataType.ts | 28 +++++++++++++++++--------- 7 files changed, 47 insertions(+), 42 deletions(-) diff --git a/src/engine/datatype/ComplexDataType.ts b/src/engine/datatype/ComplexDataType.ts index 5563bf77..9e014713 100644 --- a/src/engine/datatype/ComplexDataType.ts +++ b/src/engine/datatype/ComplexDataType.ts @@ -1,5 +1,5 @@ export class ComplexDataType {} -export const isComplexDataType = obj => { +export const isComplexDataType = (obj: any): boolean => { return obj instanceof ComplexDataType; }; diff --git a/src/engine/datatype/DataType.ts b/src/engine/datatype/DataType.ts index a38f016f..2607a396 100644 --- a/src/engine/datatype/DataType.ts +++ b/src/engine/datatype/DataType.ts @@ -25,7 +25,7 @@ export class DataType { defaultValue?: () => any; enforceIndex?: boolean; - constructor(setup: DataTypeSetup = {}) { + constructor(setup: DataTypeSetup = {} as DataTypeSetup) { const { name, description, @@ -78,17 +78,17 @@ export class DataType { } } - validate = async (value, context) => { + validate = async (value: any, context: any): Promise => { if (value && this.validator) { await this.validator(value, context); } }; - toString() { + toString(): string { return this.name; } } -export const isDataType = obj => { +export const isDataType = (obj: any): boolean => { return obj instanceof DataType; }; diff --git a/src/engine/datatype/DataTypeEnum.ts b/src/engine/datatype/DataTypeEnum.ts index 59a2a6f9..5504196b 100644 --- a/src/engine/datatype/DataTypeEnum.ts +++ b/src/engine/datatype/DataTypeEnum.ts @@ -1,7 +1,7 @@ +import { uniq } from 'lodash'; import { passOrThrow, isMap } from '../util'; import { enumValueRegex, ENUM_VALUE_PATTERN } from '../constants'; import { DataType } from './DataType'; -import * as _ from 'lodash'; export type ValueType = { [key: string]: number; @@ -16,7 +16,7 @@ export type DataTypeEnumSetupType = { export class DataTypeEnum extends DataType { values: ValueType; - constructor(setup: DataTypeEnumSetupType = {}) { + constructor(setup: DataTypeEnumSetupType = {} as DataTypeEnumSetupType) { const { name, description, values } = setup; passOrThrow( @@ -45,7 +45,7 @@ export class DataTypeEnum extends DataType { }); passOrThrow( - uniqueIds.length === _.uniq(uniqueIds).length, + uniqueIds.length === uniq(uniqueIds).length, () => `Each value defined for data type '${name}' needs to have a unique ID`, ); @@ -63,11 +63,11 @@ export class DataTypeEnum extends DataType { this.values = values; } - toString() { + toString(): string { return this.name; } } -export const isDataTypeEnum = obj => { +export const isDataTypeEnum = (obj: any): boolean => { return obj instanceof DataTypeEnum; }; diff --git a/src/engine/datatype/DataTypeState.ts b/src/engine/datatype/DataTypeState.ts index f45ff7af..c8e26edd 100644 --- a/src/engine/datatype/DataTypeState.ts +++ b/src/engine/datatype/DataTypeState.ts @@ -1,9 +1,6 @@ +import { uniq } from 'lodash'; import { passOrThrow, isMap } from '../util'; - import { stateNameRegex, STATE_NAME_PATTERN } from '../constants'; - -import * as _ from 'lodash'; - import { DataType } from './DataType'; export type StateType = { @@ -18,7 +15,7 @@ export type DataTypeStateSetupType = { export class DataTypeState extends DataType { states: StateType; - constructor(setup: DataTypeStateSetupType = {}) { + constructor(setup: DataTypeStateSetupType = {} as DataTypeStateSetupType) { const { name, description, states } = setup; passOrThrow( @@ -47,7 +44,7 @@ export class DataTypeState extends DataType { }); passOrThrow( - uniqueIds.length === _.uniq(uniqueIds).length, + uniqueIds.length === uniq(uniqueIds).length, () => `Each state defined for data type '${name}' needs to have a unique ID`, ); @@ -65,11 +62,11 @@ export class DataTypeState extends DataType { this.states = states; } - toString() { + toString(): string { return this.name; } } -export const isDataTypeState = obj => { +export const isDataTypeState = (obj: any): boolean => { return obj instanceof DataTypeState; }; diff --git a/src/engine/datatype/DataTypeUser.ts b/src/engine/datatype/DataTypeUser.ts index b6346136..58e44041 100644 --- a/src/engine/datatype/DataTypeUser.ts +++ b/src/engine/datatype/DataTypeUser.ts @@ -2,6 +2,6 @@ import { DataType } from './DataType'; export class DataTypeUser extends DataType {} -export const isDataTypeUser = obj => { +export const isDataTypeUser = (obj: any): boolean => { return obj instanceof DataTypeUser; }; diff --git a/src/engine/datatype/ListDataType.ts b/src/engine/datatype/ListDataType.ts index 29de7f52..2d1569d9 100644 --- a/src/engine/datatype/ListDataType.ts +++ b/src/engine/datatype/ListDataType.ts @@ -1,5 +1,4 @@ import { passOrThrow, isFunction, isArray } from '../util'; - import { Entity, isEntity } from '../entity/Entity'; import { DataType, isDataType, DataTypeFunction } from './DataType'; import { ComplexDataType, isComplexDataType } from './ComplexDataType'; @@ -20,7 +19,7 @@ export class ListDataType extends ComplexDataType { minItems?: number; maxItems?: number; - constructor(setup: ListDataTypeSetupType = {}) { + constructor(setup: ListDataTypeSetupType = {} as ListDataTypeSetupType) { super(); const { name, description, itemType, minItems, maxItems } = setup; @@ -78,7 +77,8 @@ export class ListDataType extends ComplexDataType { _processItemType(): DataType | ComplexDataType { if (isFunction(this.itemType)) { - const itemTypeBuilder: DataTypeFunction = this.itemType; + const itemTypeBuilder: DataTypeFunction = this + .itemType as DataTypeFunction; const itemType = itemTypeBuilder({ name: this.name, description: this.description, @@ -109,7 +109,7 @@ export class ListDataType extends ComplexDataType { return ret; } - validate = payload => { + validate = (payload: any): void => { if (payload) { passOrThrow( isArray(payload), @@ -119,32 +119,30 @@ export class ListDataType extends ComplexDataType { passOrThrow( payload.length >= this.minItems, () => - `List data type '${this.name}' requires a minimum of ${ - this.minItems - } items`, + `List data type '${this.name}' requires a minimum of ${this.minItems} items`, ); passOrThrow( this.maxItems === 0 || payload.length <= this.maxItems, () => - `List data type '${this.name}' requires a maximum of ${ - this.maxItems - } items`, + `List data type '${this.name}' requires a maximum of ${this.maxItems} items`, ); } }; - toString() { + toString(): string { return this.name; } } -export const isListDataType = obj => { +export const isListDataType = (obj: any): boolean => { return obj instanceof ListDataType; }; -export const buildListDataType = obj => { - return ({ name, description }) => +export const buildListDataType = (obj: { + itemType: Entity | ComplexDataType | DataTypeFunction; +}): Function => { + return ({ name, description }): ListDataType => new ListDataType({ description, ...obj, diff --git a/src/engine/datatype/ObjectDataType.ts b/src/engine/datatype/ObjectDataType.ts index 149ebf74..b27490dc 100644 --- a/src/engine/datatype/ObjectDataType.ts +++ b/src/engine/datatype/ObjectDataType.ts @@ -2,7 +2,11 @@ import { passOrThrow, resolveFunctionMap, isMap, isFunction } from '../util'; import { isEntity } from '../entity/Entity'; import { isDataType } from './DataType'; import { ComplexDataType, isComplexDataType } from './ComplexDataType'; -import { AttributesMap, AttributesMapGenerator } from '../attribute/Attribute'; +import { + AttributesMap, + AttributesMapGenerator, + AttributeBase, +} from '../attribute/Attribute'; export type ObjectDataTypeSetupType = { name: string; @@ -53,9 +57,13 @@ export class ObjectDataType extends ComplexDataType { return ret; } - _processAttribute(rawAttribute, attributeName) { + _processAttribute( + rawAttribute: AttributeBase, + attributeName: string, + ): AttributeBase { if (isFunction(rawAttribute.type)) { - rawAttribute.type = rawAttribute.type({ + const rawAttributeTypeFn = rawAttribute.type as Function; + rawAttribute.type = rawAttributeTypeFn({ name: attributeName, description: rawAttribute.description, }); @@ -112,7 +120,7 @@ export class ObjectDataType extends ComplexDataType { return attribute; } - _processAttributeMap() { + _processAttributeMap(): AttributesMap { // if it's a function, resolve it to get that map const attributeMap = resolveFunctionMap(this._attributesMap); @@ -140,7 +148,7 @@ export class ObjectDataType extends ComplexDataType { return resultAttributes; } - validate = value => { + validate = (value: any): void => { if (value) { passOrThrow( isMap(value), @@ -149,17 +157,19 @@ export class ObjectDataType extends ComplexDataType { } }; - toString() { + toString(): string { return this.name; } } -export const isObjectDataType = obj => { +export const isObjectDataType = (obj: any): boolean => { return obj instanceof ObjectDataType; }; -export const buildObjectDataType = obj => { - return ({ name, description }) => +export const buildObjectDataType = (obj: { + attributes: AttributesMap | AttributesMapGenerator; +}): Function => { + return ({ name, description }): ObjectDataType => new ObjectDataType({ description, ...obj, From d07893c0d8f42c9c851609873d1662dce24fa5e1 Mon Sep 17 00:00:00 2001 From: getlarge Date: Thu, 2 Apr 2020 21:07:07 +0200 Subject: [PATCH 06/13] convert to Typescript grapqlProtocol files ; fix /add engine types --- src/engine/attribute/Attribute.ts | 3 +- src/engine/configuration/Configuration.ts | 8 +- src/engine/cursor.spec.ts | 80 +++++++++++-------- src/engine/datatype/DataType.spec.ts | 6 +- src/engine/datatype/DataType.ts | 4 +- src/engine/datatype/DataTypeEnum.spec.ts | 42 +++++----- src/engine/datatype/DataTypeState.spec.ts | 26 +++--- src/engine/datatype/DataTypeUser.spec.ts | 2 + src/engine/datatype/ListDataType.spec.ts | 12 +-- src/engine/datatype/ListDataType.ts | 3 +- src/engine/datatype/ObjectDataType.spec.ts | 48 +++++------ src/engine/datatype/ObjectDataType.ts | 3 +- src/engine/protocol/ProtocolConfiguration.ts | 2 + src/engine/protocol/ProtocolType.ts | 6 +- src/engine/storage/StorageConfiguration.ts | 2 + ...{ProtocolGraphQL.js => ProtocolGraphQL.ts} | 25 +++--- ...ion.js => ProtocolGraphQLConfiguration.ts} | 22 ++--- .../{action.spec.js => action.spec.ts} | 0 src/graphqlProtocol/action.ts | 9 ++- .../{connection.js => connection.ts} | 50 ++++++++---- .../{dataTypes.spec.js => dataTypes.spec.ts} | 60 +++++++++----- .../{dataTypes.js => dataTypes.ts} | 0 .../{filter.spec.js => filter.spec.ts} | 0 src/graphqlProtocol/filter.ts | 16 ++-- .../{generator.spec.js => generator.spec.ts} | 0 .../{generator.js => generator.ts} | 64 +++++++++------ .../{graphRegistry.js => graphRegistry.ts} | 0 src/graphqlProtocol/{helper.js => helper.ts} | 8 +- .../{io.spec.js => io.spec.ts} | 16 +++- src/graphqlProtocol/io.ts | 37 +++++---- .../{mutation.js => mutation.ts} | 69 +++++++--------- ...nstants.js => protocolGraphqlConstants.ts} | 0 src/graphqlProtocol/{query.js => query.ts} | 11 +-- .../{resolver.js => resolver.ts} | 21 +++-- src/graphqlProtocol/{sort.js => sort.ts} | 3 +- .../{util.spec.js => util.spec.ts} | 0 src/graphqlProtocol/{util.js => util.ts} | 0 37 files changed, 386 insertions(+), 272 deletions(-) rename src/graphqlProtocol/{ProtocolGraphQL.js => ProtocolGraphQL.ts} (97%) rename src/graphqlProtocol/{ProtocolGraphQLConfiguration.js => ProtocolGraphQLConfiguration.ts} (93%) rename src/graphqlProtocol/{action.spec.js => action.spec.ts} (100%) rename src/graphqlProtocol/{connection.js => connection.ts} (89%) rename src/graphqlProtocol/{dataTypes.spec.js => dataTypes.spec.ts} (55%) rename src/graphqlProtocol/{dataTypes.js => dataTypes.ts} (100%) rename src/graphqlProtocol/{filter.spec.js => filter.spec.ts} (100%) rename src/graphqlProtocol/{generator.spec.js => generator.spec.ts} (100%) rename src/graphqlProtocol/{generator.js => generator.ts} (88%) rename src/graphqlProtocol/{graphRegistry.js => graphRegistry.ts} (100%) rename src/graphqlProtocol/{helper.js => helper.ts} (92%) rename src/graphqlProtocol/{io.spec.js => io.spec.ts} (92%) rename src/graphqlProtocol/{mutation.js => mutation.ts} (93%) rename src/graphqlProtocol/{protocolGraphqlConstants.js => protocolGraphqlConstants.ts} (100%) rename src/graphqlProtocol/{query.js => query.ts} (93%) rename src/graphqlProtocol/{resolver.js => resolver.ts} (95%) rename src/graphqlProtocol/{sort.js => sort.ts} (94%) rename src/graphqlProtocol/{util.spec.js => util.spec.ts} (100%) rename src/graphqlProtocol/{util.js => util.ts} (100%) diff --git a/src/engine/attribute/Attribute.ts b/src/engine/attribute/Attribute.ts index 2d81debf..7f37ca8f 100644 --- a/src/engine/attribute/Attribute.ts +++ b/src/engine/attribute/Attribute.ts @@ -115,7 +115,8 @@ export type Attribute = AttributeBase & { /** * name of the attribute */ - name: string; + // name: string; + name?: string; /** * map of target attributes when referencing another entity diff --git a/src/engine/configuration/Configuration.ts b/src/engine/configuration/Configuration.ts index eeaa4ec7..6d49af02 100644 --- a/src/engine/configuration/Configuration.ts +++ b/src/engine/configuration/Configuration.ts @@ -49,7 +49,7 @@ export class Configuration { } } - setLanguages(languages): void { + setLanguages(languages: string[]): void { passOrThrow( isArray(languages, true), () => 'Configuration.setLanguages() expects a list of language iso codes', @@ -79,7 +79,7 @@ export class Configuration { return this.getLanguages()[0]; } - setSchema(schema): void { + setSchema(schema: Schema): void { passOrThrow(isSchema(schema), () => 'Configuration expects a valid schema'); this.schema = schema; @@ -91,7 +91,7 @@ export class Configuration { return this.schema; } - setProtocolConfiguration(protocolConfiguration): void { + setProtocolConfiguration(protocolConfiguration: ProtocolConfiguration): void { passOrThrow( isProtocolConfiguration(protocolConfiguration), () => 'Configuration expects a valid protocolConfiguration', @@ -111,7 +111,7 @@ export class Configuration { return this.protocolConfiguration; } - setStorageConfiguration(storageConfiguration): void { + setStorageConfiguration(storageConfiguration: StorageConfiguration): void { passOrThrow( isStorageConfiguration(storageConfiguration), () => 'Configuration expects a valid storageConfiguration', diff --git a/src/engine/cursor.spec.ts b/src/engine/cursor.spec.ts index d9672de5..1ffe635b 100644 --- a/src/engine/cursor.spec.ts +++ b/src/engine/cursor.spec.ts @@ -35,15 +35,15 @@ describe('cursor', () => { indexes: [ new Index({ type: INDEX_UNIQUE, - attributes: [ 'loginName' ], + attributes: ['loginName'], }), new Index({ type: INDEX_UNIQUE, - attributes: [ 'firstName', 'lastName' ], + attributes: ['firstName', 'lastName'], }), new Index({ type: INDEX_UNIQUE, - attributes: [ 'email' ], + attributes: ['email'], }), ], }); @@ -58,7 +58,7 @@ describe('cursor', () => { it('should throw if incompatible cursor provided', () => { function fn() { - processCursor({}, { a: 'b' }); + processCursor({} as Entity, { a: 'b' as any }); } expect(fn).toThrowErrorMatchingSnapshot(); @@ -66,15 +66,15 @@ describe('cursor', () => { it('should throw if cursor is malformed', () => { function fn1() { - processCursor(SomeEntity, { SomeEntity: [ 'b' ] }, []); + processCursor(SomeEntity, { SomeEntity: ['b' as any] }, []); } function fn2() { - processCursor(SomeEntity, { SomeEntity: [ [ {}, {}, {} ] ] }, []); + processCursor(SomeEntity, { SomeEntity: [[{}, {}, {}] as any] }, []); } function fn3() { - processCursor(SomeEntity, { SomeEntity: [ {} ] }, []); + processCursor(SomeEntity, { SomeEntity: [{} as any] }, []); } expect(fn1).toThrowErrorMatchingSnapshot(); @@ -87,7 +87,7 @@ describe('cursor', () => { processCursor( SomeEntity, { - SomeEntity: [ [ 'iDontKnow', 123 ] ], + SomeEntity: [['iDontKnow', 123]], }, [], ); @@ -99,7 +99,7 @@ describe('cursor', () => { it('should throw if an attribute is used which the data set is not sorted by', () => { function fn1() { processCursor(SomeEntity, { - SomeEntity: [ [ 'loginName', 123 ] ], + SomeEntity: [['loginName', 123]], }); } @@ -107,7 +107,7 @@ describe('cursor', () => { processCursor( SomeEntity, { - SomeEntity: [ [ 'loginName', 123 ] ], + SomeEntity: [['loginName', 123]], }, [ { @@ -122,7 +122,10 @@ describe('cursor', () => { processCursor( SomeEntity, { - SomeEntity: [ [ 'loginName', 123 ], [ 'email', 123 ] ], + SomeEntity: [ + ['loginName', 123], + ['email', 123], + ], }, [ { @@ -143,7 +146,7 @@ describe('cursor', () => { processCursor( SomeEntity, { - SomeEntity: [ [ 'firstName', 'John' ] ], + SomeEntity: [['firstName', 'John']], }, [ { @@ -158,7 +161,10 @@ describe('cursor', () => { processCursor( SomeEntity, { - SomeEntity: [ [ 'firstName', 'John' ], [ 'lastName', 'Snow' ] ], + SomeEntity: [ + ['firstName', 'John'], + ['lastName', 'Snow'], + ], }, [ { @@ -182,7 +188,7 @@ describe('cursor', () => { const cursor1 = processCursor( SomeEntity, { - SomeEntity: [ [ 'loginName', 'user1' ] ], + SomeEntity: [['loginName', 'user1']], }, [ { @@ -201,7 +207,7 @@ describe('cursor', () => { const cursor2 = processCursor( SomeEntity, { - SomeEntity: [ [ 'loginName', 123 ] ], + SomeEntity: [['loginName', 123]], }, [ { @@ -221,8 +227,8 @@ describe('cursor', () => { SomeEntity, { SomeEntity: [ - [ 'loginName', 'user1' ], - [ 'email', 'user1@example.com' ], + ['loginName', 'user1'], + ['email', 'user1@example.com'], ], }, [ @@ -250,7 +256,10 @@ describe('cursor', () => { it('when using attributes that are not all defined as unique', () => { const row1: CursorType = { - SomeEntity: [ [ 'firstName', 'John' ], [ 'id', 1123 ] ], + SomeEntity: [ + ['firstName', 'John'], + ['id', 1123], + ], }; const cursor1 = processCursor(SomeEntity, row1, [ @@ -347,9 +356,9 @@ describe('cursor', () => { const row2: CursorType = { SomeEntity: [ - [ 'firstName', 'John' ], - [ 'lastName', 'Snow' ], - [ 'id', 1123 ], + ['firstName', 'John'], + ['lastName', 'Snow'], + ['id', 1123], ], }; @@ -409,10 +418,10 @@ describe('cursor', () => { const row3: CursorType = { SomeEntity: [ - [ 'firstName', 'John' ], - [ 'email', 'john@example.com' ], - [ 'lastName', 'Snow' ], - [ 'id', 1123 ], + ['firstName', 'John'], + ['email', 'john@example.com'], + ['lastName', 'Snow'], + ['id', 1123], ], }; @@ -460,7 +469,7 @@ describe('cursor', () => { const cursor0 = processCursor( SomeEntity, { - SomeEntity: [ [ 'loginName', 123 ] ], + SomeEntity: [['loginName', 123]], }, [ { @@ -478,7 +487,10 @@ describe('cursor', () => { }; const row1: CursorType = { - SomeEntity: [ [ 'firstName', 'John' ], [ 'id', 1123 ] ], + SomeEntity: [ + ['firstName', 'John'], + ['id', 1123], + ], }; const cursor1 = processCursor( @@ -595,9 +607,9 @@ describe('cursor', () => { const row2: CursorType = { SomeEntity: [ - [ 'firstName', 'John' ], - [ 'lastName', 'Snow' ], - [ 'id', 1123 ], + ['firstName', 'John'], + ['lastName', 'Snow'], + ['id', 1123], ], }; @@ -667,10 +679,10 @@ describe('cursor', () => { const row3: CursorType = { SomeEntity: [ - [ 'firstName', 'John' ], - [ 'email', 'john@example.com' ], - [ 'lastName', 'Snow' ], - [ 'id', 1123 ], + ['firstName', 'John'], + ['email', 'john@example.com'], + ['lastName', 'Snow'], + ['id', 1123], ], }; diff --git a/src/engine/datatype/DataType.spec.ts b/src/engine/datatype/DataType.spec.ts index b4ad2784..6ef0bdc9 100644 --- a/src/engine/datatype/DataType.spec.ts +++ b/src/engine/datatype/DataType.spec.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-empty-function */ + import { DataType, DataTypeSetup, isDataType } from './DataType'; import { passOrThrow } from '../util'; @@ -16,9 +18,9 @@ describe('DataType', () => { it('should have a description', () => { function fn() { // eslint-disable-next-line no-new - new DataType({ + new DataType({ name: 'example', - }); + } as DataTypeSetup); } expect(fn).toThrowErrorMatchingSnapshot(); diff --git a/src/engine/datatype/DataType.ts b/src/engine/datatype/DataType.ts index 2607a396..70423780 100644 --- a/src/engine/datatype/DataType.ts +++ b/src/engine/datatype/DataType.ts @@ -2,8 +2,8 @@ import { passOrThrow, isFunction } from '../util'; import { ComplexDataType } from './ComplexDataType'; export type DataTypeSetup = { - name: string; - description: string; + name?: string; + description?: string; mock?: () => any; validate?: () => any; enforceRequired?: boolean; diff --git a/src/engine/datatype/DataTypeEnum.spec.ts b/src/engine/datatype/DataTypeEnum.spec.ts index 2abe2d15..d3258878 100644 --- a/src/engine/datatype/DataTypeEnum.spec.ts +++ b/src/engine/datatype/DataTypeEnum.spec.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-empty-function */ + import { DataTypeEnum, DataTypeEnumSetupType, @@ -12,19 +14,19 @@ describe('DataTypeEnum', () => { fn = () => { // eslint-disable-next-line no-new - new DataTypeEnum({ + new DataTypeEnum({ name: 'something', - }); + } as DataTypeEnumSetupType); }; expect(fn).toThrowErrorMatchingSnapshot(); fn = () => { // eslint-disable-next-line no-new - new DataTypeEnum({ + new DataTypeEnum({ name: 'something', values: {}, - }); + } as DataTypeEnumSetupType); }; expect(fn).toThrowErrorMatchingSnapshot(); @@ -35,38 +37,38 @@ describe('DataTypeEnum', () => { fn = () => { // eslint-disable-next-line no-new - new DataTypeEnum({ + new DataTypeEnum({ name: 'lorem', values: { '7': 8, }, - }); + } as DataTypeEnumSetupType); }; expect(fn).toThrowErrorMatchingSnapshot(); fn = () => { // eslint-disable-next-line no-new - new DataTypeEnum({ + new DataTypeEnum({ values: { ' abc ': 123, }, name: 'test', - }); + } as DataTypeEnumSetupType); }; expect(fn).toThrowErrorMatchingSnapshot(); fn = () => { // eslint-disable-next-line no-new - new DataTypeEnum({ + new DataTypeEnum({ name: 'another', values: { abc: 1, def: 2, 'hello-there': 3, }, - }); + } as DataTypeEnumSetupType); }; expect(fn).toThrowErrorMatchingSnapshot(); @@ -75,11 +77,11 @@ describe('DataTypeEnum', () => { it('should have a name', () => { function fn() { // eslint-disable-next-line no-new - new DataTypeEnum({ + new DataTypeEnum({ values: { item: 1, }, - }); + } as any); } expect(fn).toThrowErrorMatchingSnapshot(); @@ -99,14 +101,14 @@ describe('DataTypeEnum', () => { }); it('should have a fallback description', () => { - const dataType = new DataTypeEnum({ + const dataType = new DataTypeEnum({ name: 'example', values: { ACTION: 1, COMEDY: 2, DRAMA: 3, }, - }); + } as DataTypeEnumSetupType); expect(dataType.description).toBe('Enumeration set: ACTION, COMEDY, DRAMA'); }); @@ -126,10 +128,10 @@ describe('DataTypeEnum', () => { uniqueIds.push(valueId); }); - const dataType = new DataTypeEnum({ + const dataType = new DataTypeEnum({ name: 'example', values, - }); + } as DataTypeEnumSetupType); const randomValue1 = dataType.mock(); const randomValue2 = dataType.mock(); @@ -142,23 +144,23 @@ describe('DataTypeEnum', () => { describe('isDataTypeEnum', () => { it('should recognize objects of type DataTypeEnum', () => { - const enum1 = new DataTypeEnum({ + const enum1 = new DataTypeEnum({ name: 'enum1', values: { ACTION: 1, COMEDY: 2, DRAMA: 3, }, - }); + } as DataTypeEnumSetupType); - const enum2 = new DataTypeEnum({ + const enum2 = new DataTypeEnum({ name: 'enum2', values: { APPLE: 10, PEAR: 20, CHERRY: 30, }, - }); + } as DataTypeEnumSetupType); function fn() { passOrThrow( diff --git a/src/engine/datatype/DataTypeState.spec.ts b/src/engine/datatype/DataTypeState.spec.ts index cf0042e8..693e68b0 100644 --- a/src/engine/datatype/DataTypeState.spec.ts +++ b/src/engine/datatype/DataTypeState.spec.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-empty-function */ + import { DataTypeState, DataTypeStateSetupType, @@ -12,19 +14,19 @@ describe('DataTypeState', () => { fn = () => { // eslint-disable-next-line no-new - new DataTypeState({ + new DataTypeState({ name: 'something', - }); + } as DataTypeStateSetupType); }; expect(fn).toThrowErrorMatchingSnapshot(); fn = () => { // eslint-disable-next-line no-new - new DataTypeState({ + new DataTypeState({ name: 'something', states: {}, - }); + } as DataTypeStateSetupType); }; expect(fn).toThrowErrorMatchingSnapshot(); @@ -35,38 +37,38 @@ describe('DataTypeState', () => { fn = () => { // eslint-disable-next-line no-new - new DataTypeState({ + new DataTypeState({ name: 'progress', states: { '6': 1, }, - }); + } as DataTypeStateSetupType); }; expect(fn).toThrowErrorMatchingSnapshot(); fn = () => { // eslint-disable-next-line no-new - new DataTypeState({ + new DataTypeState({ states: { ' abc ': 123, }, name: 'test', - }); + } as DataTypeStateSetupType); }; expect(fn).toThrowErrorMatchingSnapshot(); fn = () => { // eslint-disable-next-line no-new - new DataTypeState({ + new DataTypeState({ name: 'another', states: { abc: 1, def: 2, 'hello-there': 3, }, - }); + } as DataTypeStateSetupType); }; expect(fn).toThrowErrorMatchingSnapshot(); @@ -75,11 +77,11 @@ describe('DataTypeState', () => { it('should have a name', () => { function fn() { // eslint-disable-next-line no-new - new DataTypeState({ + new DataTypeState({ states: { item: 1, }, - }); + } as any); } expect(fn).toThrowErrorMatchingSnapshot(); diff --git a/src/engine/datatype/DataTypeUser.spec.ts b/src/engine/datatype/DataTypeUser.spec.ts index a2245350..0dfdbdd9 100644 --- a/src/engine/datatype/DataTypeUser.spec.ts +++ b/src/engine/datatype/DataTypeUser.spec.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-empty-function */ + import { DataTypeUser, isDataTypeUser } from './DataTypeUser'; import { passOrThrow } from '../util'; diff --git a/src/engine/datatype/ListDataType.spec.ts b/src/engine/datatype/ListDataType.spec.ts index 37c232ad..7d89de74 100644 --- a/src/engine/datatype/ListDataType.spec.ts +++ b/src/engine/datatype/ListDataType.spec.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-empty-function */ + import { ListDataType, ListDataTypeSetupType, @@ -20,9 +22,9 @@ describe('ListDataType', () => { it('should have a description', () => { function fn() { // eslint-disable-next-line no-new - new ListDataType({ + new ListDataType({ name: 'example', - }); + } as ListDataTypeSetupType); } expect(fn).toThrowErrorMatchingSnapshot(); @@ -31,10 +33,10 @@ describe('ListDataType', () => { it('should have an item type', () => { function fn() { // eslint-disable-next-line no-new - new ListDataType({ + new ListDataType({ name: 'Example', description: 'Just some description', - }); + } as ListDataTypeSetupType); } expect(fn).toThrowErrorMatchingSnapshot(); @@ -89,7 +91,7 @@ describe('ListDataType', () => { new ListDataType({ name: 'Example', description: 'Just some description', - itemType: [ 2, 7, 13 ], + itemType: [2, 7, 13], }); } diff --git a/src/engine/datatype/ListDataType.ts b/src/engine/datatype/ListDataType.ts index 2d1569d9..5c999bea 100644 --- a/src/engine/datatype/ListDataType.ts +++ b/src/engine/datatype/ListDataType.ts @@ -140,7 +140,8 @@ export const isListDataType = (obj: any): boolean => { }; export const buildListDataType = (obj: { - itemType: Entity | ComplexDataType | DataTypeFunction; + itemType: any; + // itemType: Entity | ComplexDataType | DataTypeFunction; }): Function => { return ({ name, description }): ListDataType => new ListDataType({ diff --git a/src/engine/datatype/ObjectDataType.spec.ts b/src/engine/datatype/ObjectDataType.spec.ts index 93325afd..9d8fd425 100644 --- a/src/engine/datatype/ObjectDataType.spec.ts +++ b/src/engine/datatype/ObjectDataType.spec.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-empty-function */ + import { ObjectDataType, ObjectDataTypeSetupType, @@ -20,9 +22,9 @@ describe('ObjectDataType', () => { it('should have a description', () => { function fn() { // eslint-disable-next-line no-new - new ObjectDataType({ + new ObjectDataType({ name: 'example', - }); + } as ObjectDataTypeSetupType); } expect(fn).toThrowErrorMatchingSnapshot(); @@ -31,21 +33,21 @@ describe('ObjectDataType', () => { it('should have a map of attributes', () => { function fn() { // eslint-disable-next-line no-new - new ObjectDataType({ + new ObjectDataType({ name: 'Example', description: 'Just some description', - }); + } as ObjectDataTypeSetupType); } expect(fn).toThrowErrorMatchingSnapshot(); }); it("should return it's name", () => { - const objectDataType = new ObjectDataType({ + const objectDataType = new ObjectDataType({ name: 'someObjectDataTypeName', description: 'Just some description', attributes: {}, - }); + } as ObjectDataTypeSetupType); expect(objectDataType.name).toBe('someObjectDataTypeName'); expect(String(objectDataType)).toBe('someObjectDataTypeName'); @@ -54,11 +56,11 @@ describe('ObjectDataType', () => { it('should accept only maps or functions as attributes definition', () => { function fn() { // eslint-disable-next-line no-new - new ObjectDataType({ + new ObjectDataType({ name: 'Example', description: 'Just some description', - attributes: [ 2, 7, 13 ], - }); + attributes: [2, 7, 13], + } as any); } expect(fn).toThrowErrorMatchingSnapshot(); @@ -66,13 +68,13 @@ describe('ObjectDataType', () => { it('should reject non-map results of attribute definition functions', () => { function fn() { - const objectDataType = new ObjectDataType({ + const objectDataType = new ObjectDataType({ name: 'Example', description: 'Just some description', attributes: () => { - return [ 2, 7, 13 ]; + return [2, 7, 13] as any; }, - }); + } as ObjectDataTypeSetupType); objectDataType.getAttributes(); } @@ -82,11 +84,11 @@ describe('ObjectDataType', () => { it('should reject empty attribute maps', () => { function fn() { - const objectDataType = new ObjectDataType({ + const objectDataType = new ObjectDataType({ name: 'Example', description: 'Just some description', attributes: {}, - }); + } as ObjectDataTypeSetupType); objectDataType.getAttributes(); } @@ -100,9 +102,9 @@ describe('ObjectDataType', () => { name: 'Example', description: 'Just some description', attributes: { - name: { + name: { type: DataTypeString, - }, + } as any, }, }); @@ -119,10 +121,10 @@ describe('ObjectDataType', () => { description: 'Just some description', attributes: { name: { - type: {}, + type: {} as any, description: 'Just some description', }, - }, + } as any, }); objectDataType.getAttributes(); @@ -140,8 +142,8 @@ describe('ObjectDataType', () => { name: { type: DataTypeString, description: 'Just some description', - resolve: 123456, - }, + resolve: 123456 as any, + } as any, }, }); @@ -160,8 +162,8 @@ describe('ObjectDataType', () => { name: { type: DataTypeString, description: 'Just some description', - defaultValue: 123456, - }, + defaultValue: 123456 as any, + } as any, }, }); @@ -226,7 +228,7 @@ describe('ObjectDataType', () => { expect(attributes.id.type).toBe(DataTypeID); expect(attributes.name.type).toBe(DataTypeString); - const attributesNested = (attributes.nested.type).getAttributes(); + const attributesNested = (attributes.nested.type as Entity).getAttributes(); expect(attributesNested.randomInput.type).toBe(DataTypeString); }); diff --git a/src/engine/datatype/ObjectDataType.ts b/src/engine/datatype/ObjectDataType.ts index b27490dc..700f1d27 100644 --- a/src/engine/datatype/ObjectDataType.ts +++ b/src/engine/datatype/ObjectDataType.ts @@ -167,7 +167,8 @@ export const isObjectDataType = (obj: any): boolean => { }; export const buildObjectDataType = (obj: { - attributes: AttributesMap | AttributesMapGenerator; + // attributes: AttributesMap | AttributesMapGenerator | AttributeBase; + attributes: any; }): Function => { return ({ name, description }): ObjectDataType => new ObjectDataType({ diff --git a/src/engine/protocol/ProtocolConfiguration.ts b/src/engine/protocol/ProtocolConfiguration.ts index f71153c1..342662c0 100644 --- a/src/engine/protocol/ProtocolConfiguration.ts +++ b/src/engine/protocol/ProtocolConfiguration.ts @@ -1,4 +1,5 @@ import { passOrThrow, isString, isArray } from '../util'; +import { Configuration } from '../configuration/Configuration'; export type ProtocolConfigurationSetup = { features?: string[]; @@ -6,6 +7,7 @@ export type ProtocolConfigurationSetup = { export class ProtocolConfiguration { features: { [key: string]: boolean }; + getParentConfiguration: () => Configuration; constructor( setup: ProtocolConfigurationSetup = {} as ProtocolConfigurationSetup, diff --git a/src/engine/protocol/ProtocolType.ts b/src/engine/protocol/ProtocolType.ts index b938db4a..a6c221e2 100644 --- a/src/engine/protocol/ProtocolType.ts +++ b/src/engine/protocol/ProtocolType.ts @@ -21,6 +21,7 @@ export type ProtocolTypeSetup = { // asInput?: boolean; // } +// how to properly define this type ? export type ProtocolDataType = { name: string | Function; }; @@ -94,7 +95,8 @@ export class ProtocolType { addDynamicDataTypeMap( schemaDataTypeDetector: Function, - protocolDataType: ProtocolType, + protocolDataType: any, + // protocolDataType: ProtocolType, ): void { passOrThrow( isFunction(schemaDataTypeDetector), @@ -122,7 +124,7 @@ export class ProtocolType { schemaDataType: DataType | DataTypeFunction, sourceName?: string, asInput?: boolean, - ): ProtocolDataType { + ): any { const foundDynamicDataType = this._dynamicDataTypeMap.find( ({ schemaDataTypeDetector }) => schemaDataTypeDetector(schemaDataType), ); diff --git a/src/engine/storage/StorageConfiguration.ts b/src/engine/storage/StorageConfiguration.ts index af13a6cb..e1ee6566 100644 --- a/src/engine/storage/StorageConfiguration.ts +++ b/src/engine/storage/StorageConfiguration.ts @@ -1,4 +1,5 @@ import { passOrThrow } from '../util'; +import { Configuration } from '../configuration/Configuration'; export type StorageConfigurationSetup = { // todo improve typings ? @@ -13,6 +14,7 @@ export class StorageConfiguration { storageInstance: any; storageModels: any; connectionConfig: any; + getParentConfiguration: () => Configuration; constructor( setup: StorageConfigurationSetup = {} as StorageConfigurationSetup, diff --git a/src/graphqlProtocol/ProtocolGraphQL.js b/src/graphqlProtocol/ProtocolGraphQL.ts similarity index 97% rename from src/graphqlProtocol/ProtocolGraphQL.js rename to src/graphqlProtocol/ProtocolGraphQL.ts index 2f0c5dec..19985913 100644 --- a/src/graphqlProtocol/ProtocolGraphQL.js +++ b/src/graphqlProtocol/ProtocolGraphQL.ts @@ -1,3 +1,15 @@ +import { + GraphQLScalarType, + GraphQLID, + GraphQLInt, + GraphQLInputObjectType, + GraphQLObjectType, + GraphQLFloat, + GraphQLString, + GraphQLBoolean, + GraphQLEnumType, +} from 'graphql'; + import { ProtocolType } from '../engine/protocol/ProtocolType'; import { DataTypeID, @@ -16,15 +28,6 @@ import { DataTypeI18n, } from '../engine/datatype/dataTypes'; -import { - GraphQLScalarType, - GraphQLID, - GraphQLInt, - GraphQLFloat, - GraphQLString, - GraphQLBoolean, - GraphQLEnumType, -} from 'graphql'; import { isDataTypeState } from '../engine/datatype/DataTypeState'; import { isDataTypeEnum } from '../engine/datatype/DataTypeEnum'; import { isObjectDataType } from '../engine/datatype/ObjectDataType'; @@ -182,7 +185,7 @@ ProtocolGraphQL.addDynamicDataTypeMap( const dataInputType = generateDataInput( `${sourceName}-${name}`, params, - ); + ) as GraphQLInputObjectType; dataTypesRegistry.object[ uniqueName ] = dataInputType.getFields().wrapped.type; @@ -196,7 +199,7 @@ ProtocolGraphQL.addDynamicDataTypeMap( `${sourceName}-${name}`, params, graphRegistry, - ); + ) as GraphQLObjectType; dataTypesRegistry.object[ uniqueName ] = dataOutputType.getFields().wrapped.type; diff --git a/src/graphqlProtocol/ProtocolGraphQLConfiguration.js b/src/graphqlProtocol/ProtocolGraphQLConfiguration.ts similarity index 93% rename from src/graphqlProtocol/ProtocolGraphQLConfiguration.js rename to src/graphqlProtocol/ProtocolGraphQLConfiguration.ts index c0b97824..32d72a9d 100644 --- a/src/graphqlProtocol/ProtocolGraphQLConfiguration.js +++ b/src/graphqlProtocol/ProtocolGraphQLConfiguration.ts @@ -128,12 +128,12 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { ); } - generateUniquenessAttributesName(entity, attributes) { + generateUniquenessAttributesName(_entity, attributes) { return generateTypeName(attributes.join('-and-')); } generateUniquenessAttributesFieldName( - entity, + _entity, attribute, uniquenessAttributesName, ) { @@ -201,15 +201,19 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { ); } - generateInputTypeName(baseName) { + generateInputTypeName(baseName: string) { return generateTypeNamePascalCase(`${baseName}-input`); } - generateDataOutPutTypeName(baseName) { + generateDataOutPutTypeName(baseName: string) { return generateTypeNamePascalCase(`${baseName}-data-output`); } - generateNestedDataOutPutTypeName(baseName, nestedParamName, level) { + generateNestedDataOutPutTypeName( + baseName: string, + nestedParamName: string, + level?: number, + ) { const levelStr = level > 1 ? `L${level}` : ''; return generateTypeNamePascalCase( @@ -217,11 +221,11 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { ); } - generateOutPutTypeName(baseName) { + generateOutPutTypeName(baseName: string) { return generateTypeNamePascalCase(`${baseName}-output`); } - generateSortKeyName(attribute, ascending) { + generateSortKeyName(attribute: any, ascending?: boolean) { const direction = ascending ? 'ASC' : 'DESC'; return `${generateTypeNameUpperCase(attribute.name)}_${direction}`; @@ -254,12 +258,12 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { return generateTypeNamePascalCase(`${typeName}-edge`); } - generateConnectionTypeName(entity) { + generateConnectionTypeName(entity): string { const typeName = this.generateEntityTypeName(entity); return generateTypeNamePascalCase(`${typeName}-connection`); } } -export const isProtocolGraphQLConfiguration = obj => { +export const isProtocolGraphQLConfiguration = (obj: any): boolean => { return obj instanceof ProtocolGraphQLConfiguration; }; diff --git a/src/graphqlProtocol/action.spec.js b/src/graphqlProtocol/action.spec.ts similarity index 100% rename from src/graphqlProtocol/action.spec.js rename to src/graphqlProtocol/action.spec.ts diff --git a/src/graphqlProtocol/action.ts b/src/graphqlProtocol/action.ts index 6781901b..c8f75afd 100644 --- a/src/graphqlProtocol/action.ts +++ b/src/graphqlProtocol/action.ts @@ -9,6 +9,7 @@ import { } from './io'; import { ProtocolGraphQL } from './ProtocolGraphQL'; +import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; import { isObjectDataType } from '../engine/datatype/ObjectDataType'; import { isListDataType } from '../engine/datatype/ListDataType'; import { validateActionPayload } from '../engine/validation'; @@ -97,7 +98,7 @@ export const handlePermission = async (context, action, input) => { userRoles, action, input, - context + context, ); if (!permissionWhere) { @@ -122,7 +123,7 @@ export const handlePermission = async (context, action, input) => { }; export const generateActions = (graphRegistry, actionTypeFilter) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const actions = {}; @@ -198,6 +199,7 @@ export const generateActions = (graphRegistry, actionTypeFilter) => { clientMutationId = args.input.clientMutationId; args.input.data = await fillDefaultValues(input, payload, context); + // would it make sense to pass args.input.data instead of payload await validateActionPayload(input, payload, action, context); } @@ -228,8 +230,7 @@ export const generateActions = (graphRegistry, actionTypeFilter) => { result, clientMutationId, }; - } - catch (error) { + } catch (error) { if (action.postProcessor) { await action.postProcessor( error, diff --git a/src/graphqlProtocol/connection.js b/src/graphqlProtocol/connection.ts similarity index 89% rename from src/graphqlProtocol/connection.js rename to src/graphqlProtocol/connection.ts index e92bd1da..25d74da5 100644 --- a/src/graphqlProtocol/connection.js +++ b/src/graphqlProtocol/connection.ts @@ -5,15 +5,21 @@ import { GraphQLList, GraphQLBoolean, } from 'graphql'; +import { first, last } from 'lodash'; import { GraphQLCursor } from './dataTypes'; import { resolveByFind } from './resolver'; import { ProtocolGraphQL } from './ProtocolGraphQL'; +import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; import { generateSortInput } from './sort'; import { generateFilterInput } from './filter'; -import * as _ from 'lodash'; +// import { Entity } from '../engine/entity/Entity'; + +export type ConnectioNode = { + cursor: any; +}; export const generateConnectionArgs = (entity, graphRegistry) => { const sortInput = generateSortInput(entity); @@ -48,14 +54,22 @@ export const generateConnectionArgs = (entity, graphRegistry) => { }; }; -export const validateConnectionArgs = (source, args, context, info) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); - const maxPageSize = protocolConfiguration.getMaxPageSize( - source, - args, - context, - info, - ); +export const validateConnectionArgs = ( + _source, + args, + // _context, + // _info, +): void => { + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; + + // const maxPageSize = protocolConfiguration.getMaxPageSize( + // source, + // args, + // context, + // info, + // ); + + const maxPageSize = protocolConfiguration.getMaxPageSize(); if (args.first >= 0 && args.last >= 0) { throw new Error('`first` and `last` settings are mutual exclusive'); @@ -78,7 +92,7 @@ export const validateConnectionArgs = (source, args, context, info) => { } }; -export const forceSortByUnique = (orderBy, entity) => { +export const forceSortByUnique = (orderBy, entity): void => { const attributes = entity.getAttributes(); let foundUnique = false; @@ -124,7 +138,9 @@ const pageInfoType = new GraphQLObjectType({ }); export const generateConnectionType = config => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + // const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; + const { nodeType, entity } = config; const typeNamePluralListName = entity.graphql.typeNamePluralPascalCase; let cursor; @@ -204,10 +220,10 @@ export const buildCursor = (entityName, primaryAttributeName, args, data) => { export const connectionFromData = ( { transformedData, originalData }, entity, - source, + _source, args, context, - info, + _info, parentConnection, pageInfoFromData, ) => { @@ -233,14 +249,14 @@ export const connectionFromData = ( const edges = transformedData.map(nodeToEdge); - const firstNode = _.first(edges); - const lastNode = _.last(edges); + const firstNode: ConnectioNode = first(edges); + const lastNode: ConnectioNode = last(edges); return { edges, totalCount: async () => { const storageType = entity.storageType; - return await storageType.count(entity, args, context, parentConnection); + return storageType.count(entity, args, context, parentConnection); }, pageInfo: { startCursor: firstNode ? firstNode.cursor : null, @@ -273,7 +289,7 @@ export const generateReverseConnections = ( ) => { const schema = configuration.getSchema(); const schemaEntities = schema.getEntities(); - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const fields = {}; diff --git a/src/graphqlProtocol/dataTypes.spec.js b/src/graphqlProtocol/dataTypes.spec.ts similarity index 55% rename from src/graphqlProtocol/dataTypes.spec.js rename to src/graphqlProtocol/dataTypes.spec.ts index e82021ff..71f46039 100644 --- a/src/graphqlProtocol/dataTypes.spec.js +++ b/src/graphqlProtocol/dataTypes.spec.ts @@ -5,72 +5,94 @@ import { parseValue } from 'graphql'; describe('dataTypes', () => { it('GraphQLDateTime', () => { - const bad1 = () => GraphQLDateTime.parseLiteral(parseValue('"foo"')); + const bad1 = () => GraphQLDateTime.parseLiteral(parseValue('"foo"'), null); expect(bad1).toThrowErrorMatchingSnapshot(); const bad2 = () => - GraphQLDateTime.parseLiteral(parseValue('"2000-01-02 111:12:13+14:15"')); + GraphQLDateTime.parseLiteral( + parseValue('"2000-01-02 111:12:13+14:15"'), + null, + ); expect(bad2).toThrowErrorMatchingSnapshot('bad hour'); const bad3 = () => - GraphQLDateTime.parseLiteral(parseValue('"2000-31-02 11:12:13+14:15"')); + GraphQLDateTime.parseLiteral( + parseValue('"2000-31-02 11:12:13+14:15"'), + null, + ); expect(bad3).toThrowErrorMatchingSnapshot('bad month'); const bad4 = () => - GraphQLDateTime.parseLiteral(parseValue('"2000-01-02 11:62:13+14:15"')); + GraphQLDateTime.parseLiteral( + parseValue('"2000-01-02 11:62:13+14:15"'), + null, + ); expect(bad4).toThrowErrorMatchingSnapshot('bad minute'); const good1 = () => - GraphQLDateTime.parseLiteral(parseValue('"2000-01-02 11:12:13+14:15"')); + GraphQLDateTime.parseLiteral( + parseValue('"2000-01-02 11:12:13+14:15"'), + null, + ); expect(good1).not.toThrow(); const good2 = () => - GraphQLDateTime.parseLiteral(parseValue('"0003-01-02 21:12:13+14:15"')); + GraphQLDateTime.parseLiteral( + parseValue('"0003-01-02 21:12:13+14:15"'), + null, + ); expect(good2).not.toThrow(); }); it('GraphQLDate', () => { - const bad1 = () => GraphQLDate.parseLiteral(parseValue('"foo"')); + const bad1 = () => GraphQLDate.parseLiteral(parseValue('"foo"'), null); expect(bad1).toThrowErrorMatchingSnapshot(); - const bad2 = () => GraphQLDate.parseLiteral(parseValue('"2000-01-32"')); + const bad2 = () => + GraphQLDate.parseLiteral(parseValue('"2000-01-32"'), null); expect(bad2).toThrowErrorMatchingSnapshot('bad day'); - const bad3 = () => GraphQLDate.parseLiteral(parseValue('"2000-31-02"')); + const bad3 = () => + GraphQLDate.parseLiteral(parseValue('"2000-31-02"'), null); expect(bad3).toThrowErrorMatchingSnapshot('bad month'); - const bad4 = () => GraphQLDate.parseLiteral(parseValue('"01-02"')); + const bad4 = () => GraphQLDate.parseLiteral(parseValue('"01-02"'), null); expect(bad4).toThrowErrorMatchingSnapshot('bad date'); - const good1 = () => GraphQLDate.parseLiteral(parseValue('"2000-01-02"')); + const good1 = () => + GraphQLDate.parseLiteral(parseValue('"2000-01-02"'), null); expect(good1).not.toThrow(); - const good2 = () => GraphQLDate.parseLiteral(parseValue('"0003-01-02"')); + const good2 = () => + GraphQLDate.parseLiteral(parseValue('"0003-01-02"'), null); expect(good2).not.toThrow(); }); it('GraphQLTime', () => { - const bad1 = () => GraphQLTime.parseLiteral(parseValue('"foo"')); + const bad1 = () => GraphQLTime.parseLiteral(parseValue('"foo"'), null); expect(bad1).toThrowErrorMatchingSnapshot(); const bad2 = () => - GraphQLTime.parseLiteral(parseValue('"111:12:13+14:15"')); + GraphQLTime.parseLiteral(parseValue('"111:12:13+14:15"'), null); expect(bad2).toThrowErrorMatchingSnapshot('bad hour'); - const bad3 = () => GraphQLTime.parseLiteral(parseValue('"11:12:13+24:15"')); + const bad3 = () => + GraphQLTime.parseLiteral(parseValue('"11:12:13+24:15"'), null); expect(bad3).toThrowErrorMatchingSnapshot('bad tz hour'); - const bad4 = () => GraphQLTime.parseLiteral(parseValue('"11:62:13+14:15"')); + const bad4 = () => + GraphQLTime.parseLiteral(parseValue('"11:62:13+14:15"'), null); expect(bad4).toThrowErrorMatchingSnapshot('bad minute'); const good1 = () => - GraphQLTime.parseLiteral(parseValue('"11:12:13+14:15"')); + GraphQLTime.parseLiteral(parseValue('"11:12:13+14:15"'), null); expect(good1).not.toThrow(); - const good2 = () => GraphQLTime.parseLiteral(parseValue('"21:12:13"')); + const good2 = () => + GraphQLTime.parseLiteral(parseValue('"21:12:13"'), null); expect(good2).not.toThrow(); - const good3 = () => GraphQLTime.parseLiteral(parseValue('"21:12"')); + const good3 = () => GraphQLTime.parseLiteral(parseValue('"21:12"'), null); expect(good3).not.toThrow(); }); }); diff --git a/src/graphqlProtocol/dataTypes.js b/src/graphqlProtocol/dataTypes.ts similarity index 100% rename from src/graphqlProtocol/dataTypes.js rename to src/graphqlProtocol/dataTypes.ts diff --git a/src/graphqlProtocol/filter.spec.js b/src/graphqlProtocol/filter.spec.ts similarity index 100% rename from src/graphqlProtocol/filter.spec.js rename to src/graphqlProtocol/filter.spec.ts diff --git a/src/graphqlProtocol/filter.ts b/src/graphqlProtocol/filter.ts index 1d72ea55..95e446fc 100644 --- a/src/graphqlProtocol/filter.ts +++ b/src/graphqlProtocol/filter.ts @@ -6,14 +6,15 @@ import { } from 'graphql'; import * as _ from 'lodash'; import { ProtocolGraphQL } from './ProtocolGraphQL'; -import { isEntity } from '../engine/entity/Entity'; +import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; +import { isEntity, Entity } from '../engine/entity/Entity'; import { storageDataTypeCapabilities, storageDataTypeCapabilityType, } from '../engine/constants'; import { isComplexDataType } from '../engine/datatype/ComplexDataType'; import { isArray, isMap } from '../engine/util'; -import { isViewEntity } from '../engine/entity/ViewEntity'; +import { isViewEntity, ViewEntity } from '../engine/entity/ViewEntity'; import { isShadowEntity } from '../engine/entity/ShadowEntity'; const AND_OPERATOR = 'AND'; @@ -27,7 +28,8 @@ const DEEP_FILTER_OPERATOR = 'filter'; const PRE_FILTER_OPERATOR = 'pre_filter'; export const generateFilterInput = (entity, graphRegistry) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; + const typeNamePluralListName = entity.graphql.typeNamePluralPascalCase; const storageType = entity.storageType; @@ -226,11 +228,11 @@ const deepFilterResolver = async (entity, filter, context, path) => { }; export const transformFilterLevel = async ( - entity, + entity: Entity | ViewEntity, filters = {}, - attributes, - context, - path, + attributes: any, + context?: any, + path?: string[], ) => { const ret = {}; const hasFilter = {}; diff --git a/src/graphqlProtocol/generator.spec.js b/src/graphqlProtocol/generator.spec.ts similarity index 100% rename from src/graphqlProtocol/generator.spec.js rename to src/graphqlProtocol/generator.spec.ts diff --git a/src/graphqlProtocol/generator.js b/src/graphqlProtocol/generator.ts similarity index 88% rename from src/graphqlProtocol/generator.js rename to src/graphqlProtocol/generator.ts index e7ebf98e..8a87fac6 100644 --- a/src/graphqlProtocol/generator.js +++ b/src/graphqlProtocol/generator.ts @@ -2,6 +2,7 @@ import * as _ from 'lodash'; import { RELAY_TYPE_PROMOTER_FIELD } from './protocolGraphqlConstants'; import { graphRegistry } from './graphRegistry'; import { ProtocolGraphQL } from './ProtocolGraphQL'; +import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; import { shaper } from 'json-shaper'; @@ -40,7 +41,7 @@ export const getTypeForEntityFromGraphRegistry = entity => { // prepare models for graphql export const extendModelsForGql = entities => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; _.forEach(entities, entity => { entity.graphql = entity.graphql || {}; @@ -198,9 +199,9 @@ export const generateGraphQLSchema = configuration => { return; } - const field = { - description: attribute.description, - }; + // const field = { + // description: attribute.description, + // }; let attributeType = attribute.type; @@ -210,17 +211,26 @@ export const generateGraphQLSchema = configuration => { const primaryAttribute = targetEntity.getPrimaryAttribute(); attributeType = primaryAttribute.type; - const reference = { - description: attribute.description, - }; + // const reference = { + // description: attribute.description, + // }; const targetTypeName = targetEntity.graphql.typeName; - reference.type = graphRegistry.types[targetTypeName].type; - reference.resolve = resolveByFindOne( - targetEntity, - ({ source }) => source[attribute.gqlFieldName], - ); + // reference.type = graphRegistry.types[targetTypeName].type; + // reference.resolve = resolveByFindOne( + // targetEntity, + // ({ source }) => source[attribute.gqlFieldName], + // ); + + const reference = { + description: attribute.description, + type: graphRegistry.types[targetTypeName].type, + resolve: resolveByFindOne( + targetEntity, + ({ source }) => source[attribute.gqlFieldName], + ), + }; const referenceFieldName = protocolConfiguration.generateReferenceFieldName( targetEntity, @@ -236,16 +246,24 @@ export const generateGraphQLSchema = configuration => { ); // make it non-nullable if it's required - if (attribute.required) { - field.type = new GraphQLNonNull(fieldType); - } else { - field.type = fieldType; - } + // if (attribute.required) { + // field.type = new GraphQLNonNull(fieldType); + // } else { + // field.type = fieldType; + // } // use computed value's function as the field resolver - if (attribute.resolve) { - field.resolve = attribute.resolve; - } + // if (attribute.resolve) { + // field.resolve = attribute.resolve; + // } + + const field = { + description: attribute.description, + type: attribute.required + ? new GraphQLNonNull(fieldType) + : fieldType, + resolve: attribute.resolve ? attribute.resolve : undefined, + }; fields[attribute.gqlFieldName] = field; @@ -325,7 +343,7 @@ export const generateGraphQLSchema = configuration => { // build the query type const queryType = new GraphQLObjectType({ name: 'Query', - root: 'The root query type', + // root: 'The root query type', fields: () => { const listQueries = generateListQueries(graphRegistry); @@ -334,7 +352,7 @@ export const generateGraphQLSchema = configuration => { // override args.id of relay to args.nodeId nodeField.args.nodeId = nodeField.args.id; - nodeField.resolve = (obj, { nodeId }, context, info) => + nodeField.resolve = (_obj, { nodeId }, context, info) => idFetcher(nodeId, context, info); delete nodeField.args.id; @@ -349,7 +367,7 @@ export const generateGraphQLSchema = configuration => { const mutationType = new GraphQLObjectType({ name: 'Mutation', - root: 'The root mutation type', + // root: 'The root mutation type', fields: () => { const mutations = generateMutations(graphRegistry); diff --git a/src/graphqlProtocol/graphRegistry.js b/src/graphqlProtocol/graphRegistry.ts similarity index 100% rename from src/graphqlProtocol/graphRegistry.js rename to src/graphqlProtocol/graphRegistry.ts diff --git a/src/graphqlProtocol/helper.js b/src/graphqlProtocol/helper.ts similarity index 92% rename from src/graphqlProtocol/helper.js rename to src/graphqlProtocol/helper.ts index 85f854d9..4689cb9d 100644 --- a/src/graphqlProtocol/helper.js +++ b/src/graphqlProtocol/helper.ts @@ -1,15 +1,17 @@ -import { ProtocolGraphQL } from './ProtocolGraphQL'; import * as _ from 'lodash'; +import { ProtocolGraphQL } from './ProtocolGraphQL'; +import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; + import { INDEX_UNIQUE } from '../engine/index/Index'; import { CustomError } from '../engine/CustomError'; export const getEntityUniquenessAttributes = entity => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const ret = []; if (!entity.getIndexes) { - return ret + return ret; } const entityIndexes = entity.getIndexes(); diff --git a/src/graphqlProtocol/io.spec.js b/src/graphqlProtocol/io.spec.ts similarity index 92% rename from src/graphqlProtocol/io.spec.js rename to src/graphqlProtocol/io.spec.ts index bcaa89ad..9560ab2e 100644 --- a/src/graphqlProtocol/io.spec.js +++ b/src/graphqlProtocol/io.spec.ts @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/no-empty-function */ /* eslint-disable @typescript-eslint/explicit-function-return-type */ +import { GraphQLInputObjectType, GraphQLObjectType } from 'graphql'; import { Action } from '../engine/action/Action'; import { DataTypeString, DataTypeInteger } from '../engine/datatype/dataTypes'; @@ -99,7 +100,8 @@ describe('io', () => { const inputFields = type.getFields(); expect(inputFields).toMatchSnapshot(); - const dataInputType = inputFields.data.type; + // const dataInputType = inputFields.data.type; + const dataInputType = inputFields.data.type as GraphQLInputObjectType; const dataInputFields = dataInputType.getFields(); expect(dataInputFields).toMatchSnapshot(); }); @@ -130,7 +132,9 @@ describe('io', () => { const outputFields = type.getFields(); expect(outputFields).toMatchSnapshot(); - const resultOutputType = outputFields.result.type; + // const resultOutputType = outputFields.result.type; + const resultOutputType = outputFields.result.type as GraphQLObjectType; + const resultOutputFields = resultOutputType.getFields(); expect(resultOutputFields).toMatchSnapshot(); }); @@ -244,11 +248,15 @@ describe('io', () => { const inputFields = type.getFields(); expect(inputFields).toMatchSnapshot(); - const dataInputType = inputFields.data.type; + // const dataInputType = inputFields.data.type; + const dataInputType = inputFields.data.type as GraphQLInputObjectType; const dataInputFields = dataInputType.getFields(); expect(dataInputFields).toMatchSnapshot(); - const playersInputType = dataInputFields.players.type; + // const playersInputType = dataInputFields.players.type; + const playersInputType = dataInputFields.players + .type as GraphQLInputObjectType; + const playersInputFields = playersInputType.getFields(); expect(playersInputFields).toMatchSnapshot(); diff --git a/src/graphqlProtocol/io.ts b/src/graphqlProtocol/io.ts index 001b7b58..0e89d0a4 100644 --- a/src/graphqlProtocol/io.ts +++ b/src/graphqlProtocol/io.ts @@ -11,6 +11,8 @@ import { import * as _ from 'lodash'; import { ProtocolGraphQL } from './ProtocolGraphQL'; +import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; + import { DataOutputField, InputFields, @@ -62,7 +64,9 @@ const generateDataInputField = ( true, ); } else if (param.i18n) { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + // const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; + const languages = protocolConfiguration .getParentConfiguration() .getLanguages(); @@ -153,8 +157,12 @@ const generateDataInputFields = ( }; //GraphQLInputObjectType | ? -export const generateDataInput = (baseName, inputParams, singleParam) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); +export const generateDataInput = ( + baseName: string, + inputParams: any, + singleParam?: any, +) => { + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; if (singleParam) { // eslint-disable-next-line no-use-before-define @@ -176,6 +184,7 @@ export const generateDataInput = (baseName, inputParams, singleParam) => { }, }); + dataInputType.getFields(); return dataInputType; }; @@ -185,7 +194,7 @@ export const generateNestedDataInput = ( nestedParamName, level = 1, ) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const dataInputType = new GraphQLInputObjectType({ name: protocolConfiguration.generateNestedDataInputTypeName( @@ -215,7 +224,7 @@ export const generateInput = ( isField, includeClientMutationId = false, ): GraphQLInputObjectType => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const inputType = new GraphQLInputObjectType({ name: protocolConfiguration.generateInputTypeName(baseName), @@ -259,7 +268,7 @@ const generateDataOutputField = ( level = 0, returnAsFieldNameMap = false, ): GraphQLObjectType | WrappedDataOutputField => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; let paramType = param.type; let baseFieldType; @@ -413,12 +422,12 @@ const generateDataOutputFields = ( }; export const generateDataOutput = ( - baseName, - outputParams, - graphRegistry, - singleParam, + baseName: string, + outputParams: any, + graphRegistry: any, + singleParam?: any, ): GraphQLObjectType | WrappedDataOutputField => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; if (singleParam) { // eslint-disable-next-line no-use-before-define @@ -446,10 +455,10 @@ export const generateNestedDataOutput = ( baseName, nestedParam, nestedParamName, - graphRegistry, + graphRegistry?: any, level = 1, ) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const dataOutputType = new GraphQLObjectType({ name: protocolConfiguration.generateNestedDataOutPutTypeName( @@ -480,7 +489,7 @@ export const generateOutput = ( isField, includeClientMutationId = false, ): GraphQLObjectType => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const outputType = new GraphQLObjectType({ name: protocolConfiguration.generateOutPutTypeName(baseName), diff --git a/src/graphqlProtocol/mutation.js b/src/graphqlProtocol/mutation.ts similarity index 93% rename from src/graphqlProtocol/mutation.js rename to src/graphqlProtocol/mutation.ts index 47261c40..4ea74011 100644 --- a/src/graphqlProtocol/mutation.js +++ b/src/graphqlProtocol/mutation.ts @@ -5,12 +5,15 @@ import { GraphQLInputObjectType, GraphQLObjectType, GraphQLInt, + GraphQLInputFieldConfigMap, + GraphQLFieldConfigMap, } from 'graphql'; import { fromGlobalId } from 'graphql-relay'; import * as _ from 'lodash'; import { ProtocolGraphQL } from './ProtocolGraphQL'; +import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; import { getEntityUniquenessAttributes } from './helper'; import { getMutationResolver } from './resolver'; import { isEntity } from '../engine/entity/Entity'; @@ -18,7 +21,8 @@ import { isEntity } from '../engine/entity/Entity'; const i18nInputFieldTypesCache = {}; const generateI18nInputFieldType = (entity, entityMutation, attribute) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; + const i18nFieldTypeName = protocolConfiguration.generateMutationI18nAttributeInputTypeName( entity, entityMutation, @@ -42,11 +46,7 @@ const generateI18nInputFieldType = (entity, entityMutation, attribute) => { const i18nFieldType = new GraphQLInputObjectType({ name: i18nFieldTypeName, - description: `**\`${ - entityMutation.name - }\`** mutation translations input type for **\`${typeNamePascalCase}.${ - attribute.gqlFieldName - }\`**`, + description: `**\`${entityMutation.name}\`** mutation translations input type for **\`${typeNamePascalCase}.${attribute.gqlFieldName}\`**`, fields: () => { const i18nFields = {}; @@ -72,7 +72,7 @@ const generateI18nInputFieldType = (entity, entityMutation, attribute) => { }; export const generateMutationInstanceInput = (entity, entityMutation) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const typeNamePascalCase = entity.graphql.typeNamePascalCase; @@ -81,12 +81,10 @@ export const generateMutationInstanceInput = (entity, entityMutation) => { entity, entityMutation, ), - description: `**\`${ - entityMutation.name - }\`** mutation input type for **\`${typeNamePascalCase}\`**`, + description: `**\`${entityMutation.name}\`** mutation input type for **\`${typeNamePascalCase}\`**`, fields: () => { - const fields = {}; + const fields: GraphQLInputFieldConfigMap = {}; const entityAttributes = entity.getAttributes(); @@ -144,7 +142,7 @@ export const generateMutationInput = ( entityMutation, entityMutationInstanceInputType, ) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const typeNamePascalCase = entity.graphql.typeNamePascalCase; @@ -156,7 +154,7 @@ export const generateMutationInput = ( description: `Mutation input type for **\`${typeNamePascalCase}\`**`, fields: () => { - const fields = { + const fields: GraphQLInputFieldConfigMap = { clientMutationId: { type: GraphQLString, }, @@ -188,7 +186,7 @@ export const generateMutationByPrimaryAttributeInput = ( entityMutationInstanceInputType, primaryAttribute, ) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const fieldName = primaryAttribute.gqlFieldName; const fieldType = ProtocolGraphQL.convertToProtocolDataType( @@ -207,7 +205,7 @@ export const generateMutationByPrimaryAttributeInput = ( description: `Mutation input type for **\`${typeNamePascalCase}\`** using the **\`${fieldName}\`**`, fields: () => { - const fields = { + const fields: GraphQLInputFieldConfigMap = { clientMutationId: { type: GraphQLString, }, @@ -237,7 +235,7 @@ export const generateInstanceUniquenessInput = ( uniquenessAttributes, graphRegistry, ) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const typeNamePascalCase = entity.graphql.typeNamePascalCase; @@ -246,12 +244,10 @@ export const generateInstanceUniquenessInput = ( entity, uniquenessAttributes.uniquenessName, ), - description: `Input type for **\`${typeNamePascalCase}\`** using data uniqueness (${ - uniquenessAttributes.attributes - }) to resolve the ID`, + description: `Input type for **\`${typeNamePascalCase}\`** using data uniqueness (${uniquenessAttributes.attributes}) to resolve the ID`, fields: () => { - const fields = {}; + const fields: GraphQLInputFieldConfigMap = {}; const entityAttributes = entity.getAttributes(); @@ -282,8 +278,7 @@ export const generateInstanceUniquenessInput = ( ? new GraphQLNonNull(fieldType) : fieldType, }; - } - else { + } else { fields[attribute.gqlFieldName] = { type: fieldType, }; @@ -303,8 +298,7 @@ export const generateInstanceUniquenessInput = ( }; }); } - } - else { + } else { const fieldType = ProtocolGraphQL.convertToProtocolDataType( attributeType, entity.name, @@ -350,7 +344,7 @@ export const generateMutationInstanceNestedInput = ( entityMutation, graphRegistry, ) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const typeNamePascalCase = entity.graphql.typeNamePascalCase; @@ -359,12 +353,10 @@ export const generateMutationInstanceNestedInput = ( entity, entityMutation, ), - description: `**\`${ - entityMutation.name - }\`** mutation input type for **\`${typeNamePascalCase}\`** using data uniqueness to resolve references`, + description: `**\`${entityMutation.name}\`** mutation input type for **\`${typeNamePascalCase}\`** using data uniqueness to resolve references`, fields: () => { - const fields = {}; + const fields: GraphQLInputFieldConfigMap = {}; const entityAttributes = entity.getAttributes(); @@ -398,8 +390,7 @@ export const generateMutationInstanceNestedInput = ( ? new GraphQLNonNull(fieldType) : fieldType, }; - } - else { + } else { fields[attribute.gqlFieldName] = { type: fieldType, }; @@ -419,8 +410,7 @@ export const generateMutationInstanceNestedInput = ( }; }); } - } - else { + } else { const fieldType = ProtocolGraphQL.convertToProtocolDataType( attributeType, entity.name, @@ -464,7 +454,7 @@ export const generateMutationNestedInput = ( entityMutation, entityMutationInstanceUniquenessInputType, ) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const typeNamePascalCase = entity.graphql.typeNamePascalCase; @@ -476,7 +466,7 @@ export const generateMutationNestedInput = ( description: `Mutation input type for **\`${typeNamePascalCase}\`** using data uniqueness to resolve references`, fields: () => { - const fields = { + const fields: GraphQLInputFieldConfigMap = { clientMutationId: { type: GraphQLString, }, @@ -507,7 +497,7 @@ export const generateMutationOutput = ( type, entityMutation, ) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const typeNamePascalCase = entity.graphql.typeNamePascalCase; @@ -519,7 +509,7 @@ export const generateMutationOutput = ( description: `Mutation output type for **\`${typeNamePascalCase}\`**`, fields: () => { - const fields = { + const fields: GraphQLFieldConfigMap = { clientMutationId: { type: GraphQLString, }, @@ -546,8 +536,7 @@ export const generateMutationOutput = ( description: primaryAttribute.description, }; } - } - else { + } else { fields[typeName] = { type: new GraphQLNonNull(type), }; @@ -581,7 +570,7 @@ const extractIdFromNodeId = (graphRegistry, sourceEntityName, nodeId) => { }; export const generateMutations = graphRegistry => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const mutations = {}; generateInstanceUniquenessInputs(graphRegistry); diff --git a/src/graphqlProtocol/protocolGraphqlConstants.js b/src/graphqlProtocol/protocolGraphqlConstants.ts similarity index 100% rename from src/graphqlProtocol/protocolGraphqlConstants.js rename to src/graphqlProtocol/protocolGraphqlConstants.ts diff --git a/src/graphqlProtocol/query.js b/src/graphqlProtocol/query.ts similarity index 93% rename from src/graphqlProtocol/query.js rename to src/graphqlProtocol/query.ts index c7953e18..cff7e4f3 100644 --- a/src/graphqlProtocol/query.js +++ b/src/graphqlProtocol/query.ts @@ -1,14 +1,15 @@ +import { GraphQLNonNull, GraphQLID } from 'graphql'; import * as _ from 'lodash'; import { ProtocolGraphQL } from './ProtocolGraphQL'; - -import { GraphQLNonNull, GraphQLID } from 'graphql'; +import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; import { resolveByFind, resolveByFindOne } from './resolver'; import { isEntity } from '../engine/entity/Entity'; import { isViewEntity } from '../engine/entity/ViewEntity'; export const generateListQueries = graphRegistry => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; + const listQueries = {}; _.forEach(graphRegistry.types, ({ entity }, typeName) => { @@ -32,7 +33,7 @@ export const generateListQueries = graphRegistry => { }; export const generateInstanceQueries = (graphRegistry, idFetcher) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const instanceQueries = {}; _.forEach(graphRegistry.types, ({ type, entity }) => { @@ -54,7 +55,7 @@ export const generateInstanceQueries = (graphRegistry, idFetcher) => { type: new GraphQLNonNull(GraphQLID), }, }, - resolve: (source, { nodeId }, context, info) => + resolve: (_source, { nodeId }, context, info) => idFetcher(nodeId, context, info), }; diff --git a/src/graphqlProtocol/resolver.js b/src/graphqlProtocol/resolver.ts similarity index 95% rename from src/graphqlProtocol/resolver.js rename to src/graphqlProtocol/resolver.ts index f78ac7fd..6afd0120 100644 --- a/src/graphqlProtocol/resolver.js +++ b/src/graphqlProtocol/resolver.ts @@ -6,6 +6,7 @@ import { } from './util'; import { ProtocolGraphQL } from './ProtocolGraphQL'; +import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; import { validateConnectionArgs, @@ -37,16 +38,17 @@ import { } from '../engine/helpers'; import { validateMutationPayload } from '../engine/validation'; -export const resolveByFind = (entity, parentConnectionCollector) => { +export const resolveByFind = (entity, parentConnectionCollector?: any) => { const storageType = entity.storageType; - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; return async (source, args, context, info) => { const parentConnection = parentConnectionCollector ? parentConnectionCollector({ source, args, context, info }) : null; - validateConnectionArgs(source, args, context, info); + // validateConnectionArgs(source, args, context, info); + validateConnectionArgs(source, args); forceSortByUnique(args.orderBy, entity); if (entity.preProcessor) { @@ -129,9 +131,9 @@ export const resolveByFind = (entity, parentConnectionCollector) => { export const resolveByFindOne = (entity, idCollector) => { const storageType = entity.storageType; - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; - return async (source, args, context, info) => { + return async (source: any, args: any, context?: object, info?: object) => { const id = idCollector({ source, args, context }); if (id === null || typeof id === 'undefined') { @@ -168,7 +170,7 @@ export const getNestedPayloadResolver = ( storageType, path = [], ) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; return async (source, args, context, info) => { const resultPayload = {}; @@ -298,7 +300,8 @@ export const getMutationResolver = ( idResolver, ) => { const storageType = entity.storageType; - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; + const nestedPayloadResolver = getNestedPayloadResolver( entity, entityMutation.attributes, @@ -310,7 +313,7 @@ export const getMutationResolver = ( entity, entityMutation, args.input[typeName], - context, + // context, ); if (nested) { @@ -369,10 +372,12 @@ export const getMutationResolver = ( if (entityMutation.type !== MUTATION_TYPE_DELETE) { // // this function might be wrong when we look serializeValues args + // unless we add typeName ? args.input[typeName] = serializeValues( entity, entityMutation, args.input[typeName], + typeName, context, ); } diff --git a/src/graphqlProtocol/sort.js b/src/graphqlProtocol/sort.ts similarity index 94% rename from src/graphqlProtocol/sort.js rename to src/graphqlProtocol/sort.ts index d7e4b997..6854ef85 100644 --- a/src/graphqlProtocol/sort.js +++ b/src/graphqlProtocol/sort.ts @@ -1,11 +1,12 @@ import { GraphQLEnumType, GraphQLList } from 'graphql'; import * as _ from 'lodash'; import { ProtocolGraphQL } from './ProtocolGraphQL'; +import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; import { isEntity } from '../engine/entity/Entity'; import { isShadowEntity } from '../engine/entity/ShadowEntity'; export const generateSortInput = entity => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const storageType = entity.storageType; const sortNames = {}; diff --git a/src/graphqlProtocol/util.spec.js b/src/graphqlProtocol/util.spec.ts similarity index 100% rename from src/graphqlProtocol/util.spec.js rename to src/graphqlProtocol/util.spec.ts diff --git a/src/graphqlProtocol/util.js b/src/graphqlProtocol/util.ts similarity index 100% rename from src/graphqlProtocol/util.js rename to src/graphqlProtocol/util.ts From 3cd3039a23ba9ccba814b3dbc4b0c7030a8e457f Mon Sep 17 00:00:00 2001 From: getlarge Date: Thu, 2 Apr 2020 21:07:30 +0200 Subject: [PATCH 07/13] add git repository url ; add node types --- package.json | 5 +++++ yarn.lock | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/package.json b/package.json index 563ea6a8..f6b86547 100644 --- a/package.json +++ b/package.json @@ -54,11 +54,16 @@ ], "author": "Chris Kalmar ", "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/chriskalmar/shyft" + }, "devDependencies": { "@babel/core": "7.8.7", "@babel/preset-env": "7.8.7", "@types/jest": "25.1.4", "@types/lodash": "4.14.149", + "@types/node": "^12.12.31", "@typescript-eslint/eslint-plugin": "2.23.0", "@typescript-eslint/parser": "2.23.0", "babel-jest": "25.1.0", diff --git a/yarn.lock b/yarn.lock index cb5f4291..7a2e693a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1229,6 +1229,11 @@ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.149.tgz#1342d63d948c6062838fbf961012f74d4e638440" integrity sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ== +"@types/node@^12.12.31": + version "12.12.31" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.31.tgz#d6b4f9645fee17f11319b508fb1001797425da51" + integrity sha512-T+wnJno8uh27G9c+1T+a1/WYCHzLeDqtsGJkoEdSp2X8RTh3oOCZQcUnjAx90CS8cmmADX51O0FI/tu9s0yssg== + "@types/parse-json@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" From 7f94a5e96b20a8ab390d0b88d621b2ce56e4f41c Mon Sep 17 00:00:00 2001 From: getlarge Date: Thu, 2 Apr 2020 21:13:57 +0200 Subject: [PATCH 08/13] update test snapshots --- .../__snapshots__/{action.spec.js.snap => action.spec.ts.snap} | 0 .../{dataTypes.spec.js.snap => dataTypes.spec.ts.snap} | 0 .../__snapshots__/{filter.spec.js.snap => filter.spec.ts.snap} | 0 .../{generator.spec.js.snap => generator.spec.ts.snap} | 0 .../__snapshots__/{io.spec.js.snap => io.spec.ts.snap} | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename src/graphqlProtocol/__snapshots__/{action.spec.js.snap => action.spec.ts.snap} (100%) rename src/graphqlProtocol/__snapshots__/{dataTypes.spec.js.snap => dataTypes.spec.ts.snap} (100%) rename src/graphqlProtocol/__snapshots__/{filter.spec.js.snap => filter.spec.ts.snap} (100%) rename src/graphqlProtocol/__snapshots__/{generator.spec.js.snap => generator.spec.ts.snap} (100%) rename src/graphqlProtocol/__snapshots__/{io.spec.js.snap => io.spec.ts.snap} (100%) diff --git a/src/graphqlProtocol/__snapshots__/action.spec.js.snap b/src/graphqlProtocol/__snapshots__/action.spec.ts.snap similarity index 100% rename from src/graphqlProtocol/__snapshots__/action.spec.js.snap rename to src/graphqlProtocol/__snapshots__/action.spec.ts.snap diff --git a/src/graphqlProtocol/__snapshots__/dataTypes.spec.js.snap b/src/graphqlProtocol/__snapshots__/dataTypes.spec.ts.snap similarity index 100% rename from src/graphqlProtocol/__snapshots__/dataTypes.spec.js.snap rename to src/graphqlProtocol/__snapshots__/dataTypes.spec.ts.snap diff --git a/src/graphqlProtocol/__snapshots__/filter.spec.js.snap b/src/graphqlProtocol/__snapshots__/filter.spec.ts.snap similarity index 100% rename from src/graphqlProtocol/__snapshots__/filter.spec.js.snap rename to src/graphqlProtocol/__snapshots__/filter.spec.ts.snap diff --git a/src/graphqlProtocol/__snapshots__/generator.spec.js.snap b/src/graphqlProtocol/__snapshots__/generator.spec.ts.snap similarity index 100% rename from src/graphqlProtocol/__snapshots__/generator.spec.js.snap rename to src/graphqlProtocol/__snapshots__/generator.spec.ts.snap diff --git a/src/graphqlProtocol/__snapshots__/io.spec.js.snap b/src/graphqlProtocol/__snapshots__/io.spec.ts.snap similarity index 100% rename from src/graphqlProtocol/__snapshots__/io.spec.js.snap rename to src/graphqlProtocol/__snapshots__/io.spec.ts.snap From 21957203d3a0828c2fa6459093b2f1b612ba5097 Mon Sep 17 00:00:00 2001 From: getlarge Date: Thu, 2 Apr 2020 21:07:07 +0200 Subject: [PATCH 09/13] convert to Typescript grapqlProtocol files ; fix /add engine types --- src/engine/attribute/Attribute.ts | 3 +- src/engine/configuration/Configuration.ts | 8 +- src/engine/cursor.spec.ts | 80 +++++++++++-------- src/engine/datatype/DataType.spec.ts | 6 +- src/engine/datatype/DataType.ts | 4 +- src/engine/datatype/DataTypeEnum.spec.ts | 42 +++++----- src/engine/datatype/DataTypeState.spec.ts | 26 +++--- src/engine/datatype/DataTypeUser.spec.ts | 2 + src/engine/datatype/ListDataType.spec.ts | 12 +-- src/engine/datatype/ListDataType.ts | 3 +- src/engine/datatype/ObjectDataType.spec.ts | 48 +++++------ src/engine/datatype/ObjectDataType.ts | 3 +- src/engine/protocol/ProtocolConfiguration.ts | 2 + src/engine/protocol/ProtocolType.ts | 6 +- src/engine/storage/StorageConfiguration.ts | 2 + ...{ProtocolGraphQL.js => ProtocolGraphQL.ts} | 25 +++--- ...ion.js => ProtocolGraphQLConfiguration.ts} | 22 ++--- .../{action.spec.js => action.spec.ts} | 0 src/graphqlProtocol/action.ts | 3 +- .../{connection.js => connection.ts} | 50 ++++++++---- .../{dataTypes.spec.js => dataTypes.spec.ts} | 60 +++++++++----- .../{dataTypes.js => dataTypes.ts} | 0 .../{filter.spec.js => filter.spec.ts} | 0 src/graphqlProtocol/filter.ts | 16 ++-- .../{generator.spec.js => generator.spec.ts} | 0 .../{generator.js => generator.ts} | 64 +++++++++------ .../{graphRegistry.js => graphRegistry.ts} | 0 src/graphqlProtocol/{helper.js => helper.ts} | 8 +- .../{io.spec.js => io.spec.ts} | 16 +++- src/graphqlProtocol/io.ts | 37 +++++---- .../{mutation.js => mutation.ts} | 69 +++++++--------- ...nstants.js => protocolGraphqlConstants.ts} | 0 src/graphqlProtocol/{query.js => query.ts} | 11 +-- .../{resolver.js => resolver.ts} | 21 +++-- src/graphqlProtocol/{sort.js => sort.ts} | 3 +- .../{util.spec.js => util.spec.ts} | 0 src/graphqlProtocol/{util.js => util.ts} | 0 37 files changed, 383 insertions(+), 269 deletions(-) rename src/graphqlProtocol/{ProtocolGraphQL.js => ProtocolGraphQL.ts} (97%) rename src/graphqlProtocol/{ProtocolGraphQLConfiguration.js => ProtocolGraphQLConfiguration.ts} (93%) rename src/graphqlProtocol/{action.spec.js => action.spec.ts} (100%) rename src/graphqlProtocol/{connection.js => connection.ts} (89%) rename src/graphqlProtocol/{dataTypes.spec.js => dataTypes.spec.ts} (55%) rename src/graphqlProtocol/{dataTypes.js => dataTypes.ts} (100%) rename src/graphqlProtocol/{filter.spec.js => filter.spec.ts} (100%) rename src/graphqlProtocol/{generator.spec.js => generator.spec.ts} (100%) rename src/graphqlProtocol/{generator.js => generator.ts} (88%) rename src/graphqlProtocol/{graphRegistry.js => graphRegistry.ts} (100%) rename src/graphqlProtocol/{helper.js => helper.ts} (92%) rename src/graphqlProtocol/{io.spec.js => io.spec.ts} (92%) rename src/graphqlProtocol/{mutation.js => mutation.ts} (93%) rename src/graphqlProtocol/{protocolGraphqlConstants.js => protocolGraphqlConstants.ts} (100%) rename src/graphqlProtocol/{query.js => query.ts} (93%) rename src/graphqlProtocol/{resolver.js => resolver.ts} (95%) rename src/graphqlProtocol/{sort.js => sort.ts} (94%) rename src/graphqlProtocol/{util.spec.js => util.spec.ts} (100%) rename src/graphqlProtocol/{util.js => util.ts} (100%) diff --git a/src/engine/attribute/Attribute.ts b/src/engine/attribute/Attribute.ts index 2d81debf..7f37ca8f 100644 --- a/src/engine/attribute/Attribute.ts +++ b/src/engine/attribute/Attribute.ts @@ -115,7 +115,8 @@ export type Attribute = AttributeBase & { /** * name of the attribute */ - name: string; + // name: string; + name?: string; /** * map of target attributes when referencing another entity diff --git a/src/engine/configuration/Configuration.ts b/src/engine/configuration/Configuration.ts index eeaa4ec7..6d49af02 100644 --- a/src/engine/configuration/Configuration.ts +++ b/src/engine/configuration/Configuration.ts @@ -49,7 +49,7 @@ export class Configuration { } } - setLanguages(languages): void { + setLanguages(languages: string[]): void { passOrThrow( isArray(languages, true), () => 'Configuration.setLanguages() expects a list of language iso codes', @@ -79,7 +79,7 @@ export class Configuration { return this.getLanguages()[0]; } - setSchema(schema): void { + setSchema(schema: Schema): void { passOrThrow(isSchema(schema), () => 'Configuration expects a valid schema'); this.schema = schema; @@ -91,7 +91,7 @@ export class Configuration { return this.schema; } - setProtocolConfiguration(protocolConfiguration): void { + setProtocolConfiguration(protocolConfiguration: ProtocolConfiguration): void { passOrThrow( isProtocolConfiguration(protocolConfiguration), () => 'Configuration expects a valid protocolConfiguration', @@ -111,7 +111,7 @@ export class Configuration { return this.protocolConfiguration; } - setStorageConfiguration(storageConfiguration): void { + setStorageConfiguration(storageConfiguration: StorageConfiguration): void { passOrThrow( isStorageConfiguration(storageConfiguration), () => 'Configuration expects a valid storageConfiguration', diff --git a/src/engine/cursor.spec.ts b/src/engine/cursor.spec.ts index d9672de5..1ffe635b 100644 --- a/src/engine/cursor.spec.ts +++ b/src/engine/cursor.spec.ts @@ -35,15 +35,15 @@ describe('cursor', () => { indexes: [ new Index({ type: INDEX_UNIQUE, - attributes: [ 'loginName' ], + attributes: ['loginName'], }), new Index({ type: INDEX_UNIQUE, - attributes: [ 'firstName', 'lastName' ], + attributes: ['firstName', 'lastName'], }), new Index({ type: INDEX_UNIQUE, - attributes: [ 'email' ], + attributes: ['email'], }), ], }); @@ -58,7 +58,7 @@ describe('cursor', () => { it('should throw if incompatible cursor provided', () => { function fn() { - processCursor({}, { a: 'b' }); + processCursor({} as Entity, { a: 'b' as any }); } expect(fn).toThrowErrorMatchingSnapshot(); @@ -66,15 +66,15 @@ describe('cursor', () => { it('should throw if cursor is malformed', () => { function fn1() { - processCursor(SomeEntity, { SomeEntity: [ 'b' ] }, []); + processCursor(SomeEntity, { SomeEntity: ['b' as any] }, []); } function fn2() { - processCursor(SomeEntity, { SomeEntity: [ [ {}, {}, {} ] ] }, []); + processCursor(SomeEntity, { SomeEntity: [[{}, {}, {}] as any] }, []); } function fn3() { - processCursor(SomeEntity, { SomeEntity: [ {} ] }, []); + processCursor(SomeEntity, { SomeEntity: [{} as any] }, []); } expect(fn1).toThrowErrorMatchingSnapshot(); @@ -87,7 +87,7 @@ describe('cursor', () => { processCursor( SomeEntity, { - SomeEntity: [ [ 'iDontKnow', 123 ] ], + SomeEntity: [['iDontKnow', 123]], }, [], ); @@ -99,7 +99,7 @@ describe('cursor', () => { it('should throw if an attribute is used which the data set is not sorted by', () => { function fn1() { processCursor(SomeEntity, { - SomeEntity: [ [ 'loginName', 123 ] ], + SomeEntity: [['loginName', 123]], }); } @@ -107,7 +107,7 @@ describe('cursor', () => { processCursor( SomeEntity, { - SomeEntity: [ [ 'loginName', 123 ] ], + SomeEntity: [['loginName', 123]], }, [ { @@ -122,7 +122,10 @@ describe('cursor', () => { processCursor( SomeEntity, { - SomeEntity: [ [ 'loginName', 123 ], [ 'email', 123 ] ], + SomeEntity: [ + ['loginName', 123], + ['email', 123], + ], }, [ { @@ -143,7 +146,7 @@ describe('cursor', () => { processCursor( SomeEntity, { - SomeEntity: [ [ 'firstName', 'John' ] ], + SomeEntity: [['firstName', 'John']], }, [ { @@ -158,7 +161,10 @@ describe('cursor', () => { processCursor( SomeEntity, { - SomeEntity: [ [ 'firstName', 'John' ], [ 'lastName', 'Snow' ] ], + SomeEntity: [ + ['firstName', 'John'], + ['lastName', 'Snow'], + ], }, [ { @@ -182,7 +188,7 @@ describe('cursor', () => { const cursor1 = processCursor( SomeEntity, { - SomeEntity: [ [ 'loginName', 'user1' ] ], + SomeEntity: [['loginName', 'user1']], }, [ { @@ -201,7 +207,7 @@ describe('cursor', () => { const cursor2 = processCursor( SomeEntity, { - SomeEntity: [ [ 'loginName', 123 ] ], + SomeEntity: [['loginName', 123]], }, [ { @@ -221,8 +227,8 @@ describe('cursor', () => { SomeEntity, { SomeEntity: [ - [ 'loginName', 'user1' ], - [ 'email', 'user1@example.com' ], + ['loginName', 'user1'], + ['email', 'user1@example.com'], ], }, [ @@ -250,7 +256,10 @@ describe('cursor', () => { it('when using attributes that are not all defined as unique', () => { const row1: CursorType = { - SomeEntity: [ [ 'firstName', 'John' ], [ 'id', 1123 ] ], + SomeEntity: [ + ['firstName', 'John'], + ['id', 1123], + ], }; const cursor1 = processCursor(SomeEntity, row1, [ @@ -347,9 +356,9 @@ describe('cursor', () => { const row2: CursorType = { SomeEntity: [ - [ 'firstName', 'John' ], - [ 'lastName', 'Snow' ], - [ 'id', 1123 ], + ['firstName', 'John'], + ['lastName', 'Snow'], + ['id', 1123], ], }; @@ -409,10 +418,10 @@ describe('cursor', () => { const row3: CursorType = { SomeEntity: [ - [ 'firstName', 'John' ], - [ 'email', 'john@example.com' ], - [ 'lastName', 'Snow' ], - [ 'id', 1123 ], + ['firstName', 'John'], + ['email', 'john@example.com'], + ['lastName', 'Snow'], + ['id', 1123], ], }; @@ -460,7 +469,7 @@ describe('cursor', () => { const cursor0 = processCursor( SomeEntity, { - SomeEntity: [ [ 'loginName', 123 ] ], + SomeEntity: [['loginName', 123]], }, [ { @@ -478,7 +487,10 @@ describe('cursor', () => { }; const row1: CursorType = { - SomeEntity: [ [ 'firstName', 'John' ], [ 'id', 1123 ] ], + SomeEntity: [ + ['firstName', 'John'], + ['id', 1123], + ], }; const cursor1 = processCursor( @@ -595,9 +607,9 @@ describe('cursor', () => { const row2: CursorType = { SomeEntity: [ - [ 'firstName', 'John' ], - [ 'lastName', 'Snow' ], - [ 'id', 1123 ], + ['firstName', 'John'], + ['lastName', 'Snow'], + ['id', 1123], ], }; @@ -667,10 +679,10 @@ describe('cursor', () => { const row3: CursorType = { SomeEntity: [ - [ 'firstName', 'John' ], - [ 'email', 'john@example.com' ], - [ 'lastName', 'Snow' ], - [ 'id', 1123 ], + ['firstName', 'John'], + ['email', 'john@example.com'], + ['lastName', 'Snow'], + ['id', 1123], ], }; diff --git a/src/engine/datatype/DataType.spec.ts b/src/engine/datatype/DataType.spec.ts index b4ad2784..6ef0bdc9 100644 --- a/src/engine/datatype/DataType.spec.ts +++ b/src/engine/datatype/DataType.spec.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-empty-function */ + import { DataType, DataTypeSetup, isDataType } from './DataType'; import { passOrThrow } from '../util'; @@ -16,9 +18,9 @@ describe('DataType', () => { it('should have a description', () => { function fn() { // eslint-disable-next-line no-new - new DataType({ + new DataType({ name: 'example', - }); + } as DataTypeSetup); } expect(fn).toThrowErrorMatchingSnapshot(); diff --git a/src/engine/datatype/DataType.ts b/src/engine/datatype/DataType.ts index 2607a396..70423780 100644 --- a/src/engine/datatype/DataType.ts +++ b/src/engine/datatype/DataType.ts @@ -2,8 +2,8 @@ import { passOrThrow, isFunction } from '../util'; import { ComplexDataType } from './ComplexDataType'; export type DataTypeSetup = { - name: string; - description: string; + name?: string; + description?: string; mock?: () => any; validate?: () => any; enforceRequired?: boolean; diff --git a/src/engine/datatype/DataTypeEnum.spec.ts b/src/engine/datatype/DataTypeEnum.spec.ts index 2abe2d15..d3258878 100644 --- a/src/engine/datatype/DataTypeEnum.spec.ts +++ b/src/engine/datatype/DataTypeEnum.spec.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-empty-function */ + import { DataTypeEnum, DataTypeEnumSetupType, @@ -12,19 +14,19 @@ describe('DataTypeEnum', () => { fn = () => { // eslint-disable-next-line no-new - new DataTypeEnum({ + new DataTypeEnum({ name: 'something', - }); + } as DataTypeEnumSetupType); }; expect(fn).toThrowErrorMatchingSnapshot(); fn = () => { // eslint-disable-next-line no-new - new DataTypeEnum({ + new DataTypeEnum({ name: 'something', values: {}, - }); + } as DataTypeEnumSetupType); }; expect(fn).toThrowErrorMatchingSnapshot(); @@ -35,38 +37,38 @@ describe('DataTypeEnum', () => { fn = () => { // eslint-disable-next-line no-new - new DataTypeEnum({ + new DataTypeEnum({ name: 'lorem', values: { '7': 8, }, - }); + } as DataTypeEnumSetupType); }; expect(fn).toThrowErrorMatchingSnapshot(); fn = () => { // eslint-disable-next-line no-new - new DataTypeEnum({ + new DataTypeEnum({ values: { ' abc ': 123, }, name: 'test', - }); + } as DataTypeEnumSetupType); }; expect(fn).toThrowErrorMatchingSnapshot(); fn = () => { // eslint-disable-next-line no-new - new DataTypeEnum({ + new DataTypeEnum({ name: 'another', values: { abc: 1, def: 2, 'hello-there': 3, }, - }); + } as DataTypeEnumSetupType); }; expect(fn).toThrowErrorMatchingSnapshot(); @@ -75,11 +77,11 @@ describe('DataTypeEnum', () => { it('should have a name', () => { function fn() { // eslint-disable-next-line no-new - new DataTypeEnum({ + new DataTypeEnum({ values: { item: 1, }, - }); + } as any); } expect(fn).toThrowErrorMatchingSnapshot(); @@ -99,14 +101,14 @@ describe('DataTypeEnum', () => { }); it('should have a fallback description', () => { - const dataType = new DataTypeEnum({ + const dataType = new DataTypeEnum({ name: 'example', values: { ACTION: 1, COMEDY: 2, DRAMA: 3, }, - }); + } as DataTypeEnumSetupType); expect(dataType.description).toBe('Enumeration set: ACTION, COMEDY, DRAMA'); }); @@ -126,10 +128,10 @@ describe('DataTypeEnum', () => { uniqueIds.push(valueId); }); - const dataType = new DataTypeEnum({ + const dataType = new DataTypeEnum({ name: 'example', values, - }); + } as DataTypeEnumSetupType); const randomValue1 = dataType.mock(); const randomValue2 = dataType.mock(); @@ -142,23 +144,23 @@ describe('DataTypeEnum', () => { describe('isDataTypeEnum', () => { it('should recognize objects of type DataTypeEnum', () => { - const enum1 = new DataTypeEnum({ + const enum1 = new DataTypeEnum({ name: 'enum1', values: { ACTION: 1, COMEDY: 2, DRAMA: 3, }, - }); + } as DataTypeEnumSetupType); - const enum2 = new DataTypeEnum({ + const enum2 = new DataTypeEnum({ name: 'enum2', values: { APPLE: 10, PEAR: 20, CHERRY: 30, }, - }); + } as DataTypeEnumSetupType); function fn() { passOrThrow( diff --git a/src/engine/datatype/DataTypeState.spec.ts b/src/engine/datatype/DataTypeState.spec.ts index cf0042e8..693e68b0 100644 --- a/src/engine/datatype/DataTypeState.spec.ts +++ b/src/engine/datatype/DataTypeState.spec.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-empty-function */ + import { DataTypeState, DataTypeStateSetupType, @@ -12,19 +14,19 @@ describe('DataTypeState', () => { fn = () => { // eslint-disable-next-line no-new - new DataTypeState({ + new DataTypeState({ name: 'something', - }); + } as DataTypeStateSetupType); }; expect(fn).toThrowErrorMatchingSnapshot(); fn = () => { // eslint-disable-next-line no-new - new DataTypeState({ + new DataTypeState({ name: 'something', states: {}, - }); + } as DataTypeStateSetupType); }; expect(fn).toThrowErrorMatchingSnapshot(); @@ -35,38 +37,38 @@ describe('DataTypeState', () => { fn = () => { // eslint-disable-next-line no-new - new DataTypeState({ + new DataTypeState({ name: 'progress', states: { '6': 1, }, - }); + } as DataTypeStateSetupType); }; expect(fn).toThrowErrorMatchingSnapshot(); fn = () => { // eslint-disable-next-line no-new - new DataTypeState({ + new DataTypeState({ states: { ' abc ': 123, }, name: 'test', - }); + } as DataTypeStateSetupType); }; expect(fn).toThrowErrorMatchingSnapshot(); fn = () => { // eslint-disable-next-line no-new - new DataTypeState({ + new DataTypeState({ name: 'another', states: { abc: 1, def: 2, 'hello-there': 3, }, - }); + } as DataTypeStateSetupType); }; expect(fn).toThrowErrorMatchingSnapshot(); @@ -75,11 +77,11 @@ describe('DataTypeState', () => { it('should have a name', () => { function fn() { // eslint-disable-next-line no-new - new DataTypeState({ + new DataTypeState({ states: { item: 1, }, - }); + } as any); } expect(fn).toThrowErrorMatchingSnapshot(); diff --git a/src/engine/datatype/DataTypeUser.spec.ts b/src/engine/datatype/DataTypeUser.spec.ts index a2245350..0dfdbdd9 100644 --- a/src/engine/datatype/DataTypeUser.spec.ts +++ b/src/engine/datatype/DataTypeUser.spec.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-empty-function */ + import { DataTypeUser, isDataTypeUser } from './DataTypeUser'; import { passOrThrow } from '../util'; diff --git a/src/engine/datatype/ListDataType.spec.ts b/src/engine/datatype/ListDataType.spec.ts index 37c232ad..7d89de74 100644 --- a/src/engine/datatype/ListDataType.spec.ts +++ b/src/engine/datatype/ListDataType.spec.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-empty-function */ + import { ListDataType, ListDataTypeSetupType, @@ -20,9 +22,9 @@ describe('ListDataType', () => { it('should have a description', () => { function fn() { // eslint-disable-next-line no-new - new ListDataType({ + new ListDataType({ name: 'example', - }); + } as ListDataTypeSetupType); } expect(fn).toThrowErrorMatchingSnapshot(); @@ -31,10 +33,10 @@ describe('ListDataType', () => { it('should have an item type', () => { function fn() { // eslint-disable-next-line no-new - new ListDataType({ + new ListDataType({ name: 'Example', description: 'Just some description', - }); + } as ListDataTypeSetupType); } expect(fn).toThrowErrorMatchingSnapshot(); @@ -89,7 +91,7 @@ describe('ListDataType', () => { new ListDataType({ name: 'Example', description: 'Just some description', - itemType: [ 2, 7, 13 ], + itemType: [2, 7, 13], }); } diff --git a/src/engine/datatype/ListDataType.ts b/src/engine/datatype/ListDataType.ts index 2d1569d9..5c999bea 100644 --- a/src/engine/datatype/ListDataType.ts +++ b/src/engine/datatype/ListDataType.ts @@ -140,7 +140,8 @@ export const isListDataType = (obj: any): boolean => { }; export const buildListDataType = (obj: { - itemType: Entity | ComplexDataType | DataTypeFunction; + itemType: any; + // itemType: Entity | ComplexDataType | DataTypeFunction; }): Function => { return ({ name, description }): ListDataType => new ListDataType({ diff --git a/src/engine/datatype/ObjectDataType.spec.ts b/src/engine/datatype/ObjectDataType.spec.ts index 93325afd..9d8fd425 100644 --- a/src/engine/datatype/ObjectDataType.spec.ts +++ b/src/engine/datatype/ObjectDataType.spec.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-empty-function */ + import { ObjectDataType, ObjectDataTypeSetupType, @@ -20,9 +22,9 @@ describe('ObjectDataType', () => { it('should have a description', () => { function fn() { // eslint-disable-next-line no-new - new ObjectDataType({ + new ObjectDataType({ name: 'example', - }); + } as ObjectDataTypeSetupType); } expect(fn).toThrowErrorMatchingSnapshot(); @@ -31,21 +33,21 @@ describe('ObjectDataType', () => { it('should have a map of attributes', () => { function fn() { // eslint-disable-next-line no-new - new ObjectDataType({ + new ObjectDataType({ name: 'Example', description: 'Just some description', - }); + } as ObjectDataTypeSetupType); } expect(fn).toThrowErrorMatchingSnapshot(); }); it("should return it's name", () => { - const objectDataType = new ObjectDataType({ + const objectDataType = new ObjectDataType({ name: 'someObjectDataTypeName', description: 'Just some description', attributes: {}, - }); + } as ObjectDataTypeSetupType); expect(objectDataType.name).toBe('someObjectDataTypeName'); expect(String(objectDataType)).toBe('someObjectDataTypeName'); @@ -54,11 +56,11 @@ describe('ObjectDataType', () => { it('should accept only maps or functions as attributes definition', () => { function fn() { // eslint-disable-next-line no-new - new ObjectDataType({ + new ObjectDataType({ name: 'Example', description: 'Just some description', - attributes: [ 2, 7, 13 ], - }); + attributes: [2, 7, 13], + } as any); } expect(fn).toThrowErrorMatchingSnapshot(); @@ -66,13 +68,13 @@ describe('ObjectDataType', () => { it('should reject non-map results of attribute definition functions', () => { function fn() { - const objectDataType = new ObjectDataType({ + const objectDataType = new ObjectDataType({ name: 'Example', description: 'Just some description', attributes: () => { - return [ 2, 7, 13 ]; + return [2, 7, 13] as any; }, - }); + } as ObjectDataTypeSetupType); objectDataType.getAttributes(); } @@ -82,11 +84,11 @@ describe('ObjectDataType', () => { it('should reject empty attribute maps', () => { function fn() { - const objectDataType = new ObjectDataType({ + const objectDataType = new ObjectDataType({ name: 'Example', description: 'Just some description', attributes: {}, - }); + } as ObjectDataTypeSetupType); objectDataType.getAttributes(); } @@ -100,9 +102,9 @@ describe('ObjectDataType', () => { name: 'Example', description: 'Just some description', attributes: { - name: { + name: { type: DataTypeString, - }, + } as any, }, }); @@ -119,10 +121,10 @@ describe('ObjectDataType', () => { description: 'Just some description', attributes: { name: { - type: {}, + type: {} as any, description: 'Just some description', }, - }, + } as any, }); objectDataType.getAttributes(); @@ -140,8 +142,8 @@ describe('ObjectDataType', () => { name: { type: DataTypeString, description: 'Just some description', - resolve: 123456, - }, + resolve: 123456 as any, + } as any, }, }); @@ -160,8 +162,8 @@ describe('ObjectDataType', () => { name: { type: DataTypeString, description: 'Just some description', - defaultValue: 123456, - }, + defaultValue: 123456 as any, + } as any, }, }); @@ -226,7 +228,7 @@ describe('ObjectDataType', () => { expect(attributes.id.type).toBe(DataTypeID); expect(attributes.name.type).toBe(DataTypeString); - const attributesNested = (attributes.nested.type).getAttributes(); + const attributesNested = (attributes.nested.type as Entity).getAttributes(); expect(attributesNested.randomInput.type).toBe(DataTypeString); }); diff --git a/src/engine/datatype/ObjectDataType.ts b/src/engine/datatype/ObjectDataType.ts index b27490dc..700f1d27 100644 --- a/src/engine/datatype/ObjectDataType.ts +++ b/src/engine/datatype/ObjectDataType.ts @@ -167,7 +167,8 @@ export const isObjectDataType = (obj: any): boolean => { }; export const buildObjectDataType = (obj: { - attributes: AttributesMap | AttributesMapGenerator; + // attributes: AttributesMap | AttributesMapGenerator | AttributeBase; + attributes: any; }): Function => { return ({ name, description }): ObjectDataType => new ObjectDataType({ diff --git a/src/engine/protocol/ProtocolConfiguration.ts b/src/engine/protocol/ProtocolConfiguration.ts index f71153c1..342662c0 100644 --- a/src/engine/protocol/ProtocolConfiguration.ts +++ b/src/engine/protocol/ProtocolConfiguration.ts @@ -1,4 +1,5 @@ import { passOrThrow, isString, isArray } from '../util'; +import { Configuration } from '../configuration/Configuration'; export type ProtocolConfigurationSetup = { features?: string[]; @@ -6,6 +7,7 @@ export type ProtocolConfigurationSetup = { export class ProtocolConfiguration { features: { [key: string]: boolean }; + getParentConfiguration: () => Configuration; constructor( setup: ProtocolConfigurationSetup = {} as ProtocolConfigurationSetup, diff --git a/src/engine/protocol/ProtocolType.ts b/src/engine/protocol/ProtocolType.ts index b938db4a..a6c221e2 100644 --- a/src/engine/protocol/ProtocolType.ts +++ b/src/engine/protocol/ProtocolType.ts @@ -21,6 +21,7 @@ export type ProtocolTypeSetup = { // asInput?: boolean; // } +// how to properly define this type ? export type ProtocolDataType = { name: string | Function; }; @@ -94,7 +95,8 @@ export class ProtocolType { addDynamicDataTypeMap( schemaDataTypeDetector: Function, - protocolDataType: ProtocolType, + protocolDataType: any, + // protocolDataType: ProtocolType, ): void { passOrThrow( isFunction(schemaDataTypeDetector), @@ -122,7 +124,7 @@ export class ProtocolType { schemaDataType: DataType | DataTypeFunction, sourceName?: string, asInput?: boolean, - ): ProtocolDataType { + ): any { const foundDynamicDataType = this._dynamicDataTypeMap.find( ({ schemaDataTypeDetector }) => schemaDataTypeDetector(schemaDataType), ); diff --git a/src/engine/storage/StorageConfiguration.ts b/src/engine/storage/StorageConfiguration.ts index af13a6cb..e1ee6566 100644 --- a/src/engine/storage/StorageConfiguration.ts +++ b/src/engine/storage/StorageConfiguration.ts @@ -1,4 +1,5 @@ import { passOrThrow } from '../util'; +import { Configuration } from '../configuration/Configuration'; export type StorageConfigurationSetup = { // todo improve typings ? @@ -13,6 +14,7 @@ export class StorageConfiguration { storageInstance: any; storageModels: any; connectionConfig: any; + getParentConfiguration: () => Configuration; constructor( setup: StorageConfigurationSetup = {} as StorageConfigurationSetup, diff --git a/src/graphqlProtocol/ProtocolGraphQL.js b/src/graphqlProtocol/ProtocolGraphQL.ts similarity index 97% rename from src/graphqlProtocol/ProtocolGraphQL.js rename to src/graphqlProtocol/ProtocolGraphQL.ts index 2f0c5dec..19985913 100644 --- a/src/graphqlProtocol/ProtocolGraphQL.js +++ b/src/graphqlProtocol/ProtocolGraphQL.ts @@ -1,3 +1,15 @@ +import { + GraphQLScalarType, + GraphQLID, + GraphQLInt, + GraphQLInputObjectType, + GraphQLObjectType, + GraphQLFloat, + GraphQLString, + GraphQLBoolean, + GraphQLEnumType, +} from 'graphql'; + import { ProtocolType } from '../engine/protocol/ProtocolType'; import { DataTypeID, @@ -16,15 +28,6 @@ import { DataTypeI18n, } from '../engine/datatype/dataTypes'; -import { - GraphQLScalarType, - GraphQLID, - GraphQLInt, - GraphQLFloat, - GraphQLString, - GraphQLBoolean, - GraphQLEnumType, -} from 'graphql'; import { isDataTypeState } from '../engine/datatype/DataTypeState'; import { isDataTypeEnum } from '../engine/datatype/DataTypeEnum'; import { isObjectDataType } from '../engine/datatype/ObjectDataType'; @@ -182,7 +185,7 @@ ProtocolGraphQL.addDynamicDataTypeMap( const dataInputType = generateDataInput( `${sourceName}-${name}`, params, - ); + ) as GraphQLInputObjectType; dataTypesRegistry.object[ uniqueName ] = dataInputType.getFields().wrapped.type; @@ -196,7 +199,7 @@ ProtocolGraphQL.addDynamicDataTypeMap( `${sourceName}-${name}`, params, graphRegistry, - ); + ) as GraphQLObjectType; dataTypesRegistry.object[ uniqueName ] = dataOutputType.getFields().wrapped.type; diff --git a/src/graphqlProtocol/ProtocolGraphQLConfiguration.js b/src/graphqlProtocol/ProtocolGraphQLConfiguration.ts similarity index 93% rename from src/graphqlProtocol/ProtocolGraphQLConfiguration.js rename to src/graphqlProtocol/ProtocolGraphQLConfiguration.ts index c0b97824..32d72a9d 100644 --- a/src/graphqlProtocol/ProtocolGraphQLConfiguration.js +++ b/src/graphqlProtocol/ProtocolGraphQLConfiguration.ts @@ -128,12 +128,12 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { ); } - generateUniquenessAttributesName(entity, attributes) { + generateUniquenessAttributesName(_entity, attributes) { return generateTypeName(attributes.join('-and-')); } generateUniquenessAttributesFieldName( - entity, + _entity, attribute, uniquenessAttributesName, ) { @@ -201,15 +201,19 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { ); } - generateInputTypeName(baseName) { + generateInputTypeName(baseName: string) { return generateTypeNamePascalCase(`${baseName}-input`); } - generateDataOutPutTypeName(baseName) { + generateDataOutPutTypeName(baseName: string) { return generateTypeNamePascalCase(`${baseName}-data-output`); } - generateNestedDataOutPutTypeName(baseName, nestedParamName, level) { + generateNestedDataOutPutTypeName( + baseName: string, + nestedParamName: string, + level?: number, + ) { const levelStr = level > 1 ? `L${level}` : ''; return generateTypeNamePascalCase( @@ -217,11 +221,11 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { ); } - generateOutPutTypeName(baseName) { + generateOutPutTypeName(baseName: string) { return generateTypeNamePascalCase(`${baseName}-output`); } - generateSortKeyName(attribute, ascending) { + generateSortKeyName(attribute: any, ascending?: boolean) { const direction = ascending ? 'ASC' : 'DESC'; return `${generateTypeNameUpperCase(attribute.name)}_${direction}`; @@ -254,12 +258,12 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { return generateTypeNamePascalCase(`${typeName}-edge`); } - generateConnectionTypeName(entity) { + generateConnectionTypeName(entity): string { const typeName = this.generateEntityTypeName(entity); return generateTypeNamePascalCase(`${typeName}-connection`); } } -export const isProtocolGraphQLConfiguration = obj => { +export const isProtocolGraphQLConfiguration = (obj: any): boolean => { return obj instanceof ProtocolGraphQLConfiguration; }; diff --git a/src/graphqlProtocol/action.spec.js b/src/graphqlProtocol/action.spec.ts similarity index 100% rename from src/graphqlProtocol/action.spec.js rename to src/graphqlProtocol/action.spec.ts diff --git a/src/graphqlProtocol/action.ts b/src/graphqlProtocol/action.ts index c4dcc530..3ff361fd 100644 --- a/src/graphqlProtocol/action.ts +++ b/src/graphqlProtocol/action.ts @@ -9,6 +9,7 @@ import { } from './io'; import { ProtocolGraphQL } from './ProtocolGraphQL'; +import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; import { isObjectDataType } from '../engine/datatype/ObjectDataType'; import { isListDataType } from '../engine/datatype/ListDataType'; import { validateActionPayload } from '../engine/validation'; @@ -122,7 +123,7 @@ export const handlePermission = async (context, action, input) => { }; export const generateActions = (graphRegistry, actionTypeFilter) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const actions = {}; diff --git a/src/graphqlProtocol/connection.js b/src/graphqlProtocol/connection.ts similarity index 89% rename from src/graphqlProtocol/connection.js rename to src/graphqlProtocol/connection.ts index e92bd1da..25d74da5 100644 --- a/src/graphqlProtocol/connection.js +++ b/src/graphqlProtocol/connection.ts @@ -5,15 +5,21 @@ import { GraphQLList, GraphQLBoolean, } from 'graphql'; +import { first, last } from 'lodash'; import { GraphQLCursor } from './dataTypes'; import { resolveByFind } from './resolver'; import { ProtocolGraphQL } from './ProtocolGraphQL'; +import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; import { generateSortInput } from './sort'; import { generateFilterInput } from './filter'; -import * as _ from 'lodash'; +// import { Entity } from '../engine/entity/Entity'; + +export type ConnectioNode = { + cursor: any; +}; export const generateConnectionArgs = (entity, graphRegistry) => { const sortInput = generateSortInput(entity); @@ -48,14 +54,22 @@ export const generateConnectionArgs = (entity, graphRegistry) => { }; }; -export const validateConnectionArgs = (source, args, context, info) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); - const maxPageSize = protocolConfiguration.getMaxPageSize( - source, - args, - context, - info, - ); +export const validateConnectionArgs = ( + _source, + args, + // _context, + // _info, +): void => { + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; + + // const maxPageSize = protocolConfiguration.getMaxPageSize( + // source, + // args, + // context, + // info, + // ); + + const maxPageSize = protocolConfiguration.getMaxPageSize(); if (args.first >= 0 && args.last >= 0) { throw new Error('`first` and `last` settings are mutual exclusive'); @@ -78,7 +92,7 @@ export const validateConnectionArgs = (source, args, context, info) => { } }; -export const forceSortByUnique = (orderBy, entity) => { +export const forceSortByUnique = (orderBy, entity): void => { const attributes = entity.getAttributes(); let foundUnique = false; @@ -124,7 +138,9 @@ const pageInfoType = new GraphQLObjectType({ }); export const generateConnectionType = config => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + // const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; + const { nodeType, entity } = config; const typeNamePluralListName = entity.graphql.typeNamePluralPascalCase; let cursor; @@ -204,10 +220,10 @@ export const buildCursor = (entityName, primaryAttributeName, args, data) => { export const connectionFromData = ( { transformedData, originalData }, entity, - source, + _source, args, context, - info, + _info, parentConnection, pageInfoFromData, ) => { @@ -233,14 +249,14 @@ export const connectionFromData = ( const edges = transformedData.map(nodeToEdge); - const firstNode = _.first(edges); - const lastNode = _.last(edges); + const firstNode: ConnectioNode = first(edges); + const lastNode: ConnectioNode = last(edges); return { edges, totalCount: async () => { const storageType = entity.storageType; - return await storageType.count(entity, args, context, parentConnection); + return storageType.count(entity, args, context, parentConnection); }, pageInfo: { startCursor: firstNode ? firstNode.cursor : null, @@ -273,7 +289,7 @@ export const generateReverseConnections = ( ) => { const schema = configuration.getSchema(); const schemaEntities = schema.getEntities(); - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const fields = {}; diff --git a/src/graphqlProtocol/dataTypes.spec.js b/src/graphqlProtocol/dataTypes.spec.ts similarity index 55% rename from src/graphqlProtocol/dataTypes.spec.js rename to src/graphqlProtocol/dataTypes.spec.ts index e82021ff..71f46039 100644 --- a/src/graphqlProtocol/dataTypes.spec.js +++ b/src/graphqlProtocol/dataTypes.spec.ts @@ -5,72 +5,94 @@ import { parseValue } from 'graphql'; describe('dataTypes', () => { it('GraphQLDateTime', () => { - const bad1 = () => GraphQLDateTime.parseLiteral(parseValue('"foo"')); + const bad1 = () => GraphQLDateTime.parseLiteral(parseValue('"foo"'), null); expect(bad1).toThrowErrorMatchingSnapshot(); const bad2 = () => - GraphQLDateTime.parseLiteral(parseValue('"2000-01-02 111:12:13+14:15"')); + GraphQLDateTime.parseLiteral( + parseValue('"2000-01-02 111:12:13+14:15"'), + null, + ); expect(bad2).toThrowErrorMatchingSnapshot('bad hour'); const bad3 = () => - GraphQLDateTime.parseLiteral(parseValue('"2000-31-02 11:12:13+14:15"')); + GraphQLDateTime.parseLiteral( + parseValue('"2000-31-02 11:12:13+14:15"'), + null, + ); expect(bad3).toThrowErrorMatchingSnapshot('bad month'); const bad4 = () => - GraphQLDateTime.parseLiteral(parseValue('"2000-01-02 11:62:13+14:15"')); + GraphQLDateTime.parseLiteral( + parseValue('"2000-01-02 11:62:13+14:15"'), + null, + ); expect(bad4).toThrowErrorMatchingSnapshot('bad minute'); const good1 = () => - GraphQLDateTime.parseLiteral(parseValue('"2000-01-02 11:12:13+14:15"')); + GraphQLDateTime.parseLiteral( + parseValue('"2000-01-02 11:12:13+14:15"'), + null, + ); expect(good1).not.toThrow(); const good2 = () => - GraphQLDateTime.parseLiteral(parseValue('"0003-01-02 21:12:13+14:15"')); + GraphQLDateTime.parseLiteral( + parseValue('"0003-01-02 21:12:13+14:15"'), + null, + ); expect(good2).not.toThrow(); }); it('GraphQLDate', () => { - const bad1 = () => GraphQLDate.parseLiteral(parseValue('"foo"')); + const bad1 = () => GraphQLDate.parseLiteral(parseValue('"foo"'), null); expect(bad1).toThrowErrorMatchingSnapshot(); - const bad2 = () => GraphQLDate.parseLiteral(parseValue('"2000-01-32"')); + const bad2 = () => + GraphQLDate.parseLiteral(parseValue('"2000-01-32"'), null); expect(bad2).toThrowErrorMatchingSnapshot('bad day'); - const bad3 = () => GraphQLDate.parseLiteral(parseValue('"2000-31-02"')); + const bad3 = () => + GraphQLDate.parseLiteral(parseValue('"2000-31-02"'), null); expect(bad3).toThrowErrorMatchingSnapshot('bad month'); - const bad4 = () => GraphQLDate.parseLiteral(parseValue('"01-02"')); + const bad4 = () => GraphQLDate.parseLiteral(parseValue('"01-02"'), null); expect(bad4).toThrowErrorMatchingSnapshot('bad date'); - const good1 = () => GraphQLDate.parseLiteral(parseValue('"2000-01-02"')); + const good1 = () => + GraphQLDate.parseLiteral(parseValue('"2000-01-02"'), null); expect(good1).not.toThrow(); - const good2 = () => GraphQLDate.parseLiteral(parseValue('"0003-01-02"')); + const good2 = () => + GraphQLDate.parseLiteral(parseValue('"0003-01-02"'), null); expect(good2).not.toThrow(); }); it('GraphQLTime', () => { - const bad1 = () => GraphQLTime.parseLiteral(parseValue('"foo"')); + const bad1 = () => GraphQLTime.parseLiteral(parseValue('"foo"'), null); expect(bad1).toThrowErrorMatchingSnapshot(); const bad2 = () => - GraphQLTime.parseLiteral(parseValue('"111:12:13+14:15"')); + GraphQLTime.parseLiteral(parseValue('"111:12:13+14:15"'), null); expect(bad2).toThrowErrorMatchingSnapshot('bad hour'); - const bad3 = () => GraphQLTime.parseLiteral(parseValue('"11:12:13+24:15"')); + const bad3 = () => + GraphQLTime.parseLiteral(parseValue('"11:12:13+24:15"'), null); expect(bad3).toThrowErrorMatchingSnapshot('bad tz hour'); - const bad4 = () => GraphQLTime.parseLiteral(parseValue('"11:62:13+14:15"')); + const bad4 = () => + GraphQLTime.parseLiteral(parseValue('"11:62:13+14:15"'), null); expect(bad4).toThrowErrorMatchingSnapshot('bad minute'); const good1 = () => - GraphQLTime.parseLiteral(parseValue('"11:12:13+14:15"')); + GraphQLTime.parseLiteral(parseValue('"11:12:13+14:15"'), null); expect(good1).not.toThrow(); - const good2 = () => GraphQLTime.parseLiteral(parseValue('"21:12:13"')); + const good2 = () => + GraphQLTime.parseLiteral(parseValue('"21:12:13"'), null); expect(good2).not.toThrow(); - const good3 = () => GraphQLTime.parseLiteral(parseValue('"21:12"')); + const good3 = () => GraphQLTime.parseLiteral(parseValue('"21:12"'), null); expect(good3).not.toThrow(); }); }); diff --git a/src/graphqlProtocol/dataTypes.js b/src/graphqlProtocol/dataTypes.ts similarity index 100% rename from src/graphqlProtocol/dataTypes.js rename to src/graphqlProtocol/dataTypes.ts diff --git a/src/graphqlProtocol/filter.spec.js b/src/graphqlProtocol/filter.spec.ts similarity index 100% rename from src/graphqlProtocol/filter.spec.js rename to src/graphqlProtocol/filter.spec.ts diff --git a/src/graphqlProtocol/filter.ts b/src/graphqlProtocol/filter.ts index 1d72ea55..95e446fc 100644 --- a/src/graphqlProtocol/filter.ts +++ b/src/graphqlProtocol/filter.ts @@ -6,14 +6,15 @@ import { } from 'graphql'; import * as _ from 'lodash'; import { ProtocolGraphQL } from './ProtocolGraphQL'; -import { isEntity } from '../engine/entity/Entity'; +import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; +import { isEntity, Entity } from '../engine/entity/Entity'; import { storageDataTypeCapabilities, storageDataTypeCapabilityType, } from '../engine/constants'; import { isComplexDataType } from '../engine/datatype/ComplexDataType'; import { isArray, isMap } from '../engine/util'; -import { isViewEntity } from '../engine/entity/ViewEntity'; +import { isViewEntity, ViewEntity } from '../engine/entity/ViewEntity'; import { isShadowEntity } from '../engine/entity/ShadowEntity'; const AND_OPERATOR = 'AND'; @@ -27,7 +28,8 @@ const DEEP_FILTER_OPERATOR = 'filter'; const PRE_FILTER_OPERATOR = 'pre_filter'; export const generateFilterInput = (entity, graphRegistry) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; + const typeNamePluralListName = entity.graphql.typeNamePluralPascalCase; const storageType = entity.storageType; @@ -226,11 +228,11 @@ const deepFilterResolver = async (entity, filter, context, path) => { }; export const transformFilterLevel = async ( - entity, + entity: Entity | ViewEntity, filters = {}, - attributes, - context, - path, + attributes: any, + context?: any, + path?: string[], ) => { const ret = {}; const hasFilter = {}; diff --git a/src/graphqlProtocol/generator.spec.js b/src/graphqlProtocol/generator.spec.ts similarity index 100% rename from src/graphqlProtocol/generator.spec.js rename to src/graphqlProtocol/generator.spec.ts diff --git a/src/graphqlProtocol/generator.js b/src/graphqlProtocol/generator.ts similarity index 88% rename from src/graphqlProtocol/generator.js rename to src/graphqlProtocol/generator.ts index e7ebf98e..8a87fac6 100644 --- a/src/graphqlProtocol/generator.js +++ b/src/graphqlProtocol/generator.ts @@ -2,6 +2,7 @@ import * as _ from 'lodash'; import { RELAY_TYPE_PROMOTER_FIELD } from './protocolGraphqlConstants'; import { graphRegistry } from './graphRegistry'; import { ProtocolGraphQL } from './ProtocolGraphQL'; +import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; import { shaper } from 'json-shaper'; @@ -40,7 +41,7 @@ export const getTypeForEntityFromGraphRegistry = entity => { // prepare models for graphql export const extendModelsForGql = entities => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; _.forEach(entities, entity => { entity.graphql = entity.graphql || {}; @@ -198,9 +199,9 @@ export const generateGraphQLSchema = configuration => { return; } - const field = { - description: attribute.description, - }; + // const field = { + // description: attribute.description, + // }; let attributeType = attribute.type; @@ -210,17 +211,26 @@ export const generateGraphQLSchema = configuration => { const primaryAttribute = targetEntity.getPrimaryAttribute(); attributeType = primaryAttribute.type; - const reference = { - description: attribute.description, - }; + // const reference = { + // description: attribute.description, + // }; const targetTypeName = targetEntity.graphql.typeName; - reference.type = graphRegistry.types[targetTypeName].type; - reference.resolve = resolveByFindOne( - targetEntity, - ({ source }) => source[attribute.gqlFieldName], - ); + // reference.type = graphRegistry.types[targetTypeName].type; + // reference.resolve = resolveByFindOne( + // targetEntity, + // ({ source }) => source[attribute.gqlFieldName], + // ); + + const reference = { + description: attribute.description, + type: graphRegistry.types[targetTypeName].type, + resolve: resolveByFindOne( + targetEntity, + ({ source }) => source[attribute.gqlFieldName], + ), + }; const referenceFieldName = protocolConfiguration.generateReferenceFieldName( targetEntity, @@ -236,16 +246,24 @@ export const generateGraphQLSchema = configuration => { ); // make it non-nullable if it's required - if (attribute.required) { - field.type = new GraphQLNonNull(fieldType); - } else { - field.type = fieldType; - } + // if (attribute.required) { + // field.type = new GraphQLNonNull(fieldType); + // } else { + // field.type = fieldType; + // } // use computed value's function as the field resolver - if (attribute.resolve) { - field.resolve = attribute.resolve; - } + // if (attribute.resolve) { + // field.resolve = attribute.resolve; + // } + + const field = { + description: attribute.description, + type: attribute.required + ? new GraphQLNonNull(fieldType) + : fieldType, + resolve: attribute.resolve ? attribute.resolve : undefined, + }; fields[attribute.gqlFieldName] = field; @@ -325,7 +343,7 @@ export const generateGraphQLSchema = configuration => { // build the query type const queryType = new GraphQLObjectType({ name: 'Query', - root: 'The root query type', + // root: 'The root query type', fields: () => { const listQueries = generateListQueries(graphRegistry); @@ -334,7 +352,7 @@ export const generateGraphQLSchema = configuration => { // override args.id of relay to args.nodeId nodeField.args.nodeId = nodeField.args.id; - nodeField.resolve = (obj, { nodeId }, context, info) => + nodeField.resolve = (_obj, { nodeId }, context, info) => idFetcher(nodeId, context, info); delete nodeField.args.id; @@ -349,7 +367,7 @@ export const generateGraphQLSchema = configuration => { const mutationType = new GraphQLObjectType({ name: 'Mutation', - root: 'The root mutation type', + // root: 'The root mutation type', fields: () => { const mutations = generateMutations(graphRegistry); diff --git a/src/graphqlProtocol/graphRegistry.js b/src/graphqlProtocol/graphRegistry.ts similarity index 100% rename from src/graphqlProtocol/graphRegistry.js rename to src/graphqlProtocol/graphRegistry.ts diff --git a/src/graphqlProtocol/helper.js b/src/graphqlProtocol/helper.ts similarity index 92% rename from src/graphqlProtocol/helper.js rename to src/graphqlProtocol/helper.ts index 85f854d9..4689cb9d 100644 --- a/src/graphqlProtocol/helper.js +++ b/src/graphqlProtocol/helper.ts @@ -1,15 +1,17 @@ -import { ProtocolGraphQL } from './ProtocolGraphQL'; import * as _ from 'lodash'; +import { ProtocolGraphQL } from './ProtocolGraphQL'; +import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; + import { INDEX_UNIQUE } from '../engine/index/Index'; import { CustomError } from '../engine/CustomError'; export const getEntityUniquenessAttributes = entity => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const ret = []; if (!entity.getIndexes) { - return ret + return ret; } const entityIndexes = entity.getIndexes(); diff --git a/src/graphqlProtocol/io.spec.js b/src/graphqlProtocol/io.spec.ts similarity index 92% rename from src/graphqlProtocol/io.spec.js rename to src/graphqlProtocol/io.spec.ts index bcaa89ad..9560ab2e 100644 --- a/src/graphqlProtocol/io.spec.js +++ b/src/graphqlProtocol/io.spec.ts @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/no-empty-function */ /* eslint-disable @typescript-eslint/explicit-function-return-type */ +import { GraphQLInputObjectType, GraphQLObjectType } from 'graphql'; import { Action } from '../engine/action/Action'; import { DataTypeString, DataTypeInteger } from '../engine/datatype/dataTypes'; @@ -99,7 +100,8 @@ describe('io', () => { const inputFields = type.getFields(); expect(inputFields).toMatchSnapshot(); - const dataInputType = inputFields.data.type; + // const dataInputType = inputFields.data.type; + const dataInputType = inputFields.data.type as GraphQLInputObjectType; const dataInputFields = dataInputType.getFields(); expect(dataInputFields).toMatchSnapshot(); }); @@ -130,7 +132,9 @@ describe('io', () => { const outputFields = type.getFields(); expect(outputFields).toMatchSnapshot(); - const resultOutputType = outputFields.result.type; + // const resultOutputType = outputFields.result.type; + const resultOutputType = outputFields.result.type as GraphQLObjectType; + const resultOutputFields = resultOutputType.getFields(); expect(resultOutputFields).toMatchSnapshot(); }); @@ -244,11 +248,15 @@ describe('io', () => { const inputFields = type.getFields(); expect(inputFields).toMatchSnapshot(); - const dataInputType = inputFields.data.type; + // const dataInputType = inputFields.data.type; + const dataInputType = inputFields.data.type as GraphQLInputObjectType; const dataInputFields = dataInputType.getFields(); expect(dataInputFields).toMatchSnapshot(); - const playersInputType = dataInputFields.players.type; + // const playersInputType = dataInputFields.players.type; + const playersInputType = dataInputFields.players + .type as GraphQLInputObjectType; + const playersInputFields = playersInputType.getFields(); expect(playersInputFields).toMatchSnapshot(); diff --git a/src/graphqlProtocol/io.ts b/src/graphqlProtocol/io.ts index 001b7b58..0e89d0a4 100644 --- a/src/graphqlProtocol/io.ts +++ b/src/graphqlProtocol/io.ts @@ -11,6 +11,8 @@ import { import * as _ from 'lodash'; import { ProtocolGraphQL } from './ProtocolGraphQL'; +import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; + import { DataOutputField, InputFields, @@ -62,7 +64,9 @@ const generateDataInputField = ( true, ); } else if (param.i18n) { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + // const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; + const languages = protocolConfiguration .getParentConfiguration() .getLanguages(); @@ -153,8 +157,12 @@ const generateDataInputFields = ( }; //GraphQLInputObjectType | ? -export const generateDataInput = (baseName, inputParams, singleParam) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); +export const generateDataInput = ( + baseName: string, + inputParams: any, + singleParam?: any, +) => { + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; if (singleParam) { // eslint-disable-next-line no-use-before-define @@ -176,6 +184,7 @@ export const generateDataInput = (baseName, inputParams, singleParam) => { }, }); + dataInputType.getFields(); return dataInputType; }; @@ -185,7 +194,7 @@ export const generateNestedDataInput = ( nestedParamName, level = 1, ) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const dataInputType = new GraphQLInputObjectType({ name: protocolConfiguration.generateNestedDataInputTypeName( @@ -215,7 +224,7 @@ export const generateInput = ( isField, includeClientMutationId = false, ): GraphQLInputObjectType => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const inputType = new GraphQLInputObjectType({ name: protocolConfiguration.generateInputTypeName(baseName), @@ -259,7 +268,7 @@ const generateDataOutputField = ( level = 0, returnAsFieldNameMap = false, ): GraphQLObjectType | WrappedDataOutputField => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; let paramType = param.type; let baseFieldType; @@ -413,12 +422,12 @@ const generateDataOutputFields = ( }; export const generateDataOutput = ( - baseName, - outputParams, - graphRegistry, - singleParam, + baseName: string, + outputParams: any, + graphRegistry: any, + singleParam?: any, ): GraphQLObjectType | WrappedDataOutputField => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; if (singleParam) { // eslint-disable-next-line no-use-before-define @@ -446,10 +455,10 @@ export const generateNestedDataOutput = ( baseName, nestedParam, nestedParamName, - graphRegistry, + graphRegistry?: any, level = 1, ) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const dataOutputType = new GraphQLObjectType({ name: protocolConfiguration.generateNestedDataOutPutTypeName( @@ -480,7 +489,7 @@ export const generateOutput = ( isField, includeClientMutationId = false, ): GraphQLObjectType => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const outputType = new GraphQLObjectType({ name: protocolConfiguration.generateOutPutTypeName(baseName), diff --git a/src/graphqlProtocol/mutation.js b/src/graphqlProtocol/mutation.ts similarity index 93% rename from src/graphqlProtocol/mutation.js rename to src/graphqlProtocol/mutation.ts index 47261c40..4ea74011 100644 --- a/src/graphqlProtocol/mutation.js +++ b/src/graphqlProtocol/mutation.ts @@ -5,12 +5,15 @@ import { GraphQLInputObjectType, GraphQLObjectType, GraphQLInt, + GraphQLInputFieldConfigMap, + GraphQLFieldConfigMap, } from 'graphql'; import { fromGlobalId } from 'graphql-relay'; import * as _ from 'lodash'; import { ProtocolGraphQL } from './ProtocolGraphQL'; +import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; import { getEntityUniquenessAttributes } from './helper'; import { getMutationResolver } from './resolver'; import { isEntity } from '../engine/entity/Entity'; @@ -18,7 +21,8 @@ import { isEntity } from '../engine/entity/Entity'; const i18nInputFieldTypesCache = {}; const generateI18nInputFieldType = (entity, entityMutation, attribute) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; + const i18nFieldTypeName = protocolConfiguration.generateMutationI18nAttributeInputTypeName( entity, entityMutation, @@ -42,11 +46,7 @@ const generateI18nInputFieldType = (entity, entityMutation, attribute) => { const i18nFieldType = new GraphQLInputObjectType({ name: i18nFieldTypeName, - description: `**\`${ - entityMutation.name - }\`** mutation translations input type for **\`${typeNamePascalCase}.${ - attribute.gqlFieldName - }\`**`, + description: `**\`${entityMutation.name}\`** mutation translations input type for **\`${typeNamePascalCase}.${attribute.gqlFieldName}\`**`, fields: () => { const i18nFields = {}; @@ -72,7 +72,7 @@ const generateI18nInputFieldType = (entity, entityMutation, attribute) => { }; export const generateMutationInstanceInput = (entity, entityMutation) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const typeNamePascalCase = entity.graphql.typeNamePascalCase; @@ -81,12 +81,10 @@ export const generateMutationInstanceInput = (entity, entityMutation) => { entity, entityMutation, ), - description: `**\`${ - entityMutation.name - }\`** mutation input type for **\`${typeNamePascalCase}\`**`, + description: `**\`${entityMutation.name}\`** mutation input type for **\`${typeNamePascalCase}\`**`, fields: () => { - const fields = {}; + const fields: GraphQLInputFieldConfigMap = {}; const entityAttributes = entity.getAttributes(); @@ -144,7 +142,7 @@ export const generateMutationInput = ( entityMutation, entityMutationInstanceInputType, ) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const typeNamePascalCase = entity.graphql.typeNamePascalCase; @@ -156,7 +154,7 @@ export const generateMutationInput = ( description: `Mutation input type for **\`${typeNamePascalCase}\`**`, fields: () => { - const fields = { + const fields: GraphQLInputFieldConfigMap = { clientMutationId: { type: GraphQLString, }, @@ -188,7 +186,7 @@ export const generateMutationByPrimaryAttributeInput = ( entityMutationInstanceInputType, primaryAttribute, ) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const fieldName = primaryAttribute.gqlFieldName; const fieldType = ProtocolGraphQL.convertToProtocolDataType( @@ -207,7 +205,7 @@ export const generateMutationByPrimaryAttributeInput = ( description: `Mutation input type for **\`${typeNamePascalCase}\`** using the **\`${fieldName}\`**`, fields: () => { - const fields = { + const fields: GraphQLInputFieldConfigMap = { clientMutationId: { type: GraphQLString, }, @@ -237,7 +235,7 @@ export const generateInstanceUniquenessInput = ( uniquenessAttributes, graphRegistry, ) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const typeNamePascalCase = entity.graphql.typeNamePascalCase; @@ -246,12 +244,10 @@ export const generateInstanceUniquenessInput = ( entity, uniquenessAttributes.uniquenessName, ), - description: `Input type for **\`${typeNamePascalCase}\`** using data uniqueness (${ - uniquenessAttributes.attributes - }) to resolve the ID`, + description: `Input type for **\`${typeNamePascalCase}\`** using data uniqueness (${uniquenessAttributes.attributes}) to resolve the ID`, fields: () => { - const fields = {}; + const fields: GraphQLInputFieldConfigMap = {}; const entityAttributes = entity.getAttributes(); @@ -282,8 +278,7 @@ export const generateInstanceUniquenessInput = ( ? new GraphQLNonNull(fieldType) : fieldType, }; - } - else { + } else { fields[attribute.gqlFieldName] = { type: fieldType, }; @@ -303,8 +298,7 @@ export const generateInstanceUniquenessInput = ( }; }); } - } - else { + } else { const fieldType = ProtocolGraphQL.convertToProtocolDataType( attributeType, entity.name, @@ -350,7 +344,7 @@ export const generateMutationInstanceNestedInput = ( entityMutation, graphRegistry, ) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const typeNamePascalCase = entity.graphql.typeNamePascalCase; @@ -359,12 +353,10 @@ export const generateMutationInstanceNestedInput = ( entity, entityMutation, ), - description: `**\`${ - entityMutation.name - }\`** mutation input type for **\`${typeNamePascalCase}\`** using data uniqueness to resolve references`, + description: `**\`${entityMutation.name}\`** mutation input type for **\`${typeNamePascalCase}\`** using data uniqueness to resolve references`, fields: () => { - const fields = {}; + const fields: GraphQLInputFieldConfigMap = {}; const entityAttributes = entity.getAttributes(); @@ -398,8 +390,7 @@ export const generateMutationInstanceNestedInput = ( ? new GraphQLNonNull(fieldType) : fieldType, }; - } - else { + } else { fields[attribute.gqlFieldName] = { type: fieldType, }; @@ -419,8 +410,7 @@ export const generateMutationInstanceNestedInput = ( }; }); } - } - else { + } else { const fieldType = ProtocolGraphQL.convertToProtocolDataType( attributeType, entity.name, @@ -464,7 +454,7 @@ export const generateMutationNestedInput = ( entityMutation, entityMutationInstanceUniquenessInputType, ) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const typeNamePascalCase = entity.graphql.typeNamePascalCase; @@ -476,7 +466,7 @@ export const generateMutationNestedInput = ( description: `Mutation input type for **\`${typeNamePascalCase}\`** using data uniqueness to resolve references`, fields: () => { - const fields = { + const fields: GraphQLInputFieldConfigMap = { clientMutationId: { type: GraphQLString, }, @@ -507,7 +497,7 @@ export const generateMutationOutput = ( type, entityMutation, ) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const typeNamePascalCase = entity.graphql.typeNamePascalCase; @@ -519,7 +509,7 @@ export const generateMutationOutput = ( description: `Mutation output type for **\`${typeNamePascalCase}\`**`, fields: () => { - const fields = { + const fields: GraphQLFieldConfigMap = { clientMutationId: { type: GraphQLString, }, @@ -546,8 +536,7 @@ export const generateMutationOutput = ( description: primaryAttribute.description, }; } - } - else { + } else { fields[typeName] = { type: new GraphQLNonNull(type), }; @@ -581,7 +570,7 @@ const extractIdFromNodeId = (graphRegistry, sourceEntityName, nodeId) => { }; export const generateMutations = graphRegistry => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const mutations = {}; generateInstanceUniquenessInputs(graphRegistry); diff --git a/src/graphqlProtocol/protocolGraphqlConstants.js b/src/graphqlProtocol/protocolGraphqlConstants.ts similarity index 100% rename from src/graphqlProtocol/protocolGraphqlConstants.js rename to src/graphqlProtocol/protocolGraphqlConstants.ts diff --git a/src/graphqlProtocol/query.js b/src/graphqlProtocol/query.ts similarity index 93% rename from src/graphqlProtocol/query.js rename to src/graphqlProtocol/query.ts index c7953e18..cff7e4f3 100644 --- a/src/graphqlProtocol/query.js +++ b/src/graphqlProtocol/query.ts @@ -1,14 +1,15 @@ +import { GraphQLNonNull, GraphQLID } from 'graphql'; import * as _ from 'lodash'; import { ProtocolGraphQL } from './ProtocolGraphQL'; - -import { GraphQLNonNull, GraphQLID } from 'graphql'; +import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; import { resolveByFind, resolveByFindOne } from './resolver'; import { isEntity } from '../engine/entity/Entity'; import { isViewEntity } from '../engine/entity/ViewEntity'; export const generateListQueries = graphRegistry => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; + const listQueries = {}; _.forEach(graphRegistry.types, ({ entity }, typeName) => { @@ -32,7 +33,7 @@ export const generateListQueries = graphRegistry => { }; export const generateInstanceQueries = (graphRegistry, idFetcher) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const instanceQueries = {}; _.forEach(graphRegistry.types, ({ type, entity }) => { @@ -54,7 +55,7 @@ export const generateInstanceQueries = (graphRegistry, idFetcher) => { type: new GraphQLNonNull(GraphQLID), }, }, - resolve: (source, { nodeId }, context, info) => + resolve: (_source, { nodeId }, context, info) => idFetcher(nodeId, context, info), }; diff --git a/src/graphqlProtocol/resolver.js b/src/graphqlProtocol/resolver.ts similarity index 95% rename from src/graphqlProtocol/resolver.js rename to src/graphqlProtocol/resolver.ts index f78ac7fd..6afd0120 100644 --- a/src/graphqlProtocol/resolver.js +++ b/src/graphqlProtocol/resolver.ts @@ -6,6 +6,7 @@ import { } from './util'; import { ProtocolGraphQL } from './ProtocolGraphQL'; +import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; import { validateConnectionArgs, @@ -37,16 +38,17 @@ import { } from '../engine/helpers'; import { validateMutationPayload } from '../engine/validation'; -export const resolveByFind = (entity, parentConnectionCollector) => { +export const resolveByFind = (entity, parentConnectionCollector?: any) => { const storageType = entity.storageType; - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; return async (source, args, context, info) => { const parentConnection = parentConnectionCollector ? parentConnectionCollector({ source, args, context, info }) : null; - validateConnectionArgs(source, args, context, info); + // validateConnectionArgs(source, args, context, info); + validateConnectionArgs(source, args); forceSortByUnique(args.orderBy, entity); if (entity.preProcessor) { @@ -129,9 +131,9 @@ export const resolveByFind = (entity, parentConnectionCollector) => { export const resolveByFindOne = (entity, idCollector) => { const storageType = entity.storageType; - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; - return async (source, args, context, info) => { + return async (source: any, args: any, context?: object, info?: object) => { const id = idCollector({ source, args, context }); if (id === null || typeof id === 'undefined') { @@ -168,7 +170,7 @@ export const getNestedPayloadResolver = ( storageType, path = [], ) => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; return async (source, args, context, info) => { const resultPayload = {}; @@ -298,7 +300,8 @@ export const getMutationResolver = ( idResolver, ) => { const storageType = entity.storageType; - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; + const nestedPayloadResolver = getNestedPayloadResolver( entity, entityMutation.attributes, @@ -310,7 +313,7 @@ export const getMutationResolver = ( entity, entityMutation, args.input[typeName], - context, + // context, ); if (nested) { @@ -369,10 +372,12 @@ export const getMutationResolver = ( if (entityMutation.type !== MUTATION_TYPE_DELETE) { // // this function might be wrong when we look serializeValues args + // unless we add typeName ? args.input[typeName] = serializeValues( entity, entityMutation, args.input[typeName], + typeName, context, ); } diff --git a/src/graphqlProtocol/sort.js b/src/graphqlProtocol/sort.ts similarity index 94% rename from src/graphqlProtocol/sort.js rename to src/graphqlProtocol/sort.ts index d7e4b997..6854ef85 100644 --- a/src/graphqlProtocol/sort.js +++ b/src/graphqlProtocol/sort.ts @@ -1,11 +1,12 @@ import { GraphQLEnumType, GraphQLList } from 'graphql'; import * as _ from 'lodash'; import { ProtocolGraphQL } from './ProtocolGraphQL'; +import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; import { isEntity } from '../engine/entity/Entity'; import { isShadowEntity } from '../engine/entity/ShadowEntity'; export const generateSortInput = entity => { - const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration(); + const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const storageType = entity.storageType; const sortNames = {}; diff --git a/src/graphqlProtocol/util.spec.js b/src/graphqlProtocol/util.spec.ts similarity index 100% rename from src/graphqlProtocol/util.spec.js rename to src/graphqlProtocol/util.spec.ts diff --git a/src/graphqlProtocol/util.js b/src/graphqlProtocol/util.ts similarity index 100% rename from src/graphqlProtocol/util.js rename to src/graphqlProtocol/util.ts From ec19a5076c8525408767cf0fdfda6a75437c619e Mon Sep 17 00:00:00 2001 From: getlarge Date: Thu, 2 Apr 2020 21:07:30 +0200 Subject: [PATCH 10/13] add git repository url ; add node types --- package.json | 5 +++++ yarn.lock | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/package.json b/package.json index 5a7590d4..4f0076b0 100644 --- a/package.json +++ b/package.json @@ -54,11 +54,16 @@ ], "author": "Chris Kalmar ", "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/chriskalmar/shyft" + }, "devDependencies": { "@babel/core": "7.8.7", "@babel/preset-env": "7.8.7", "@types/jest": "25.1.4", "@types/lodash": "4.14.149", + "@types/node": "^12.12.31", "@typescript-eslint/eslint-plugin": "2.23.0", "@typescript-eslint/parser": "2.23.0", "babel-jest": "25.1.0", diff --git a/yarn.lock b/yarn.lock index cb5f4291..7a2e693a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1229,6 +1229,11 @@ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.149.tgz#1342d63d948c6062838fbf961012f74d4e638440" integrity sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ== +"@types/node@^12.12.31": + version "12.12.31" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.31.tgz#d6b4f9645fee17f11319b508fb1001797425da51" + integrity sha512-T+wnJno8uh27G9c+1T+a1/WYCHzLeDqtsGJkoEdSp2X8RTh3oOCZQcUnjAx90CS8cmmADX51O0FI/tu9s0yssg== + "@types/parse-json@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" From d599fec4dddbd13f77c3c6f11df078c88e29eb63 Mon Sep 17 00:00:00 2001 From: getlarge Date: Thu, 2 Apr 2020 21:13:57 +0200 Subject: [PATCH 11/13] update test snapshots --- .../__snapshots__/{action.spec.js.snap => action.spec.ts.snap} | 0 .../{dataTypes.spec.js.snap => dataTypes.spec.ts.snap} | 0 .../__snapshots__/{filter.spec.js.snap => filter.spec.ts.snap} | 0 .../{generator.spec.js.snap => generator.spec.ts.snap} | 0 .../__snapshots__/{io.spec.js.snap => io.spec.ts.snap} | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename src/graphqlProtocol/__snapshots__/{action.spec.js.snap => action.spec.ts.snap} (100%) rename src/graphqlProtocol/__snapshots__/{dataTypes.spec.js.snap => dataTypes.spec.ts.snap} (100%) rename src/graphqlProtocol/__snapshots__/{filter.spec.js.snap => filter.spec.ts.snap} (100%) rename src/graphqlProtocol/__snapshots__/{generator.spec.js.snap => generator.spec.ts.snap} (100%) rename src/graphqlProtocol/__snapshots__/{io.spec.js.snap => io.spec.ts.snap} (100%) diff --git a/src/graphqlProtocol/__snapshots__/action.spec.js.snap b/src/graphqlProtocol/__snapshots__/action.spec.ts.snap similarity index 100% rename from src/graphqlProtocol/__snapshots__/action.spec.js.snap rename to src/graphqlProtocol/__snapshots__/action.spec.ts.snap diff --git a/src/graphqlProtocol/__snapshots__/dataTypes.spec.js.snap b/src/graphqlProtocol/__snapshots__/dataTypes.spec.ts.snap similarity index 100% rename from src/graphqlProtocol/__snapshots__/dataTypes.spec.js.snap rename to src/graphqlProtocol/__snapshots__/dataTypes.spec.ts.snap diff --git a/src/graphqlProtocol/__snapshots__/filter.spec.js.snap b/src/graphqlProtocol/__snapshots__/filter.spec.ts.snap similarity index 100% rename from src/graphqlProtocol/__snapshots__/filter.spec.js.snap rename to src/graphqlProtocol/__snapshots__/filter.spec.ts.snap diff --git a/src/graphqlProtocol/__snapshots__/generator.spec.js.snap b/src/graphqlProtocol/__snapshots__/generator.spec.ts.snap similarity index 100% rename from src/graphqlProtocol/__snapshots__/generator.spec.js.snap rename to src/graphqlProtocol/__snapshots__/generator.spec.ts.snap diff --git a/src/graphqlProtocol/__snapshots__/io.spec.js.snap b/src/graphqlProtocol/__snapshots__/io.spec.ts.snap similarity index 100% rename from src/graphqlProtocol/__snapshots__/io.spec.js.snap rename to src/graphqlProtocol/__snapshots__/io.spec.ts.snap From 1e0a785b24ec81753f0d9ba8a602837ea17cac93 Mon Sep 17 00:00:00 2001 From: getlarge Date: Fri, 3 Apr 2020 08:35:15 +0200 Subject: [PATCH 12/13] Update engine/Action.ts and tests --- src/engine/action/Action.js | 208 ------------------------------------ src/engine/action/Action.ts | 20 +++- 2 files changed, 18 insertions(+), 210 deletions(-) delete mode 100644 src/engine/action/Action.js diff --git a/src/engine/action/Action.js b/src/engine/action/Action.js deleted file mode 100644 index 2484a7dd..00000000 --- a/src/engine/action/Action.js +++ /dev/null @@ -1,208 +0,0 @@ -import { passOrThrow, isMap, isFunction } from '../util'; - -import { - generatePermissionDescription, - processActionPermissions, -} from '../permission/Permission'; - -export const ACTION_TYPE_MUTATION = 'mutation'; -export const ACTION_TYPE_QUERY = 'query'; -export const actionTypes = [ ACTION_TYPE_MUTATION, ACTION_TYPE_QUERY ]; - -export class Action { - constructor(setup = {}) { - const { - name, - description, - input, - output, - resolve, - type, - permissions, - preProcessor, - postProcessor, - } = setup; - - passOrThrow(name, () => 'Missing action name'); - passOrThrow(description, () => `Missing description for action '${name}'`); - - passOrThrow( - !input || isMap(input) || isFunction(input), - () => `Action '${name}' has an invalid input definition`, - ); - - passOrThrow( - !output || isMap(output) || isFunction(output), - () => `Action '${name}' has an invalid output definition`, - ); - - passOrThrow( - isFunction(resolve), - () => `Action '${name}' needs a resolve function`, - ); - - passOrThrow( - !type || actionTypes.indexOf(type) >= 0, - () => - `Unknown action type '${type}' used in action '${name}', try one of these: '${actionTypes.join( - ', ', - )}'`, - ); - - if (preProcessor) { - passOrThrow( - isFunction(preProcessor), - () => `preProcessor of of action '${name}' needs to be a valid function`, - ); - - this.preProcessor = preProcessor; - } - - if (postProcessor) { - passOrThrow( - isFunction(postProcessor), - () => - `postProcessor of action '${name}' needs to be a valid function`, - ); - - this.postProcessor = postProcessor; - } - - this.name = name; - this.description = description; - this.input = input; - this.output = output; - this.resolve = resolve; - this.type = type || ACTION_TYPE_MUTATION; - this._permissions = permissions; - } - - getInput() { - if (!this.hasInput()) { - return null; - } - - if (this._input) { - return this._input; - } - - if (isFunction(this.input)) { - this.input = this.input(); - - passOrThrow( - isMap(this.input), - () => - `Input definition function for action '${ - this.name - }' does not return a map`, - ); - } - - passOrThrow( - this.input.type, - () => `Missing input type for action '${this.name}'`, - ); - - if (isFunction(this.input.type)) { - this.input.type = this.input.type({ - name: 'input', - description: this.input.description || this.description, - }); - } - - this._input = this.input; - - return this._input; - } - - hasInput() { - return !!this.input; - } - - getOutput() { - if (!this.hasOutput()) { - return null; - } - - if (this._output) { - return this._output; - } - - if (isFunction(this.output)) { - this.output = this.output(); - - passOrThrow( - isMap(this.output), - () => - `Output definition function for action '${ - this.name - }' does not return a map`, - ); - } - - passOrThrow( - this.output.type, - () => `Missing output type for action '${this.name}'`, - ); - - if (isFunction(this.output.type)) { - this.output.type = this.output.type({ - name: 'output', - description: this.output.description || this.description, - }); - } - - this._output = this.output; - - return this._output; - } - - hasOutput() { - return !!this.output; - } - - _processPermissions() { - if (this._permissions) { - const permissions = isFunction(this._permissions) - ? this._permissions() - : this._permissions; - - return processActionPermissions(this, permissions); - } - else if (this._defaultPermissions) { - return processActionPermissions(this, this._defaultPermissions); - } - - return null; - } - - _generatePermissionDescriptions() { - if (this.permissions) { - this.descriptionPermissions = generatePermissionDescription( - this.permissions, - ); - } - } - - _injectDefaultPermissionsBySchema(defaultPermissions) { - this._defaultPermissions = defaultPermissions; - } - - getPermissions() { - if ((!this._permissions && !this._defaultPermissions) || this.permissions) { - return this.permissions; - } - - this.permissions = this._processPermissions(); - this._generatePermissionDescriptions(); - return this.permissions; - } - - toString() { - return this.name; - } -} - -export const isAction = obj => { - return obj instanceof Action; -}; diff --git a/src/engine/action/Action.ts b/src/engine/action/Action.ts index e60dc843..b0e16fb2 100644 --- a/src/engine/action/Action.ts +++ b/src/engine/action/Action.ts @@ -23,6 +23,7 @@ export type ActionSetup = { resolve?: Function; type?: string; permissions?: Function | Permission | Permission[]; + preProcessor?: Function; postProcessor?: Function; }; @@ -43,6 +44,7 @@ export class Action { private _permissions: Function | Permission | Permission[]; private _defaultPermissions: Permission | Permission[]; descriptionPermissions: string | boolean; + preProcessor: Function; postProcessor: Function; constructor(setup: ActionSetup = {} as ActionSetup) { @@ -54,6 +56,7 @@ export class Action { resolve, type, permissions, + preProcessor, postProcessor, } = setup; @@ -83,11 +86,20 @@ export class Action { )}'`, ); + if (preProcessor) { + passOrThrow( + isFunction(preProcessor), + () => + `preProcessor of of action '${name}' needs to be a valid function`, + ); + + this.preProcessor = preProcessor; + } + if (postProcessor) { passOrThrow( isFunction(postProcessor), - () => - `postProcessor of mutation '${name}' needs to be a valid function`, + () => `postProcessor of action '${name}' needs to be a valid function`, ); this.postProcessor = postProcessor; @@ -192,6 +204,8 @@ export class Action { _processPermissions(): null | Permission | Permission[] { if (this._permissions) { + // if (isArray(this._permissions)) { check type for each permission } + if (isFunction(this._permissions)) { const permissionsFn = this._permissions as Function; const permissions: Permission | Permission[] = permissionsFn(); @@ -213,6 +227,8 @@ export class Action { _generatePermissionDescriptions(): void { if (this.permissions) { + // if (isArray(this._permissions)) { check type for each permission } + let permissions: Permission | Permission[]; if (isFunction(this._permissions)) { const permissionsFn = this._permissions as Function; From 0226c7ef3a973dcabec1ada623890cff18622b1e Mon Sep 17 00:00:00 2001 From: getlarge Date: Fri, 3 Apr 2020 10:54:30 +0200 Subject: [PATCH 13/13] update lint commands ; fix ConnectionNode type --- package.json | 5 ++--- src/graphqlProtocol/connection.ts | 13 +++++-------- src/graphqlProtocol/types.ts | 5 +++++ 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 4f0076b0..9bd557c5 100644 --- a/package.json +++ b/package.json @@ -8,9 +8,8 @@ "clean": "rimraf lib", "test": "jest", "test-watch": "jest --watch", - "lint": "eslint src/*", - "lint-fix": "eslint src/* --fix", - "lint:fix": "tsc --noEmit && eslint '*/**/*.{js,ts,tsx}' --quiet --fix", + "lint": "tsc --noEmit && eslint '*/**/*.{js,ts,tsx}'", + "lint-fix": "tsc --noEmit && eslint '*/**/*.{js,ts,tsx}' --quiet --fix", "lint-staged": "lint-staged", "coverage": "cross-env NODE_ENV=test jest --coverage", "coverage-ci": "npm run coverage && cat ./coverage/lcov.info | codecov", diff --git a/src/graphqlProtocol/connection.ts b/src/graphqlProtocol/connection.ts index 25d74da5..1b815fd1 100644 --- a/src/graphqlProtocol/connection.ts +++ b/src/graphqlProtocol/connection.ts @@ -15,12 +15,9 @@ import { ProtocolGraphQL } from './ProtocolGraphQL'; import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; import { generateSortInput } from './sort'; import { generateFilterInput } from './filter'; +import { ConnectionNode } from './types'; // import { Entity } from '../engine/entity/Entity'; -export type ConnectioNode = { - cursor: any; -}; - export const generateConnectionArgs = (entity, graphRegistry) => { const sortInput = generateSortInput(entity); const filterInput = generateFilterInput(entity, graphRegistry); @@ -228,7 +225,7 @@ export const connectionFromData = ( pageInfoFromData, ) => { const entityName = entity.name; - let nodeToEdge; + let nodeToEdge: (node: any, idx?: number) => ConnectionNode; if (entity.getPrimaryAttribute()) { const primaryAttributeName = entity.getPrimaryAttribute().name; @@ -247,10 +244,10 @@ export const connectionFromData = ( }); } - const edges = transformedData.map(nodeToEdge); + const edges: ConnectionNode[] = transformedData.map(nodeToEdge); - const firstNode: ConnectioNode = first(edges); - const lastNode: ConnectioNode = last(edges); + const firstNode = first(edges); + const lastNode = last(edges); return { edges, diff --git a/src/graphqlProtocol/types.ts b/src/graphqlProtocol/types.ts index 307b5f21..44f91abc 100644 --- a/src/graphqlProtocol/types.ts +++ b/src/graphqlProtocol/types.ts @@ -23,3 +23,8 @@ export type OutputFields = { // eslint-disable-next-line @typescript-eslint/no-explicit-any result?: any; }; + +export type ConnectionNode = { + cursor?: any; + node?: any; +};