Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/assets/migrations/create-table.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
'use strict';
<%= isTypescriptProject ? `import { QueryInterface, DataTypes } from 'sequelize';` : '' %>

/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up (queryInterface, Sequelize) {
async up (queryInterface<%= isTypescriptProject ? ': QueryInterface' : '' %>, Sequelize<%= isTypescriptProject ? ': typeof DataTypes' : '' %>) {
await queryInterface.createTable('<%= tableName %>', {
id: {
allowNull: false,
Expand All @@ -29,7 +30,7 @@ module.exports = {
});
},

async down (queryInterface, Sequelize) {
async down (queryInterface<%= isTypescriptProject ? ': QueryInterface' : '' %>, Sequelize<%= isTypescriptProject ? ': typeof DataTypes' : '' %>) {
await queryInterface.dropTable('<%= tableName %>');
}
};
5 changes: 3 additions & 2 deletions src/assets/migrations/skeleton.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
'use strict';
<%= isTypescriptProject ? `import { QueryInterface, DataTypes } from 'sequelize';` : '' %>

/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up (queryInterface, Sequelize) {
async up (queryInterface<%= isTypescriptProject ? ': QueryInterface' : '' %>, Sequelize<%= isTypescriptProject ? ': typeof DataTypes' : '' %>) {
/**
* Add altering commands here.
*
Expand All @@ -11,7 +12,7 @@ module.exports = {
*/
},

async down (queryInterface, Sequelize) {
async down (queryInterface<%= isTypescriptProject ? ': QueryInterface' : '' %>, Sequelize<%= isTypescriptProject ? ': typeof DataTypes' : '' %>) {
/**
* Add reverting commands here.
*
Expand Down
10 changes: 10 additions & 0 deletions src/assets/models/connection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'use strict';
import { Sequelize } from 'sequelize';
const env = process.env.NODE_ENV || 'development';
const config = require(<%= configFile %>)[env];

const sequelizeConnection<%= isTypescriptProject ? ': Sequelize' : '' %> = config.config.use_env_variable
? new Sequelize( process.env[config.config.use_env_variable], config)
: new Sequelize(config.database, config.username, config.password, config);

module.exports = sequelizeConnection;
43 changes: 0 additions & 43 deletions src/assets/models/index.js

This file was deleted.

45 changes: 30 additions & 15 deletions src/assets/models/model.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
'use strict';

const { Model } = require('sequelize');
import { Model, DataTypes } from 'sequelize';
const sequelize = require('./connection');

module.exports = (sequelize, DataTypes) => {
class <%= name %> extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate (models) {
// define association here
}
}
<% if (isTypescriptProject) { %>
export interface <%= name %>Attributes {
<% attributes.forEach(function(attribute, index) { %>
<%= attribute.fieldName %>: <%= attribute.tsType %>;
<% }) %>
}
<% } %>

<%= name %>.init({
class <%= name %> extends Model<%= isTypescriptProject ? '<UserAttributes> implements UserAttributes' : '' %> {
<% if (isTypescriptProject) { %>
<% attributes.forEach(function(attribute, index) { %>
<%= attribute.fieldName %><%=isTypescriptProject ? `!: ${attribute.tsType}` : '' %>;
<% }) %>
<% } %>
}

<%= name %>.init({
<% attributes.forEach(function(attribute, index) { %>
<%= attribute.fieldName %>: DataTypes.<%= attribute.dataFunction ? `${attribute.dataFunction.toUpperCase()}(DataTypes.${attribute.dataType.toUpperCase()})` : attribute.dataValues ? `${attribute.dataType.toUpperCase()}(${attribute.dataValues})` : attribute.dataType.toUpperCase() %>
<%= (Object.keys(attributes).length - 1) > index ? ',' : '' %>
Expand All @@ -25,5 +30,15 @@ module.exports = (sequelize, DataTypes) => {
<%= underscored ? 'underscored: true,' : '' %>
});

return <%= name %>;
};
// Associations
// <%= name %>.belongsTo(TargetModel, {
// as: 'custom_name',
// foreignKey: {
// name: 'foreign_key_column_name',
// allowNull: false,
// },
// onDelete: "RESTRICT",
// foreignKeyConstraint: true,
// });

export default <%= name %>;
5 changes: 3 additions & 2 deletions src/assets/seeders/skeleton.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
'use strict';
<%= isTypescriptProject ? `import { QueryInterface, DataTypes } from 'sequelize';` : '' %>

/** @type {import('sequelize-cli').Migration} */
module.exports = {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think also worth export default no?

async up (queryInterface, Sequelize) {
async up (queryInterface<%= isTypescriptProject ? ': QueryInterface' : '' %>, Sequelize<%= isTypescriptProject ? ': typeof DataTypes' : '' %>) {
/**
* Add seed commands here.
*
Expand All @@ -14,7 +15,7 @@ module.exports = {
*/
},

async down (queryInterface, Sequelize) {
async down (queryInterface<%= isTypescriptProject ? ': QueryInterface' : '' %>, Sequelize<%= isTypescriptProject ? ': typeof DataTypes' : '' %>) {
/**
* Add commands to revert seed here.
*
Expand Down
2 changes: 1 addition & 1 deletion src/commands/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ function initConfig(args) {

function initModels(args) {
helpers.init.createModelsFolder(!!args.force);
helpers.init.createModelsIndexFile(!!args.force);
helpers.init.createConnectionFile(!!args.force);
}

function initMigrations(args) {
Expand Down
15 changes: 15 additions & 0 deletions src/helpers/import-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@ async function supportsDynamicImport() {
}
}

function isPackageInstalled(packageName) {
try {
// Try to require the package
require.resolve(packageName);
return true;
} catch (error) {
// If require.resolve throws an error, the package is not installed
return false;
}
}

const isTypescriptProject = isPackageInstalled('typescript');
Copy link

@shlomisas shlomisas Feb 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about having a way to decide it from the CLI? e.g. npx sequelize-cli migration:generate --name XXX --typescript and then inside each *_generate.js provide the isTypescript to the render function?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


/**
* Imports a JSON, CommonJS or ESM module
* based on feature detection.
Expand Down Expand Up @@ -39,4 +52,6 @@ async function importModule(modulePath) {
module.exports = {
supportsDynamicImport,
importModule,
isPackageInstalled,
isTypescriptProject,
};
6 changes: 3 additions & 3 deletions src/helpers/init-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ const init = {
createFolder('models', helpers.path.getModelsPath(), force);
},

createModelsIndexFile: (force) => {
createConnectionFile: (force) => {
const modelsPath = helpers.path.getModelsPath();
const indexPath = path.resolve(
modelsPath,
helpers.path.addFileExtension('index')
helpers.path.addFileExtension('connection')
);

if (!helpers.path.existsSync(modelsPath)) {
Expand All @@ -71,7 +71,7 @@ const init = {
helpers.asset.write(
indexPath,
helpers.template.render(
'models/index.js',
'models/connection.js',
{
configFile:
"__dirname + '/" + relativeConfigPath.replace(/\\/g, '/') + "'",
Expand Down
50 changes: 44 additions & 6 deletions src/helpers/model-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,27 @@ import helpers from './index';

const Sequelize = helpers.generic.getSequelize();
const validAttributeFunctionType = ['array', 'enum'];
const typescriptTypesForDbFieldTypes = {
string: 'string',
text: 'string',
uuid: 'string',
CHAR: 'string',
number: 'number',
float: 'number',
integer: 'number',
bigint: 'number',
mediumint: 'number',
tinyint: 'number',
smallint: 'number',
double: 'number',
'double precision': 'number',
real: 'number',
decimal: 'number',
date: 'data',
now: 'data',
dateonly: 'data',
boolean: 'boolean',
};

/**
* Check the given dataType actual exists.
Expand All @@ -15,6 +36,17 @@ function validateDataType(dataType) {
return dataType;
}

function getTsTypeForDbColumnType(db_type, attribute_func, values) {
db_type = db_type.toLowerCase();
if (attribute_func === 'array') {
return `${typescriptTypesForDbFieldTypes[db_type]}[]`;
} else if (attribute_func === 'enum') {
return values.join(' | ');
}

return typescriptTypesForDbFieldTypes[db_type] || 'any';
}

function formatAttributes(attribute) {
let result;
const split = attribute.split(':');
Expand All @@ -24,10 +56,13 @@ function formatAttributes(attribute) {
fieldName: split[0],
dataType: split[1],
dataFunction: null,
tsType: getTsTypeForDbColumnType(split[1]),
dataValues: null,
};
} else if (split.length === 3) {
const validValues = /^\{(,? ?[A-z0-9 ]+)+\}$/;
const validValues =
/^\{((('[A-z0-9 ]+')|("[A-z0-9 ]+")|([A-z0-9 ]+)))(, ?(('[A-z0-9 ]+')|("[A-z0-9 ]+")|([A-z0-9 ]+)))*\}$/;

Check failure

Code scanning / CodeQL

Inefficient regular expression

This part of the regular expression may cause exponential backtracking on strings starting with '{{ ,' and containing many repetitions of ' ,'.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's a false positive, @WikiRik can you please dismiss this alert?

Check warning

Code scanning / CodeQL

Overly permissive regular expression range

Suspicious character range that is equivalent to \[A-Z\\[\\\\]^_`a-z\].

Check warning

Code scanning / CodeQL

Overly permissive regular expression range

Suspicious character range that is equivalent to \[A-Z\\[\\\\]^_`a-z\].

Check warning

Code scanning / CodeQL

Overly permissive regular expression range

Suspicious character range that is equivalent to \[A-Z\\[\\\\]^_`a-z\].

Check warning

Code scanning / CodeQL

Overly permissive regular expression range

Suspicious character range that is equivalent to \[A-Z\\[\\\\]^_`a-z\].

Check warning

Code scanning / CodeQL

Overly permissive regular expression range

Suspicious character range that is equivalent to \[A-Z\\[\\\\]^_`a-z\].

Check warning

Code scanning / CodeQL

Overly permissive regular expression range

Suspicious character range that is equivalent to \[A-Z\\[\\\\]^_`a-z\].

const isValidFunction =
validAttributeFunctionType.indexOf(split[1].toLowerCase()) !== -1;
const isValidValue =
Expand All @@ -40,20 +75,23 @@ function formatAttributes(attribute) {
fieldName: split[0],
dataType: split[2],
dataFunction: split[1],
tsType: getTsTypeForDbColumnType(split[2], split[1]),
dataValues: null,
};
}

if (isValidFunction && !isValidValue && isValidValues) {
const values = split[2]
.replace(/(^\{|\}$)/g, '')
.split(/\s*,\s*/)
.map((s) => (s.startsWith('"') || s.startsWith("'") ? s : `'${s}'`));

result = {
fieldName: split[0],
dataType: split[1],
tsType: getTsTypeForDbColumnType(split[2], split[1], values),
dataFunction: null,
dataValues: split[2]
.replace(/(^\{|\}$)/g, '')
.split(/\s*,\s*/)
.map((s) => `'${s}'`)
.join(', '),
dataValues: values.join(', '),
};
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/helpers/path-helper.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import path from 'path';
import fs from 'fs';
import process from 'process';
import { isTypescriptProject } from './import-helper';

const resolve = require('resolve').sync;
import getYArgs from '../core/yargs';
Expand Down Expand Up @@ -45,7 +46,7 @@ module.exports = {
},

getFileExtension() {
return 'js';
return isTypescriptProject ? 'ts' : 'js';
},

addFileExtension(basename, options) {
Expand Down
4 changes: 4 additions & 0 deletions src/helpers/template-helper.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import _ from 'lodash';
import beautify from 'js-beautify';
import helpers from './index';
import { isTypescriptProject } from './import-helper';

module.exports = {
render(path, locals, options) {
Expand All @@ -14,6 +15,9 @@ module.exports = {
);

const template = helpers.asset.read(path);
locals = locals || {};
locals['isTypescriptProject'] = isTypescriptProject;

let content = _.template(template)(locals || {});

if (options.beautify) {
Expand Down
4 changes: 4 additions & 0 deletions src/sequelize.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#!/usr/bin/env node

import getYArgs from './core/yargs';
import { isTypescriptProject } from './helpers/import-helper';

// enable typescript compatibility if project is based on typescript
if (isTypescriptProject) require('ts-node/register');

const yargs = getYArgs();

Expand Down
Loading