Skip to content

Commit

Permalink
refactor: use morphism to map schemas
Browse files Browse the repository at this point in the history
  • Loading branch information
Victor Korzunin committed Sep 13, 2021
1 parent 4beb77c commit 13f6dc0
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 45 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"dependencies": {
"@prisma/generator-helper": "^2.29.1",
"@prisma/sdk": "^2.29.1",
"morphism": "^1.12.3",
"node-plop": "^0.26.2",
"ramda": "^0.27.1"
},
Expand Down
31 changes: 31 additions & 0 deletions src/generator/properties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,34 @@ export const PrismaTypeToSequelizeType: Record<string, string> = {
DateTime: 'DATE',
Json: 'JSONB',
};

export interface ModelProperties {
name: string;
dbName: string;
scalarFields: ScalarProperties[];
belongsToFields: RelationProperties[];
hasOneFields: RelationProperties[];
hasManyFields: RelationProperties[];
hasCreatedAt: boolean;
hasUpdatedAt: boolean;
hasDeletedAt: boolean;
}

export interface RelationProperties {
as: string;
name: string;
targetKey: string;
foreignKey: string;
}

export interface ScalarProperties {
isList: boolean;
hasDefaultValue: boolean;
default: any;
isId: boolean;
isUnique: boolean;
name: string;
type: string;
allowNull: boolean;
isAutoincrement: boolean;
}
110 changes: 65 additions & 45 deletions src/generator/transformDMMF.ts
Original file line number Diff line number Diff line change
@@ -1,62 +1,82 @@
import { indexBy, prop } from 'ramda';
import { morphism, Schema } from 'morphism';
import { compose, includes, indexBy, map, not, prop } from 'ramda';

import { PrismaTypeToSequelizeType } from './properties';
import { ModelProperties, PrismaTypeToSequelizeType, RelationProperties, ScalarProperties } from './properties';

import type { DMMF } from '@prisma/generator-helper';

export function transformDMMF(dmmf: DMMF.Document) {
const enumIndex = indexBy(prop('name'), dmmf.datamodel.enums ?? []);

return {
models: dmmf.datamodel.models.map((model) => {
const attributes = model.fields.map((field) => field.name);
const scalarMorphism = morphism<Schema<ScalarProperties, DMMF.Field>>({
isList: 'isList',
hasDefaultValue: 'hasDefaultValue',
default: 'default',
isId: 'isId',
isUnique: 'isUnique',
name: 'name',
type: (field: DMMF.Field) =>
field.kind === 'scalar'
? PrismaTypeToSequelizeType[field.type]
: `ENUM(${enumIndex[field.type].values
.map(prop('name'))
.map((n) => `'${n}'`)
.join(', ')})`,
allowNull: { path: 'isRequired', fn: not },
isAutoincrement: (field: DMMF.Field) =>
field.hasDefaultValue && typeof field.default === 'object' && field.default.name === 'autoincrement',
});

return {
...model,
scalarFields: model.fields
const relationMorphism = morphism<Schema<RelationProperties, DMMF.Field>>({
as: 'name',
name: 'type',
targetKey: 'relationToFields[0]',
foreignKey: 'relationFromFields[0]',
});

const modelMorphism = morphism<Schema<ModelProperties, DMMF.Model>>({
name: 'name',
dbName: 'dbName',
scalarFields: {
path: 'fields',
fn: (fields: DMMF.Field[]) =>
fields
.filter((field) => ['scalar', 'enum'].includes(field.kind))
.filter((field) => !['createdAt', 'updatedAt', 'deletedAt'].includes(field.name))
.map((field) => ({
...field,
name: field.name,
type:
field.kind === 'scalar'
? PrismaTypeToSequelizeType[field.type]
: `ENUM(${enumIndex[field.type].values
.map(prop('name'))
.map((n) => `'${n}'`)
.join(', ')})`,
allowNull: !field.isRequired,
isAutoincrement:
field.hasDefaultValue && typeof field.default === 'object' && field.default.name === 'autoincrement',
})),
belongsToFields: model.fields
.map(scalarMorphism),
},
belongsToFields: {
path: 'fields',
fn: (fields: DMMF.Field[]) =>
fields
.filter((field) => field.kind === 'object')
.filter((field) => !field.isList && field.relationToFields?.length)
.map((field) => ({
as: field.name,
name: field.type,
targetKey: field.relationToFields![0],
foreignKey: field.relationFromFields[0],
})),
hasOneFields: model.fields
.map(relationMorphism),
},
hasOneFields: {
path: 'fields',
fn: (fields: DMMF.Field[]) =>
fields
.filter((field) => field.kind === 'object')
.filter((field) => !field.isList && !field.relationToFields?.length)
.map((field) => ({
as: field.name,
name: field.type,
})),
hasManyFields: model.fields
.map(relationMorphism),
},
hasManyFields: {
path: 'fields',
fn: (fields: DMMF.Field[]) =>
fields
.filter((field) => field.kind === 'object')
.filter((field) => field.isList)
.map((field) => ({
as: field.name,
name: field.type,
})),
hasCreatedAt: attributes.includes('createdAt'),
hasUpdatedAt: attributes.includes('updatedAt'),
hasDeletedAt: attributes.includes('deletedAt'),
};
}),
};
.map(relationMorphism),
},
hasCreatedAt: { path: 'fields', fn: compose(includes('createdAt'), map(prop('name'))) },
hasUpdatedAt: { path: 'fields', fn: compose(includes('updatedAt'), map(prop('name'))) },
hasDeletedAt: { path: 'fields', fn: compose(includes('deletedAt'), map(prop('name'))) },
});

const transformMorphism = morphism<Schema<{ models: ModelProperties[] }, DMMF.Datamodel>>({
models: { path: 'models', fn: modelMorphism },
});

return transformMorphism(dmmf.datamodel);
}

0 comments on commit 13f6dc0

Please sign in to comment.