forked from Yara724/api
116 lines
3.0 KiB
TypeScript
116 lines
3.0 KiB
TypeScript
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);
|
||
});
|
||
});
|
||
}
|