Skip to content

Commit

Permalink
Merge pull request #20 from bcgsc/release/v4.0.0
Browse files Browse the repository at this point in the history
Release/v4.0.0
  • Loading branch information
creisle committed May 13, 2022
2 parents 93f30b9 + 480a226 commit 722fd55
Show file tree
Hide file tree
Showing 30 changed files with 2,020 additions and 1,856 deletions.
22 changes: 16 additions & 6 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,30 @@
"airbnb-typescript/base",
"plugin:@typescript-eslint/recommended"
],
"parserOptions": {
"project": "./tsconfig.json"
},
"plugins": [
"jest",
"jest-formatting"
],
"parserOptions": { "project": "./tsconfig.json" },
"rules": {
"@typescript-eslint/no-throw-literal": "warn",
"import/prefer-default-export": "off",
"@typescript-eslint/lines-between-class-members": ["error", "always", { "exceptAfterSingleLine": true }],
"@typescript-eslint/indent": [
"error",
4,
{
"SwitchCase": 1
}
],
"@typescript-eslint/lines-between-class-members": [
"error",
"always",
{
"exceptAfterSingleLine": true
}
],
"@typescript-eslint/no-throw-literal": "warn",
"import/prefer-default-export": "off",
"jest/consistent-test-it": [
"error",
{
Expand All @@ -37,13 +45,15 @@
"error",
"unix"
],
"max-classes-per-file": "off",
"max-len": [
"warn",
{
"code": 100,
"ignoreComments": true,
"ignoreStrings": true,
"ignoreTrailingComments": true,
"code": 100
"ignoreTemplateLiterals": true,
"ignoreTrailingComments": true
}
],
"multiline-ternary": [
Expand Down
25 changes: 24 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,32 @@ for orientjs 3.X.X) that you will patch this after import. For example

```javascript
const {RID} = require('orientjs');
const {constants, schema: SCHEMA_DEFN} = require('@bcgsc-pori/graphkb-schema');
const {constants, schema} = require('@bcgsc-pori/graphkb-schema');

const {PERMISSIONS} = constants;

constants.RID = RID; // IMPORTANT: Without this all castToRID will do is convert to a string
```

## Migrating from v3 to v4

To facilitate more reuseable typing schemes ClassModel and Property classes have been removed and now are simply objects. All interactions with these models should go through the schema class instead of interacting directly with the model and property objects. Return types are given only when they differ.

| v3 | v4 equivalent |
| ------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `ClassModel._properties` | `ClassDefinition.properties` |
| `ClassModel.properties` | `SchemaDefinition.getProperties(modelName: string)` |
| `ClassModel.required` | `SchemaDefinition.requiredProperties(modelName: string)` |
| `ClassModel.optional` | `SchemaDefinition.optionalProperties(modelName: string)` |
| `ClassModel.getActiveProperties()` | `SchemaDefinition.activeProperties(modelName: string)` |
| `ClassModel.inherits` | `SchemaDefinition.ancestors(modelName: string)` |
| `ClassModel.subclasses: ClassModel[]` | `SchemaDefinition.children(modelName: string): string[]` |
| `ClassModel.descendantTree(excludeAbstract: boolean): ClassModel[]` | `SchemaDefinition.descendants(modelName: string, opt: { excludeAbstract?: boolean, includeSelf?: boolean }): string[]` [^1] |
| `ClassModel.queryProperties: Record<string,Property[]>` | `SchemaDefinition.queryableProperties(modelName: string): Record<string,PropertyDefinition[]>` |
| `ClassModel.inheritsProperty(propName: string)` | `SchemaDefinition.inheritsProperty(modelName: string, propName: string)` |
| `ClassModel.toJSON` | N/A [^2] |
| `ClassModel.formatRecord(record: GraphRecord, opt = {})` | `SchemaDefinition.formatRecord(modelName: string, record: GraphRecord, opt = {})` |
| `Property.validate(inputValue: unknown): unknown` | `validateProperty = (prop: PropertyDefinition, inputValue: unknown): unknown` |

[^1]: must be called with includeSelf=true to match v3 edition
[^2]: There is no need for this function now since the ClassDefinition object is effectively already a JSON object
44 changes: 20 additions & 24 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@bcgsc-pori/graphkb-schema",
"version": "3.16.0",
"version": "4.0.0",
"description": "Shared package between the API and GUI for GraphKB which holds the schema definitions and schema-related functions",
"bugs": {
"email": "graphkb@bcgsc.ca"
Expand All @@ -23,11 +23,11 @@
"@bcgsc-pori/graphkb-parser": ">=2.0.0 <3.0.0"
},
"dependencies": {
"isemail": "^3.2.0",
"lodash.omit": "4.5.0",
"typescript": "^4.5.5",
"uuid": "3.3.2",
"uuid-validate": "0.0.3"
"uuid-validate": "0.0.3",
"validator": "^13.7.0"
},
"devDependencies": {
"@types/jest": "^27.4.0",
Expand Down
83 changes: 83 additions & 0 deletions src/class.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import {
ClassDefinition, PropertyDefinition, ClassDefinitionInput, Expose, ClassPermissions, GroupName,
} from './types';
import { createPropertyDefinition } from './property';
import {
EXPOSE_ALL, EXPOSE_EDGE, EXPOSE_NONE, PERMISSIONS,
} from './constants';

const getRouteName = (name: string, isEdge: boolean) => {
if (name.length === 1) {
return `/${name.toLowerCase()}`;
} if (!isEdge && !name.endsWith('ary') && name.toLowerCase() !== 'evidence') {
if (/.*[^aeiou]y$/.exec(name)) {
return `/${name.slice(0, name.length - 1)}ies`.toLowerCase();
}
return `/${name}s`.toLowerCase();
}
return `/${name.toLowerCase()}`;
};

const defaultPermissions = (routes: Partial<Expose> = {}): ClassPermissions => {
const permissions = {
default: PERMISSIONS.NONE,
readonly: PERMISSIONS.READ,
};

if (routes.QUERY || routes.GET) {
permissions.default |= PERMISSIONS.READ;
}
if (routes.POST) {
permissions.default |= PERMISSIONS.CREATE;
}
if (routes.PATCH) {
permissions.default |= PERMISSIONS.UPDATE;
}
if (routes.DELETE) {
permissions.default |= PERMISSIONS.DELETE;
}
return permissions;
};

const createClassDefinition = (opt: ClassDefinitionInput): ClassDefinition => {
const { name } = opt;
const properties: Record<string, PropertyDefinition> = {};

for (const propDefn of opt.properties || []) {
properties[propDefn.name] = createPropertyDefinition(propDefn);
}

let isEdge = Boolean(opt.isEdge);

if (opt.targetModel || opt.sourceModel) {
isEdge = true;
}

let defaultRoutes: Expose;

if (opt.isAbstract || opt.embedded) {
defaultRoutes = EXPOSE_NONE;
} else if (opt.isEdge) {
defaultRoutes = EXPOSE_EDGE;
} else {
defaultRoutes = EXPOSE_ALL;
}

const routes = opt.routes || defaultRoutes || {};

return {
...opt,
properties,
routeName: getRouteName(opt.name, Boolean(opt.isEdge)),
isEdge,
routes,
isAbstract: Boolean(opt.isAbstract),
inherits: opt.inherits || [],
description: opt.description || '',
embedded: Boolean(opt.embedded),
indices: opt.indices || [],
permissions: { ...defaultPermissions(routes), ...(opt.permissions || {}) },
};
};

export { createClassDefinition, getRouteName };
11 changes: 2 additions & 9 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,9 @@ const EXPOSE_READ = {
QUERY: true, PATCH: false, DELETE: false, POST: false, GET: true,
};

const FUZZY_CLASSES = ['AliasOf', 'DeprecatedBy'];

// default separator chars for orientdb full text hash: https://github.com/orientechnologies/orientdb/blob/2.2.x/core/src/main/java/com/orientechnologies/orient/core/index/OIndexFullText.java
const INDEX_SEP_CHARS = ' \r\n\t:;,.|+*/\\=!?[]()';

/**
* @namespace
* @property {Number} CREATE permissions for create/insert/post opertations
* @property {Number} CREATE permissions for create/insert/post operations
* @property {Number} READ permissions for read/get operations
* @property {Number} UPDATE permissions for update/patch operations
* @property {Number} DELETE permissions for delete/remove operations
Expand All @@ -45,7 +40,7 @@ const PERMISSIONS = {
UPDATE: 0b0010,
DELETE: 0b0001,
NONE: 0b0000,
ALL: 0,
ALL: 1,
};
PERMISSIONS.ALL = PERMISSIONS.READ | PERMISSIONS.CREATE | PERMISSIONS.UPDATE | PERMISSIONS.DELETE;

Expand All @@ -62,8 +57,6 @@ export {
EXPOSE_NONE,
EXPOSE_EDGE,
EXPOSE_READ,
FUZZY_CLASSES,
INDEX_SEP_CHARS,
PERMISSIONS,
RID, // IMPORTANT: to be patched with orientjs.RID for API and not GUI
};
33 changes: 12 additions & 21 deletions src/schema/edges.ts → src/definitions/edges.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { PartialSchemaDefn } from '../types';
import { EXPOSE_READ } from '../constants';
import { ModelTypeDefinition } from '../types';
import { defineSimpleIndex, BASE_PROPERTIES, activeUUID } from './util';

const edgeModels: Record<string, ModelTypeDefinition> = {
const edgeModels: PartialSchemaDefn = {
E: {
description: 'Edges',
routes: EXPOSE_READ,
Expand All @@ -22,26 +22,29 @@ const edgeModels: Record<string, ModelTypeDefinition> = {
indices: [activeUUID('E'), defineSimpleIndex({ model: 'E', property: 'createdAt' })],
},
AliasOf: {
reverseName: 'HasAlias',
description: 'The source record is an equivalent representation of the target record, both of which are from the same source',
},
Cites: { description: 'Generally refers to relationships between publications. For example, some article cites another' },
CrossReferenceOf: { description: 'The source record is an equivalent representation of the target record from a different source' },
DeprecatedBy: { description: 'The target record is a newer version of the source record' },
ElementOf: { description: 'The source record is part of (or contained within) the target record' },
GeneralizationOf: { description: 'The source record is a less specific (or more general) instance of the target record' },
Cites: { reverseName: 'CitedBy', description: 'Generally refers to relationships between publications. For example, some article cites another' },
CrossReferenceOf: { reverseName: 'HasCrossReference', description: 'The source record is an equivalent representation of the target record from a different source' },
DeprecatedBy: { reverseName: 'Deprecates', description: 'The target record is a newer version of the source record' },
ElementOf: { reverseName: 'HasElement', description: 'The source record is part of (or contained within) the target record' },
GeneralizationOf: { reverseName: 'HasGeneralization', description: 'The source record is a less specific (or more general) instance of the target record' },
Infers: {
description: 'Given the source record, the target record is also expected. For example given some genomic variant we infer the protein change equivalent',
sourceModel: 'Variant',
targetModel: 'Variant',
reverseName: 'InferredBy',
},
SubClassOf: { description: 'The source record is a subset of the target record' },
SubClassOf: { reverseName: 'HasSubclass', description: 'The source record is a subset of the target record' },
TargetOf: {
reverseName: 'HasTarget',
description: 'The source record is a target of the target record. For example some gene is the target of a particular drug',
properties: [
{ ...BASE_PROPERTIES.in },
{ ...BASE_PROPERTIES.out },
{ name: 'source', type: 'link', linkedClass: 'Source' },
{ name: 'actionType', description: 'The type of action between the gene and drug', example: 'inhibitor' },
{ name: 'actionType', description: 'The type of action between the gene and drug', examples: ['inhibitor'] },
],
},
};
Expand All @@ -59,20 +62,8 @@ for (const name of [
'TargetOf',
]) {
const sourceProp = { name: 'source', type: 'link' as const, linkedClass: 'Source' };
let reverseName;

if (name.endsWith('Of')) {
reverseName = `Has${name.slice(0, name.length - 2)}`;
} else if (name.endsWith('By')) {
reverseName = `${name.slice(0, name.length - 3)}s`;
} else if (name === 'Infers') {
reverseName = 'InferredBy';
} else {
reverseName = `${name.slice(0, name.length - 1)}dBy`;
}
edgeModels[name] = {
isEdge: true,
reverseName,
inherits: ['E'],
sourceModel: 'Ontology',
targetModel: 'Ontology',
Expand Down
Loading

0 comments on commit 722fd55

Please sign in to comment.