Skip to content
This repository has been archived by the owner on Apr 17, 2023. It is now read-only.

Commit

Permalink
Merge pull request #899 from aerogear/schema-relationships
Browse files Browse the repository at this point in the history
WIP: generated relationship details for schema
  • Loading branch information
wtrocki authored Nov 23, 2020
2 parents ba9b386 + fcef636 commit f84688b
Show file tree
Hide file tree
Showing 7 changed files with 769 additions and 89 deletions.
4 changes: 3 additions & 1 deletion packages/datastore/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@
"@types/bson": "4.0.3",
"@types/jest": "26.0.15",
"@types/yargs": "15.0.10",
"endent": "^2.0.1",
"jest": "26.6.3",
"rimraf": "3.0.2",
"safe-eval": "^0.4.1",
"ts-jest": "26.4.4",
"typescript": "3.9.7"
},
"dependencies": {
"@graphback/core": "0.16.2",
"@graphback/core": "1.1.0-alpha1",
"@graphql-tools/load-files": "6.2.5",
"@graphql-tools/merge": "6.2.5",
"graphql": "^15.3.0",
Expand Down
24 changes: 12 additions & 12 deletions packages/datastore/cli/src/OffixDataStorePlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { GraphbackPlugin, GraphbackCoreMetadata } from "@graphback/core";
import { writeFileSync } from "fs";
import { IOffixDataStorePluginConfig } from "./OffixDataStoreConfig";
import { createJsonSchema, createModelType } from "./generate-documents";
import { isDataSyncClientModel, makeDirIfNotExists } from "./utils";
import { makeDirIfNotExists } from "./utils";
import { validateOffixDataStorePluginConfig } from "./OffixDataStorePluginValidator";
import endent from "endent";

export const OFFIX_DATASYNC_PLUGIN_NAME = "OffixDataStorePlugin";

Expand Down Expand Up @@ -34,25 +35,24 @@ export class OffixDataStorePlugin extends GraphbackPlugin {
}

public getDocuments(metadata: GraphbackCoreMetadata) {
const models = metadata.getModelDefinitions()
.filter(model => isDataSyncClientModel(model));

const models = metadata.getModelDefinitions();
const modelJsonSchemas = models
.map(model => (createJsonSchema(model)));

// concatenate all the json documents
const jsonSchema = modelJsonSchemas
.reduce((prev, cur) => ({ ...prev, [cur.name]: cur }), {});
const modelTypes = models.map(model => createModelType(model)).join("\n");

// TODO use actual model type instead of any for ModelJsonSchema
const exports = `import { GeneratedModelSchema } from "offix-datastore";
import jsonSchema from "./schema.json";

export const schema = jsonSchema as GeneratedModelSchema;
const modelTypes = modelJsonSchemas
.map(model => createModelType(model)).join("\n");

export * from "./types";
`;
const exports = endent`
import { GeneratedModelSchema } from "offix-datastore";
import jsonSchema from "./schema.json";
export const schema = jsonSchema as GeneratedModelSchema;
export * from "./types";
`;

return {
json: jsonSchema,
Expand Down
38 changes: 33 additions & 5 deletions packages/datastore/cli/src/generate-documents/createJsonSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,9 @@ import {
} from "graphql";
import { convertToTsType } from "../utils";


const getFieldParameters = (fieldName: string, type: GraphQLOutputType): any => {
const options: any = {};

// TODO handle relationships

options.key = fieldName;

if (isNonNullType(type)) {
Expand All @@ -24,22 +21,53 @@ const getFieldParameters = (fieldName: string, type: GraphQLOutputType): any =>

const getModelProperties = (model: ModelDefinition, primaryKey: string) => {
const fieldMap = model.graphqlType.getFields();
const keys = Object.keys(fieldMap);
// get a list of relationships
const relNames = model.relationships.map(r => r.ownerField.name);

const generatedProperties = Object.keys(fieldMap)
// loop through graphback relationship types
const relationships = model.relationships
// filter out oneToMany relationships
.filter(r => r.kind !== "oneToMany")
// generate key/value pair with foreign key as key
.map(r => {
const fieldOptions = getFieldParameters(
r.relationForeignKey!,
r.relationType
);
fieldOptions.relationship = r.relationType;
return { [r.relationForeignKey!]: fieldOptions };
});

const generatedProperties = keys
// filter out autogenerated relationship properties
.filter(fieldName => !relNames.includes(fieldName))
.map(fieldName => {
const fieldOptions = getFieldParameters(fieldName, fieldMap[fieldName].type);
const fieldOptions = getFieldParameters(
fieldName,
fieldMap[fieldName].type
);
if (fieldName === primaryKey) {
fieldOptions.primary = true;
}
return { [fieldName]: fieldOptions };
})
// add previously created relationship key/values
.concat(relationships)
.reduce((prev, current) => ({ ...prev, ...current }), {});

generatedProperties._version = {
type: "string",
key: "_version",
isRequired: true
};

generatedProperties._lastUpdatedAt = {
type: "number",
key: "_lastUpdatedAt",
isRequired: true
};

return generatedProperties;
};

Expand Down
47 changes: 20 additions & 27 deletions packages/datastore/cli/src/generate-documents/createModelTypes.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,28 @@
import { ModelDefinition, getPrimaryKey } from "@graphback/core";
import { GraphQLOutputType, isNonNullType, getNullableType } from "graphql";
import { convertToTsType } from "../utils";
import endent from "endent";

const getField = (fieldName: string, type: GraphQLOutputType) => {
if (isNonNullType(type)) {
type = getNullableType(type);
} else {
fieldName = `${fieldName}?`;
}
const getModelProperties = (schema: any) => {
const fieldMap = schema.properties;
const keys = Object.keys(fieldMap);

return `${fieldName}: ${convertToTsType(type)}`;
return keys
.map(fieldName => {
const s = fieldMap[fieldName];
const name = s.isRequired ? fieldName : `${fieldName}?`;
return `${name}: ${s.type}`;
})
.join(";\n");
};

const getModelProperties = (model: ModelDefinition) => {
const fieldMap = model.graphqlType.getFields();
export const createModelType = (schema: any) => {
const { name: modelName, primaryKey } = schema;

return Object.keys(fieldMap)
.map(fieldName => (getField(fieldName, fieldMap[fieldName].type)))
.join(";\n ");
};

export const createModelType = (model: ModelDefinition) => {
const modelName = model.graphqlType.name;
const primaryKey = getPrimaryKey(model.graphqlType).name;
return endent`
export interface ${modelName} {
${getModelProperties(schema)}
}
return `export interface ${modelName} {
${getModelProperties(model)}
_version: number;
}
export type ${modelName}Create = ${primaryKey ? `Omit<${modelName}, "${primaryKey}">` : modelName};
export type ${modelName}Change = ${primaryKey ? `Pick<${modelName}, "${primaryKey}"> & ` : ""}Partial<${modelName}Create>;
export type ${modelName}Create = ${primaryKey ? `Omit<${modelName}, "${primaryKey}">` : modelName};
export type ${modelName}Change = ${primaryKey ? `Pick<${modelName}, "${primaryKey}"> & ` : ""}Partial<${modelName}Create>;
`;
`;
};
Loading

0 comments on commit f84688b

Please sign in to comment.