1
0
forked from Yara724/api
Files
yara724-api/src/helpers/mongoose-fa-timestamps.plugin.ts
2026-04-22 10:35:00 +03:30

116 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Connection, Query, Schema } from "mongoose";
const PERSIAN_TO_ENGLISH: Record<string, string> = {
"۰": "0",
"۱": "1",
"۲": "2",
"۳": "3",
"۴": "4",
"۵": "5",
"۶": "6",
"۷": "7",
"۸": "8",
"۹": "9",
};
function normalizeDigits(value: string): string {
return value.replace(/[۰-۹]/g, (ch) => PERSIAN_TO_ENGLISH[ch] ?? ch);
}
function toIranFaDateTimeTuple(input: Date): [string, string] {
const dateFa = normalizeDigits(
input.toLocaleDateString("fa-IR", {
timeZone: "Asia/Tehran",
year: "numeric",
month: "2-digit",
day: "2-digit",
}),
);
const timeFa = normalizeDigits(
input.toLocaleTimeString("fa-IR", {
timeZone: "Asia/Tehran",
hour12: false,
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
}),
);
return [dateFa, timeFa];
}
function isMissingFaTuple(value: unknown): boolean {
if (value == null) return true;
if (!Array.isArray(value)) return false;
if (value.length < 2) return true;
const [d, t] = value;
return !d || !t;
}
function writeFaTimestampsOnUpdate(query: Query<any, any>): void {
const nowFa = toIranFaDateTimeTuple(new Date());
const update = (query.getUpdate() ?? {}) as Record<string, any>;
if (!update.$set || typeof update.$set !== "object") {
update.$set = {};
}
update.$set.updatedAtFa = nowFa;
// Keep createdAtFa immutable on regular updates; set only for upsert inserts.
const opts = (query as any).getOptions?.() ?? {};
if (opts.upsert) {
if (!update.$setOnInsert || typeof update.$setOnInsert !== "object") {
update.$setOnInsert = {};
}
if (isMissingFaTuple(update.$setOnInsert.createdAtFa)) {
update.$setOnInsert.createdAtFa = nowFa;
}
}
query.setUpdate(update);
}
/**
* Adds `createdAtFa` / `updatedAtFa` (Iran timezone tuple: [date, time])
* to all schemas that use mongoose timestamps.
*/
export function applyIranFaTimestampPlugin(connection: Connection): void {
connection.plugin((schema: Schema) => {
const timestamps = schema.get("timestamps");
if (!timestamps) return;
schema.add({
createdAtFa: { type: [String], index: true },
updatedAtFa: { type: [String], index: true },
});
schema.pre("save", function (next) {
const nowFa = toIranFaDateTimeTuple(new Date());
if (isMissingFaTuple((this as any).createdAtFa)) {
(this as any).createdAtFa = nowFa;
}
(this as any).updatedAtFa = nowFa;
next();
});
schema.pre("insertMany", function (next, docs: any[]) {
const nowFa = toIranFaDateTimeTuple(new Date());
for (const doc of docs) {
if (isMissingFaTuple(doc.createdAtFa)) doc.createdAtFa = nowFa;
doc.updatedAtFa = nowFa;
}
next();
});
schema.pre("findOneAndUpdate", function () {
writeFaTimestampsOnUpdate(this);
});
schema.pre("updateOne", function () {
writeFaTimestampsOnUpdate(this);
});
schema.pre("updateMany", function () {
writeFaTimestampsOnUpdate(this);
});
});
}