@medyll/idae-api 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
File without changes
@@ -0,0 +1,10 @@
1
+ export declare class ApiServe {
2
+ private app;
3
+ private port;
4
+ constructor(port?: number, mdbPort?: number, mdbName?: string);
5
+ private configureMiddleware;
6
+ private getDynamicModel;
7
+ private getCollectionName;
8
+ private configureRoutes;
9
+ start(): void;
10
+ }
@@ -0,0 +1,113 @@
1
+ // ServerConfig.ts
2
+ import express, {} from 'express';
3
+ import DBaseService from './engine/DBaseService.js';
4
+ import DatabaseManager from './engine/DBaseManager.js';
5
+ import mongoose, { Schema, Model, Document } from 'mongoose';
6
+ export class ApiServe {
7
+ constructor(port = 3000, mdbPort = 27017, mdbName = 'idae') {
8
+ this.app = express();
9
+ this.port = port;
10
+ this.configureMiddleware();
11
+ this.configureRoutes();
12
+ }
13
+ configureMiddleware() {
14
+ this.app.use(express.json());
15
+ }
16
+ getDynamicModel(collectionName) {
17
+ if (mongoose.models[collectionName]) {
18
+ return mongoose.models[collectionName];
19
+ }
20
+ const schema = new Schema({}, { strict: false });
21
+ return mongoose.model(collectionName, schema, collectionName);
22
+ }
23
+ getCollectionName(collectionName) {
24
+ let dbName, collection;
25
+ if (collectionName.includes('.')) {
26
+ [dbName, collection] = collectionName.split('.');
27
+ }
28
+ else {
29
+ collection = collectionName;
30
+ }
31
+ return collection;
32
+ }
33
+ configureRoutes() {
34
+ this.app.use('/:collectionName', DatabaseManager.connectToDatabase);
35
+ this.app.get('/:collectionName', async (req, res) => {
36
+ try {
37
+ const { collectionName } = req.params;
38
+ const collection = this.getCollectionName(collectionName);
39
+ const databaseService = new DBaseService(collection);
40
+ const documents = await databaseService.findAll(req.query);
41
+ res.send(documents);
42
+ }
43
+ catch (error) {
44
+ res.status(500).send(error);
45
+ }
46
+ });
47
+ this.app.get('/:collectionName/:id', async (req, res) => {
48
+ try {
49
+ const { collectionName, id } = req.params;
50
+ const collection = this.getCollectionName(collectionName);
51
+ const databaseService = new DBaseService(collection);
52
+ const document = await databaseService.findById(id);
53
+ if (!document) {
54
+ return res.status(404).send({ error: 'Document not found' });
55
+ }
56
+ res.send(document);
57
+ }
58
+ catch (error) {
59
+ res.status(500).send(error);
60
+ }
61
+ });
62
+ this.app.delete('/:collectionName/:id', async (req, res) => {
63
+ try {
64
+ const { collectionName, id } = req.params;
65
+ const collection = this.getCollectionName(collectionName);
66
+ const databaseService = new DBaseService(collection);
67
+ const result = await databaseService.deleteById(id);
68
+ res.send(result);
69
+ }
70
+ catch (error) {
71
+ res.status(500).send(error);
72
+ }
73
+ });
74
+ this.app.delete('/:collectionName/', async (req, res) => {
75
+ try {
76
+ const { collectionName } = req.params;
77
+ const collection = this.getCollectionName(collectionName);
78
+ const databaseService = new DBaseService(collection);
79
+ const result = await databaseService.deleteManyByQuery(req.query);
80
+ res.send(result);
81
+ }
82
+ catch (error) {
83
+ res.status(500).send(error);
84
+ }
85
+ });
86
+ const directCommands = ['findAll', 'create', 'update', 'deleteById', 'deleteManyByQuery'];
87
+ this.app.all('/:collectionName/:command/:params?', async (req, res) => {
88
+ try {
89
+ const { collectionName, command, params } = req.params;
90
+ const collection = this.getCollectionName(collectionName);
91
+ if (!directCommands.includes(command)) {
92
+ return res.status(400).send({ error: 'Command not supported' });
93
+ }
94
+ const databaseService = new DBaseService(collection);
95
+ const decodedParams = params ? databaseService.decodeUrlParams(params) : {};
96
+ const result = await databaseService[command](decodedParams);
97
+ res.status(200).send(result);
98
+ }
99
+ catch (error) {
100
+ res.status(400).send({ error: error.message });
101
+ }
102
+ });
103
+ }
104
+ start() {
105
+ this.app.listen(this.port, () => {
106
+ console.log(`Server is running on port: ${this.port}`);
107
+ });
108
+ }
109
+ }
110
+ // Usage:
111
+ // import { ServerConfig } from './ServerConfig.js';
112
+ //const server = new ApiServer(3050);
113
+ //server.start();
@@ -0,0 +1,15 @@
1
+ import type { Request, Response, NextFunction } from 'express';
2
+ declare const defaultDbName: string;
3
+ declare class DBaseManager {
4
+ private static instance;
5
+ static port: number;
6
+ constructor();
7
+ static getInstance(): DBaseManager;
8
+ connectToDatabase(req: Request<{
9
+ dbName: string;
10
+ collectionName: string;
11
+ }>, res: Response, next: NextFunction): Promise<void>;
12
+ }
13
+ declare const _default: DBaseManager;
14
+ export default _default;
15
+ export { DBaseManager as DatabaseManager, defaultDbName };
@@ -0,0 +1,49 @@
1
+ import mongoose from 'mongoose';
2
+ const defaultDbName = 'idae';
3
+ // this is my middleware to connect to the appropriate database
4
+ class DBaseManager {
5
+ constructor() { }
6
+ static getInstance() {
7
+ if (!DBaseManager.instance) {
8
+ DBaseManager.instance = new DBaseManager();
9
+ }
10
+ return DBaseManager.instance;
11
+ }
12
+ async connectToDatabase(req, res, next) {
13
+ const { collectionName } = req.params;
14
+ let dbName;
15
+ //
16
+ if (collectionName.includes('.')) {
17
+ dbName = collectionName.split('.')[0];
18
+ }
19
+ else {
20
+ dbName = defaultDbName;
21
+ }
22
+ const dbUri = `mongodb://localhost:${DBaseManager.port}/${dbName}`;
23
+ try {
24
+ if (!mongoose.connection.readyState) {
25
+ await mongoose.connect(dbUri, {
26
+ autoIndex: true,
27
+ dbName
28
+ });
29
+ }
30
+ else if (mongoose.connection.name !== dbName) {
31
+ await mongoose.disconnect();
32
+ await mongoose.connect(dbUri, {
33
+ autoIndex: true,
34
+ dbName
35
+ });
36
+ }
37
+ console.log('connected to db', `${dbName}`);
38
+ next();
39
+ }
40
+ catch (error) {
41
+ /** @ts-ignore */
42
+ res.status(500).send(`Failed to connect to database ${dbName}: ${error.message}`);
43
+ }
44
+ }
45
+ }
46
+ DBaseManager.port = 27017;
47
+ // i can call it as a normal class or as a singleton
48
+ export default DBaseManager.getInstance();
49
+ export { DBaseManager as DatabaseManager, defaultDbName };
@@ -0,0 +1,16 @@
1
+ import { Document } from 'mongoose';
2
+ import { type RequestParams } from './types';
3
+ declare class DBaseService {
4
+ private model;
5
+ constructor(collection: string);
6
+ create(document: any): Promise<Document>;
7
+ findAll(params: RequestParams): Promise<Document[]>;
8
+ findById(id: string): Promise<Document | null>;
9
+ findOne(params: RequestParams): Promise<Document | null>;
10
+ deleteById(id: string): Promise<Document | null>;
11
+ deleteManyByQuery(params: RequestParams): Promise<{
12
+ deletedCount?: number;
13
+ }>;
14
+ decodeUrlParams(urlParams: string): RequestParams;
15
+ }
16
+ export default DBaseService;
@@ -0,0 +1,48 @@
1
+ import { Model, Document } from 'mongoose';
2
+ import { getModel } from './tools';
3
+ import {} from './types';
4
+ class DBaseService {
5
+ constructor(collection) {
6
+ this.model = getModel(collection);
7
+ }
8
+ async create(document) {
9
+ const newDocument = new this.model(document);
10
+ return newDocument.save();
11
+ }
12
+ async findAll(params) {
13
+ const sortOptions = {};
14
+ if (params.sortBy) {
15
+ const sortFields = params.sortBy.split(',');
16
+ sortFields.forEach((field) => {
17
+ const [key, order] = field.split(':');
18
+ sortOptions[key] = order === 'desc' ? -1 : 1;
19
+ });
20
+ }
21
+ return this.model.find().sort(sortOptions);
22
+ }
23
+ async findById(id) {
24
+ return this.model.findById(id);
25
+ }
26
+ async findOne(params) {
27
+ return this.model.findOne(params.query);
28
+ }
29
+ async deleteById(id) {
30
+ return this.model.findByIdAndDelete(id);
31
+ }
32
+ async deleteManyByQuery(params) {
33
+ return this.model.deleteMany(params.query);
34
+ }
35
+ decodeUrlParams(urlParams) {
36
+ const params = {};
37
+ const urlParamsArray = urlParams.split('&');
38
+ urlParamsArray.forEach((param) => {
39
+ const [key, value] = param.split('=');
40
+ if (key && value) {
41
+ /** @ts-ignore */
42
+ params[key] = JSON.parse(decodeURIComponent(value));
43
+ }
44
+ });
45
+ return params;
46
+ }
47
+ }
48
+ export default DBaseService;
@@ -0,0 +1,2 @@
1
+ import { Document, Model } from "mongoose";
2
+ export declare const getModel: (collectionName: string) => Model<Document>;
@@ -0,0 +1,11 @@
1
+ import mongoose, { Schema, Document, Model } from "mongoose";
2
+ import AutoIncrementFactory from "mongoose-sequence";
3
+ const AutoIncrement = AutoIncrementFactory(mongoose);
4
+ export const getModel = (collectionName) => {
5
+ if (mongoose.models[collectionName]) {
6
+ return mongoose.models[collectionName];
7
+ }
8
+ const schema = new Schema({}, { strict: false });
9
+ schema.plugin(AutoIncrement, { inc_field: "idFieldName" });
10
+ return mongoose.model(collectionName, schema, collectionName);
11
+ };
@@ -0,0 +1,9 @@
1
+ export interface RequestParams {
2
+ id?: string;
3
+ query?: any;
4
+ sortBy?: string;
5
+ body?: any;
6
+ }
7
+ export interface SortOptions {
8
+ [key: string]: 1 | -1;
9
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export { ApiServe } from './ApiServe.js';
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ // Reexport your entry components here
2
+ export { ApiServe } from './ApiServe.js';
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@medyll/idae-api",
3
+ "scope": "@medyll",
4
+ "version": "0.0.1",
5
+ "scripts": {
6
+ "dev": "vite dev",
7
+ "build": "vite build && npm run package",
8
+ "preview": "vite preview",
9
+ "package": "svelte-kit sync && svelte-package && publint",
10
+ "prepublishOnly": "npm run package",
11
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
12
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
13
+ "test": "vitest",
14
+ "lint": "prettier --check . && eslint .",
15
+ "format": "prettier --write ."
16
+ },
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "svelte": "./dist/index.js"
21
+ }
22
+ },
23
+ "files": [
24
+ "dist",
25
+ "!dist/**/*.test.*",
26
+ "!dist/**/*.spec.*"
27
+ ],
28
+ "dependencies": {
29
+ "express": "^4.19.2",
30
+ "mongoose-sequence": "^6.0.1"
31
+ },
32
+ "peerDependencies": {
33
+ "svelte": "^4.0.0 || ^5.0.0"
34
+ },
35
+ "devDependencies": {
36
+ "@sveltejs/adapter-auto": "^3.0.0",
37
+ "@sveltejs/kit": "^2.0.0",
38
+ "@sveltejs/package": "^2.0.0",
39
+ "@sveltejs/vite-plugin-svelte": "^3.0.0",
40
+ "@types/eslint": "^8.56.7",
41
+ "@types/express": "^4.17.21",
42
+ "@types/mongoose": "^5.11.97",
43
+ "eslint": "^9.0.0",
44
+ "eslint-config-prettier": "^9.1.0",
45
+ "eslint-plugin-svelte": "^2.36.0",
46
+ "globals": "^15.0.0",
47
+ "prettier": "^3.1.1",
48
+ "prettier-plugin-svelte": "^3.1.2",
49
+ "publint": "^0.1.9",
50
+ "svelte": "^5.0.0-next.181",
51
+ "svelte-check": "^3.6.0",
52
+ "tslib": "^2.4.1",
53
+ "tsx": "^4.16.2",
54
+ "typescript": "^5.0.0",
55
+ "typescript-eslint": "^8.0.0-alpha.20",
56
+ "vite": "^5.0.11",
57
+ "vitest": "^1.2.0"
58
+ },
59
+ "svelte": "./dist/index.js",
60
+ "types": "./dist/index.d.ts",
61
+ "type": "module"
62
+ }