@replyke/express
Version:
Replyke: Build interactive apps with social features like comments, votes, feeds, user lists, notifications, and more.
195 lines (194 loc) • 7.03 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const sequelize_1 = require("sequelize");
const Entity_1 = __importDefault(require("./Entity"));
const User_1 = __importDefault(require("./User"));
const Report_1 = __importDefault(require("./Report"));
class Comment extends sequelize_1.Model {
static initModel(sequelize) {
Comment.init({
id: {
type: sequelize_1.DataTypes.UUID,
defaultValue: sequelize_1.DataTypes.UUIDV4,
primaryKey: true,
allowNull: false,
},
projectId: {
type: sequelize_1.DataTypes.UUID,
allowNull: false,
},
userId: {
type: sequelize_1.DataTypes.UUID,
allowNull: false,
},
referenceId: {
type: sequelize_1.DataTypes.STRING,
allowNull: true,
},
foreignId: {
type: sequelize_1.DataTypes.STRING,
allowNull: true,
},
entityId: {
type: sequelize_1.DataTypes.UUID,
allowNull: false,
},
parentId: {
type: sequelize_1.DataTypes.UUID,
allowNull: true,
},
content: {
type: sequelize_1.DataTypes.TEXT,
allowNull: true,
},
gif: {
type: sequelize_1.DataTypes.JSON,
allowNull: true,
},
mentions: {
type: sequelize_1.DataTypes.ARRAY(sequelize_1.DataTypes.JSONB),
allowNull: false,
defaultValue: [],
},
upvotes: {
type: sequelize_1.DataTypes.ARRAY(sequelize_1.DataTypes.UUID),
allowNull: false,
defaultValue: [],
},
downvotes: {
type: sequelize_1.DataTypes.ARRAY(sequelize_1.DataTypes.UUID),
allowNull: false,
defaultValue: [],
},
parentDeletedAt: {
type: sequelize_1.DataTypes.DATE,
allowNull: true,
},
referencedCommentId: {
type: sequelize_1.DataTypes.UUID,
allowNull: true,
},
attachments: {
type: sequelize_1.DataTypes.ARRAY(sequelize_1.DataTypes.JSONB),
allowNull: false,
defaultValue: [],
},
metadata: {
type: sequelize_1.DataTypes.JSONB,
allowNull: false,
defaultValue: {},
validate: {
notTooLarge(value) {
const MAX_SIZE = 10240; // 10 KB
if (value !== null) {
const size = Buffer.byteLength(JSON.stringify(value), "utf8");
if (size > MAX_SIZE) {
throw new Error(`Metadata exceeds the size limit of ${MAX_SIZE} bytes.`);
}
}
},
},
},
createdAt: {
type: sequelize_1.DataTypes.DATE,
allowNull: false,
defaultValue: sequelize_1.DataTypes.NOW,
},
updatedAt: {
type: sequelize_1.DataTypes.DATE,
allowNull: false,
defaultValue: sequelize_1.DataTypes.NOW,
},
deletedAt: {
type: sequelize_1.DataTypes.DATE,
allowNull: true,
},
}, {
sequelize,
modelName: "Comment",
tableName: "Comments",
timestamps: false,
paranoid: true,
indexes: [
{
fields: ["projectId"],
},
{
fields: ["entityId"],
},
{
fields: ["parentId"],
},
// make the comment‐count scan index‐only
{
name: "idx_comments_active",
fields: ["entityId"],
where: {
deletedAt: null,
parentDeletedAt: null,
},
},
{
name: "idx_comments_active_parent",
fields: ["parentId"],
where: {
deletedAt: null,
parentDeletedAt: null,
},
},
{
name: "idx_comments_list",
fields: [
{ name: "projectId" },
{ name: "entityId" },
{ name: "createdAt", order: "DESC" },
],
where: {
deletedAt: null,
},
},
],
});
// On update: only overwrite updatedAt *if* the user didn’t explicitly set it.
Comment.beforeUpdate((inst) => {
if (!inst.changed("updatedAt")) {
inst.setDataValue("updatedAt", new Date());
}
});
}
/**
* Define associations to other models
*/
static associate() {
Comment.belongsTo(Entity_1.default, {
foreignKey: "entityId",
onDelete: "CASCADE", // Ensures each Comment belongs to an Entity
as: "entity", // Define the alias here
});
// We don't cascade delete comments when users are remove to keep conversation integrity. We will just not show the user if there is no one
Comment.belongsTo(User_1.default, {
foreignKey: "userId",
as: "user", // Define the alias here
});
// Self-referential relationship between Comment and itself
// We don't cascade deletion. Currently, if a comment is deleted, the replies are not deleted.
Comment.hasMany(Comment, {
foreignKey: "parentId", // This field refers to the parent comment
as: "replies", // Alias for the relation
});
Comment.belongsTo(Comment, {
foreignKey: "parentId", // Reference to the parent comment
as: "parentComment", // Alias for the parent folder relation
});
Comment.hasMany(Report_1.default, {
foreignKey: "targetId",
constraints: false,
onDelete: "CASCADE",
scope: { targetType: "Comment" }, // Ensures this association only applies to Reports for Comments
});
}
}
exports.default = Comment;