From f1b5730dd5e09695c7b6bfb15b93625ac6479271 Mon Sep 17 00:00:00 2001 From: Victor Korzunin Date: Sat, 11 Sep 2021 20:22:21 +0200 Subject: [PATCH] feat: cleanup generated file structure, improve model initialization --- README.md | 2 +- plop/Model.ts.hbs | 46 ------------ plop/index.ts.hbs | 31 +++----- plop/models/Model.ts.hbs | 44 ++++++++++++ plop/models/index.ts.hbs | 3 + plop/plopfile.js | 14 +++- prisma/models/Post.ts | 31 -------- prisma/models/User.ts | 61 ---------------- prisma/models/index.ts | 80 --------------------- prisma/sequelize/config.json | 29 ++++++++ prisma/sequelize/index.ts | 41 +++++++++++ prisma/sequelize/models/Post.ts | 29 ++++++++ prisma/sequelize/models/User.ts | 59 +++++++++++++++ prisma/sequelize/models/index.ts | 2 + prisma/{models => sequelize}/utils/find.ts | 0 prisma/{models => sequelize}/utils/index.ts | 0 src/index.ts | 2 +- 17 files changed, 230 insertions(+), 244 deletions(-) delete mode 100644 plop/Model.ts.hbs create mode 100644 plop/models/Model.ts.hbs create mode 100644 plop/models/index.ts.hbs delete mode 100644 prisma/models/Post.ts delete mode 100644 prisma/models/User.ts delete mode 100644 prisma/models/index.ts create mode 100644 prisma/sequelize/config.json create mode 100644 prisma/sequelize/index.ts create mode 100644 prisma/sequelize/models/Post.ts create mode 100644 prisma/sequelize/models/User.ts create mode 100644 prisma/sequelize/models/index.ts rename prisma/{models => sequelize}/utils/find.ts (100%) rename prisma/{models => sequelize}/utils/index.ts (100%) diff --git a/README.md b/README.md index 4f81829..86851ca 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ generator client { } ``` -With a custom output path (default=./models) +With a custom output path (default=./sequelize) ```prisma generator client { diff --git a/plop/Model.ts.hbs b/plop/Model.ts.hbs deleted file mode 100644 index 881009f..0000000 --- a/plop/Model.ts.hbs +++ /dev/null @@ -1,46 +0,0 @@ -import { Sequelize, Model, DataTypes, ModelCtor } from 'sequelize'; - -export const {{model.name}}Factory = (sequelize: Sequelize) => { - class {{model.name}} extends Model { - {{#if (or belongsToFields (or hasManyFields hasOneFields))}} - static associate(models: Record>) { - {{#each belongsToFields}} - this.belongsTo(models.{{name}}, { as: '{{as}}', targetKey: '{{targetKey}}', foreignKey: '{{foreignKey}}' }); - {{/each}} - {{#each hasManyFields}} - this.hasMany(models.{{name}}, { as: '{{as}}' }); - {{/each}} - {{#each hasOneFields}} - this.hasOne(models.{{name}}, { as: '{{as}}' }); - {{/each}} - } - {{/if}} - } - - {{model.name}}.init( - { - {{#each scalarFields}} - {{name}}: { - type: {{#if isList}}DataTypes.ARRAY(DataTypes.{{type}}){{else}}DataTypes.{{{type}}}{{/if}},{{#if (eq allowNull false)}} - allowNull: {{allowNull}},{{/if}}{{#if (and hasDefaultValue (eq isAutoincrement false))}} - defaultValue: '{{default}}',{{/if}}{{#if isId}} - primaryKey: {{isId}},{{/if}}{{#if isAutoincrement}} - autoIncrement: {{isAutoincrement}},{{/if}}{{#if isUnique}} - unique: {{isUnique}},{{/if}} - }, - {{/each}} - }, - { - sequelize, - modelName: '{{model.name}}', - tableName: '{{#if model.dbName}}{{model.dbName}}{{else}}{{model.name}}{{/if}}', - timestamps: {{or (or hasCreatedAt hasUpdatedAt) hasDeletedAt}},{{#if (or (or hasCreatedAt hasUpdatedAt) hasDeletedAt)}}{{#if (eq hasCreatedAt false)}} - createdAt: false,{{/if}}{{#if (eq hasUpdatedAt false)}} - updatedAt: false,{{/if}}{{!-- {{#if (eq hasDeletedAt false)}} - deletedAt: false,{{/if}} --}}{{#if hasDeletedAt}} - paranoid: true,{{/if}}{{/if}} - } - ); - - return {{model.name}}; -}; diff --git a/plop/index.ts.hbs b/plop/index.ts.hbs index c7840cb..69ed076 100644 --- a/plop/index.ts.hbs +++ b/plop/index.ts.hbs @@ -1,15 +1,13 @@ -import { ModelCtor, Sequelize } from 'sequelize'; +import { Sequelize } from 'sequelize'; import { tryLoadEnvs } from '@prisma/sdk'; import path from 'path'; + import { findSync } from './utils'; +import config from './config.json'; const dirname = findSync(process.cwd(), ['{{relativeOutputDir}}', '{{slsRelativeOutputDir}}'], ['d'], ['d'], 1)[0] || __dirname; -{{#each models}} -import { {{name}}Factory } from './{{name}}'; -{{/each}} - -const config = {{{config}}}; +import * as models from './models'; const loadedEnv = tryLoadEnvs({ rootEnvPath: config.relativeEnvPaths.rootEnvPath && path.resolve(dirname, config.relativeEnvPaths.rootEnvPath), @@ -28,7 +26,11 @@ export const createInstance = async () => { }, }); - const models = prepareModels(sequelize); + Object.keys(models).forEach((model) => { + models[model].initialize?.(sequelize); + models[model].associate?.(models); + models[model].hooks?.(models); + }); await sequelize.authenticate(); @@ -37,18 +39,3 @@ export const createInstance = async () => { models, }; }; - -function prepareModels(sequelize: Sequelize) { - const models = { - {{#each models}} - {{name}}: {{name}}Factory(sequelize), - {{/each}} - }; - - Object.keys(models).forEach((model) => { - models[model].associate?.(models); - models[model].hooks?.(models); - }); - - return models; -} diff --git a/plop/models/Model.ts.hbs b/plop/models/Model.ts.hbs new file mode 100644 index 0000000..248b22d --- /dev/null +++ b/plop/models/Model.ts.hbs @@ -0,0 +1,44 @@ +import { Sequelize, Model, DataTypes, ModelCtor } from 'sequelize'; + +export class {{model.name}} extends Model { + static initialize(sequelize: Sequelize) { + this.init( + { + {{#each scalarFields}} + {{name}}: { + type: {{#if isList}}DataTypes.ARRAY(DataTypes.{{type}}){{else}}DataTypes.{{{type}}}{{/if}},{{#if (eq allowNull false)}} + allowNull: {{allowNull}},{{/if}}{{#if (and hasDefaultValue (eq isAutoincrement false))}} + defaultValue: '{{default}}',{{/if}}{{#if isId}} + primaryKey: {{isId}},{{/if}}{{#if isAutoincrement}} + autoIncrement: {{isAutoincrement}},{{/if}}{{#if isUnique}} + unique: {{isUnique}},{{/if}} + }, + {{/each}} + }, + { + sequelize, + modelName: '{{model.name}}', + tableName: '{{#if model.dbName}}{{model.dbName}}{{else}}{{model.name}}{{/if}}', + timestamps: {{or (or hasCreatedAt hasUpdatedAt) hasDeletedAt}},{{#if (or (or hasCreatedAt hasUpdatedAt) hasDeletedAt)}}{{#if (eq hasCreatedAt false)}} + createdAt: false,{{/if}}{{#if (eq hasUpdatedAt false)}} + updatedAt: false,{{/if}}{{!-- {{#if (eq hasDeletedAt false)}} + deletedAt: false,{{/if}} --}}{{#if hasDeletedAt}} + paranoid: true,{{/if}}{{/if}} + } + ); + } + + {{#if (or belongsToFields (or hasManyFields hasOneFields))}} + static associate(models: Record>) { + {{#each belongsToFields}} + this.belongsTo(models.{{name}}, { as: '{{as}}', targetKey: '{{targetKey}}', foreignKey: '{{foreignKey}}' }); + {{/each}} + {{#each hasManyFields}} + this.hasMany(models.{{name}}, { as: '{{as}}' }); + {{/each}} + {{#each hasOneFields}} + this.hasOne(models.{{name}}, { as: '{{as}}' }); + {{/each}} + } + {{/if}} +} diff --git a/plop/models/index.ts.hbs b/plop/models/index.ts.hbs new file mode 100644 index 0000000..0c48e76 --- /dev/null +++ b/plop/models/index.ts.hbs @@ -0,0 +1,3 @@ +{{#each models}} +export * from './{{name}}'; +{{/each}} diff --git a/plop/plopfile.js b/plop/plopfile.js index 86f8bb4..393b6d7 100644 --- a/plop/plopfile.js +++ b/plop/plopfile.js @@ -31,11 +31,21 @@ module.exports = function (plop) { plop.setGenerator('index.ts', { actions: () => [ + { + type: 'add', + path: 'models/index.ts', + templateFile: path.join(__dirname, './models/index.ts.hbs'), + }, { type: 'add', path: 'index.ts', templateFile: path.join(__dirname, './index.ts.hbs'), }, + { + type: 'add', + path: 'config.json', + template: '{{{config}}}', + }, ], }); @@ -43,8 +53,8 @@ module.exports = function (plop) { actions: () => [ { type: 'add', - path: '{{model.name}}.ts', - templateFile: path.join(__dirname, './Model.ts.hbs'), + path: 'models/{{model.name}}.ts', + templateFile: path.join(__dirname, './models/Model.ts.hbs'), }, ], }); diff --git a/prisma/models/Post.ts b/prisma/models/Post.ts deleted file mode 100644 index c743f9b..0000000 --- a/prisma/models/Post.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Sequelize, Model, DataTypes, ModelCtor } from 'sequelize'; - -export const PostFactory = (sequelize: Sequelize) => { - class Post extends Model { - static associate(models: Record>) { - this.belongsTo(models.User, { as: 'user', targetKey: 'id', foreignKey: 'userId' }); - } - } - - Post.init( - { - id: { - type: DataTypes.INTEGER, - allowNull: false, - primaryKey: true, - autoIncrement: true, - }, - userId: { - type: DataTypes.INTEGER, - }, - }, - { - sequelize, - modelName: 'Post', - tableName: 'Posts', - timestamps: false, - } - ); - - return Post; -}; diff --git a/prisma/models/User.ts b/prisma/models/User.ts deleted file mode 100644 index d6b0d10..0000000 --- a/prisma/models/User.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { Sequelize, Model, DataTypes, ModelCtor } from 'sequelize'; - -export const UserFactory = (sequelize: Sequelize) => { - class User extends Model { - static associate(models: Record>) { - this.belongsTo(models.User, { as: 'successor', targetKey: 'id', foreignKey: 'successorId' }); - this.hasMany(models.Post, { as: 'posts' }); - this.hasOne(models.User, { as: 'predecessor' }); - } - } - - User.init( - { - id: { - type: DataTypes.INTEGER, - allowNull: false, - primaryKey: true, - autoIncrement: true, - }, - email: { - type: DataTypes.STRING, - allowNull: false, - unique: true, - }, - weight: { - type: DataTypes.FLOAT, - }, - is18: { - type: DataTypes.BOOLEAN, - }, - name: { - type: DataTypes.STRING, - }, - successorId: { - type: DataTypes.INTEGER, - }, - role: { - type: DataTypes.ENUM('USER', 'ADMIN'), - allowNull: false, - defaultValue: 'USER', - }, - keywords: { - type: DataTypes.ARRAY(DataTypes.STRING), - allowNull: false, - }, - biography: { - type: DataTypes.JSONB, - allowNull: false, - }, - }, - { - sequelize, - modelName: 'User', - tableName: 'User', - timestamps: true, - updatedAt: false, - } - ); - - return User; -}; diff --git a/prisma/models/index.ts b/prisma/models/index.ts deleted file mode 100644 index b08f616..0000000 --- a/prisma/models/index.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { ModelCtor, Sequelize } from 'sequelize'; -import { tryLoadEnvs } from '@prisma/sdk'; -import path from 'path'; -import { findSync } from './utils'; - -const dirname = findSync(process.cwd(), ['prisma/models', 'models'], ['d'], ['d'], 1)[0] || __dirname; - -import { UserFactory } from './User'; -import { PostFactory } from './Post'; - -const config = { - "generator": { - "name": "models", - "provider": { - "fromEnvVar": null, - "value": "node ./dist/generator.js" - }, - "output": { - "value": "/Users/victor/Projects/_own/prisma-sequelize-generator/prisma/models", - "fromEnvVar": "null" - }, - "config": {}, - "binaryTargets": [], - "previewFeatures": [] - }, - "relativeEnvPaths": { - "rootEnvPath": "../../.env", - "schemaEnvPath": "../../.env" - }, - "datasource": { - "name": "db", - "provider": "postgresql", - "activeProvider": "postgresql", - "url": { - "fromEnvVar": "DATABASE_URL", - "value": null - } - } -}; - -const loadedEnv = tryLoadEnvs({ - rootEnvPath: config.relativeEnvPaths.rootEnvPath && path.resolve(dirname, config.relativeEnvPaths.rootEnvPath), - schemaEnvPath: config.relativeEnvPaths.schemaEnvPath && path.resolve(dirname, config.relativeEnvPaths.schemaEnvPath), -}); -const env = { ...(loadedEnv ? loadedEnv.parsed : {}), ...process.env }; -const databaseUrl = config.datasource.url.fromEnvVar - ? env[config.datasource.url.fromEnvVar] - : config.datasource.url.value; - -export const createInstance = async () => { - const sequelize = new Sequelize(databaseUrl, { - ssl: true, - define: { - freezeTableName: true, - }, - }); - - const models = prepareModels(sequelize); - - await sequelize.authenticate(); - - return { - sequelize, - models, - }; -}; - -function prepareModels(sequelize: Sequelize) { - const models = { - User: UserFactory(sequelize), - Post: PostFactory(sequelize), - }; - - Object.keys(models).forEach((model) => { - models[model].associate?.(models); - models[model].hooks?.(models); - }); - - return models; -} diff --git a/prisma/sequelize/config.json b/prisma/sequelize/config.json new file mode 100644 index 0000000..e562033 --- /dev/null +++ b/prisma/sequelize/config.json @@ -0,0 +1,29 @@ +{ + "generator": { + "name": "models", + "provider": { + "fromEnvVar": null, + "value": "node ./dist/generator.js" + }, + "output": { + "value": "/Users/victor/Projects/_own/prisma-sequelize-generator/prisma/sequelize", + "fromEnvVar": "null" + }, + "config": {}, + "binaryTargets": [], + "previewFeatures": [] + }, + "relativeEnvPaths": { + "rootEnvPath": "../../.env", + "schemaEnvPath": "../../.env" + }, + "datasource": { + "name": "db", + "provider": "postgresql", + "activeProvider": "postgresql", + "url": { + "fromEnvVar": "DATABASE_URL", + "value": null + } + } +} \ No newline at end of file diff --git a/prisma/sequelize/index.ts b/prisma/sequelize/index.ts new file mode 100644 index 0000000..0935496 --- /dev/null +++ b/prisma/sequelize/index.ts @@ -0,0 +1,41 @@ +import { Sequelize } from 'sequelize'; +import { tryLoadEnvs } from '@prisma/sdk'; +import path from 'path'; + +import { findSync } from './utils'; +import config from './config.json'; + +const dirname = findSync(process.cwd(), ['prisma/sequelize', 'sequelize'], ['d'], ['d'], 1)[0] || __dirname; + +import * as models from './models'; + +const loadedEnv = tryLoadEnvs({ + rootEnvPath: config.relativeEnvPaths.rootEnvPath && path.resolve(dirname, config.relativeEnvPaths.rootEnvPath), + schemaEnvPath: config.relativeEnvPaths.schemaEnvPath && path.resolve(dirname, config.relativeEnvPaths.schemaEnvPath), +}); +const env = { ...(loadedEnv ? loadedEnv.parsed : {}), ...process.env }; +const databaseUrl = config.datasource.url.fromEnvVar + ? env[config.datasource.url.fromEnvVar] + : config.datasource.url.value; + +export const createInstance = async () => { + const sequelize = new Sequelize(databaseUrl, { + ssl: true, + define: { + freezeTableName: true, + }, + }); + + Object.keys(models).forEach((model) => { + models[model].initialize?.(sequelize); + models[model].associate?.(models); + models[model].hooks?.(models); + }); + + await sequelize.authenticate(); + + return { + sequelize, + models, + }; +}; diff --git a/prisma/sequelize/models/Post.ts b/prisma/sequelize/models/Post.ts new file mode 100644 index 0000000..b956663 --- /dev/null +++ b/prisma/sequelize/models/Post.ts @@ -0,0 +1,29 @@ +import { Sequelize, Model, DataTypes, ModelCtor } from 'sequelize'; + +export class Post extends Model { + static initialize(sequelize: Sequelize) { + this.init( + { + id: { + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true, + autoIncrement: true, + }, + userId: { + type: DataTypes.INTEGER, + }, + }, + { + sequelize, + modelName: 'Post', + tableName: 'Posts', + timestamps: false, + } + ); + } + + static associate(models: Record>) { + this.belongsTo(models.User, { as: 'user', targetKey: 'id', foreignKey: 'userId' }); + } +} diff --git a/prisma/sequelize/models/User.ts b/prisma/sequelize/models/User.ts new file mode 100644 index 0000000..62522cb --- /dev/null +++ b/prisma/sequelize/models/User.ts @@ -0,0 +1,59 @@ +import { Sequelize, Model, DataTypes, ModelCtor } from 'sequelize'; + +export class User extends Model { + static initialize(sequelize: Sequelize) { + this.init( + { + id: { + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true, + autoIncrement: true, + }, + email: { + type: DataTypes.STRING, + allowNull: false, + unique: true, + }, + weight: { + type: DataTypes.FLOAT, + }, + is18: { + type: DataTypes.BOOLEAN, + }, + name: { + type: DataTypes.STRING, + }, + successorId: { + type: DataTypes.INTEGER, + }, + role: { + type: DataTypes.ENUM('USER', 'ADMIN'), + allowNull: false, + defaultValue: 'USER', + }, + keywords: { + type: DataTypes.ARRAY(DataTypes.STRING), + allowNull: false, + }, + biography: { + type: DataTypes.JSONB, + allowNull: false, + }, + }, + { + sequelize, + modelName: 'User', + tableName: 'User', + timestamps: true, + updatedAt: false, + } + ); + } + + static associate(models: Record>) { + this.belongsTo(models.User, { as: 'successor', targetKey: 'id', foreignKey: 'successorId' }); + this.hasMany(models.Post, { as: 'posts' }); + this.hasOne(models.User, { as: 'predecessor' }); + } +} diff --git a/prisma/sequelize/models/index.ts b/prisma/sequelize/models/index.ts new file mode 100644 index 0000000..bb40634 --- /dev/null +++ b/prisma/sequelize/models/index.ts @@ -0,0 +1,2 @@ +export * from './User'; +export * from './Post'; diff --git a/prisma/models/utils/find.ts b/prisma/sequelize/utils/find.ts similarity index 100% rename from prisma/models/utils/find.ts rename to prisma/sequelize/utils/find.ts diff --git a/prisma/models/utils/index.ts b/prisma/sequelize/utils/index.ts similarity index 100% rename from prisma/models/utils/index.ts rename to prisma/sequelize/utils/index.ts diff --git a/src/index.ts b/src/index.ts index 0e02f7d..e703eba 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,7 +12,7 @@ import { PrismaTypeToSequelizeType } from './mappers'; generatorHandler({ onManifest() { return { - defaultOutput: './models', + defaultOutput: './sequelize', prettyName: 'Sequelize Models', }; },