@developers-joyride/shortify
Version:
High performance URL shortener library with multi-database support (MongoDB, SQLite, PostgreSQL, MySQL)
178 lines (177 loc) • 6.84 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MongoAdapter = void 0;
const mongoose_1 = __importDefault(require("mongoose"));
const events_1 = require("events");
class MongoAdapter extends events_1.EventEmitter {
constructor(config) {
super();
this.retryCount = 0;
this._isConnected = false;
this.mongoUri = config.mongoUri;
this.maxRetries = config.maxRetries || 5;
this.retryDelay = config.retryDelay || 5000;
this.collectionName = config.collectionName || "urls";
// Configure mongoose for high performance
mongoose_1.default.set("strictQuery", true);
}
async connect() {
try {
if (this._isConnected) {
return true;
}
// Optimized connection options for high throughput
await mongoose_1.default.connect(this.mongoUri, {
serverSelectionTimeoutMS: 5000,
maxPoolSize: 100, // Increased connection pool for high throughput
});
this._isConnected = true;
this.retryCount = 0;
this.emit("connected");
// Handle connection events
mongoose_1.default.connection.on("error", (err) => {
console.error("MongoDB connection error:", err);
this._isConnected = false;
this.emit("error", err);
this.retryConnection();
});
mongoose_1.default.connection.on("disconnected", () => {
this._isConnected = false;
this.emit("disconnected");
this.retryConnection();
});
return true;
}
catch (error) {
console.error("Failed to connect to MongoDB:", error);
this.emit("error", error);
return this.retryConnection();
}
}
retryConnection() {
if (this.retryCount < this.maxRetries) {
this.retryCount++;
// Exponential backoff
const delay = this.retryDelay * Math.pow(2, this.retryCount - 1);
console.log(`Retrying MongoDB connection in ${delay}ms (attempt ${this.retryCount}/${this.maxRetries})`);
setTimeout(() => {
this.connect();
}, delay);
return true;
}
else {
this.emit("maxRetriesReached");
return false;
}
}
async disconnect() {
if (mongoose_1.default.connection.readyState !== 0) {
await mongoose_1.default.disconnect();
this._isConnected = false;
this.emit("disconnected");
}
}
isConnected() {
return this._isConnected;
}
async createUrl(url) {
const { createUrlModel } = await Promise.resolve().then(() => __importStar(require("../models/url.model")));
const UrlModel = createUrlModel(this.collectionName);
const newUrl = new UrlModel({
urlId: url.urlId,
originalUrl: url.originalUrl,
shortUrl: url.shortUrl,
clicks: url.clicks,
expiresAt: url.expiresAt,
});
const savedUrl = await newUrl.save();
return {
urlId: savedUrl.urlId,
originalUrl: savedUrl.originalUrl,
shortUrl: savedUrl.shortUrl,
clicks: savedUrl.clicks,
createdAt: savedUrl.createdAt,
expiresAt: savedUrl.expiresAt,
};
}
async findUrlByUrlId(urlId) {
const { createUrlModel } = await Promise.resolve().then(() => __importStar(require("../models/url.model")));
const UrlModel = createUrlModel(this.collectionName);
const url = await UrlModel.findOne({ urlId }).exec();
if (!url) {
return null;
}
return {
urlId: url.urlId,
originalUrl: url.originalUrl,
shortUrl: url.shortUrl,
clicks: url.clicks,
createdAt: url.createdAt,
expiresAt: url.expiresAt,
};
}
async findUrlByOriginalUrl(originalUrl) {
const { createUrlModel } = await Promise.resolve().then(() => __importStar(require("../models/url.model")));
const UrlModel = createUrlModel(this.collectionName);
const url = await UrlModel.findOne({ originalUrl }).exec();
if (!url) {
return null;
}
return {
urlId: url.urlId,
originalUrl: url.originalUrl,
shortUrl: url.shortUrl,
clicks: url.clicks,
createdAt: url.createdAt,
expiresAt: url.expiresAt,
};
}
async updateUrlClicks(urlId, clicks) {
const { createUrlModel } = await Promise.resolve().then(() => __importStar(require("../models/url.model")));
const UrlModel = createUrlModel(this.collectionName);
await UrlModel.updateOne({ urlId }, { clicks });
}
async deleteUrl(urlId) {
const { createUrlModel } = await Promise.resolve().then(() => __importStar(require("../models/url.model")));
const UrlModel = createUrlModel(this.collectionName);
const result = await UrlModel.deleteOne({ urlId });
return result.deletedCount > 0;
}
}
exports.MongoAdapter = MongoAdapter;