Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf

.idea*
# AWS User-specific
.idea/**/aws.xml

Expand Down
122 changes: 70 additions & 52 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
# Changelog

## v1.2.1 - 27 Apr, 2025
## [1.2.2] - 2025-04-29

### Added

- TypeScript support with type definitions (index.d.ts)
- Comprehensive JSDoc comments for better code documentation

### Changed

- Updated all dependencies to latest compatible versions
- Enhanced JSON response formatting for errors

### Fixed

- Connection cleanup on errors
- Schema registration to avoid duplicates
- Central domain validation logic

## [1.2.1] - 2025-04-29

### Features

Expand Down Expand Up @@ -31,7 +49,7 @@ const connection = await queue.connect('redis://test:test@redis.test');

---

## v1.2.0 - 16 Apr, 2025
## [1.2.0] - 2025-04-16

### Features

Expand All @@ -44,7 +62,7 @@ const connection = await queue.connect('redis://test:test@redis.test');

---

## v1.1.0 - 16 Mar, 2025
## [1.1.0] - 2025-03-16

Adding jest tests and some code improvements to queue connection.

Expand All @@ -66,54 +84,54 @@ queueClass.publishMessage('support_test', {'message': 'test'}, true);
const {queue, config} = require('node-tenancy');

function setConnectionConfig(is_tenant_connection) {
if (is_tenant_connection) {
config.setConfig({
'connection': 'tenant',
});
} else {
config.setConfig({
'connection': 'central',
});
}
if (is_tenant_connection) {
config.setConfig({
'connection': 'tenant',
});
} else {
config.setConfig({
'connection': 'central',
});
}
}

async function getMessages(queue_name, is_tenant_connection = false) {
setConnectionConfig(is_tenant_connection);

const conn = await queue.connect(queue.getConnectionUrl());
const channel = await conn.createChannel();

await channel.assertQueue(queue_name);

channel.consume(queue_name, async (msg) => {
if (msg !== null) {
console.log('Received:', msg.content.toString());
channel.ack(msg);
} else {
console.log('Consumer cancelled by server');
}
await channel.close();
await conn.close();
});
setConnectionConfig(is_tenant_connection);

const conn = await queue.connect(queue.getConnectionUrl());
const channel = await conn.createChannel();

await channel.assertQueue(queue_name);

channel.consume(queue_name, async (msg) => {
if (msg !== null) {
console.log('Received:', msg.content.toString());
channel.ack(msg);
} else {
console.log('Consumer cancelled by server');
}
await channel.close();
await conn.close();
});
}

async function publishMessage(queue_name, message, is_tenant_connection = false) {
setConnectionConfig(is_tenant_connection);

const conn = await queue.connect(queue.getConnectionUrl());
const channel = await conn.createChannel();
channel.sendToQueue(queue_name, Buffer.from(JSON.stringify(message)));
setTimeout(function () {
conn.close();
}, 500);
setConnectionConfig(is_tenant_connection);

const conn = await queue.connect(queue.getConnectionUrl());
const channel = await conn.createChannel();
channel.sendToQueue(queue_name, Buffer.from(JSON.stringify(message)));
setTimeout(function () {
conn.close();
}, 500);
}

module.exports = {getMessages, publishMessage};
```

---

## v1.0.4 - 7 Mar, 2025
## [1.0.4] - 2025-03-07

### File Structure

Expand All @@ -129,23 +147,23 @@ errors you might get with v1.0.4***
const {queue} = require('node-tenancy');

queue.connect(queue.getConnectionUrl(), function (connectionErr, connection) {
if (connectionErr) {
console.log(connectionErr);
}
connection.createChannel(function (channelErr, channel) {
if (channelErr) {
console.log(channelErr);
if (connectionErr) {
console.log(connectionErr);
}
connection.createChannel(function (channelErr, channel) {
if (channelErr) {
console.log(channelErr);
}

const queue = 'test';
const queue = 'test';

channel.assertQueue(queue, {
durable: true
});
channel.assertQueue(queue, {
durable: true
});

channel.consume(queue, function (msg) {
console.log(msg);
});
})
channel.consume(queue, function (msg) {
console.log(msg);
});
})
});
```
44 changes: 40 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Trying to make it like [Tenancy for Laravel](https://tenancyforlaravel.com)
- [Queue](#2-queue-connection)
- [Mongoose Usage](#3-using-mongoose)
- [Sql Usage](#4-using-sql-with-sequelize)
- [TypeScript Support](#typescript-support)
- [CHANGELOG](CHANGELOG.md) (for latest updates and changes)

## Support
Expand Down Expand Up @@ -68,7 +69,7 @@ const tenancy = require('node-tenancy');
router.use(tenancy.initializeTenancyMiddleware);

router.get('/get', function (Request, Response) {
return Response.status(200).json("Hello");
return Response.status(200).json("Hello");
});
```

Expand All @@ -82,9 +83,9 @@ const tenancy = require('node-tenancy');
router.use(tenancy.initializeCentralMiddleware);

router.get('/get', function (Request, Response) {
return Response.status(200).json({
'tenant_id': tenancy.config.getConfig().tenant_id
});
return Response.status(200).json({
'tenant_id': tenancy.config.getConfig().tenant_id
});
});
```

Expand Down Expand Up @@ -119,3 +120,38 @@ Read more about it here [Sequelize guide](docs/SQL.md).

**In case you are using mongodb we assume that domains is an array inside
tenants collection**

## TypeScript Support

Tenancy now includes TypeScript type definitions. Example usage:

```typescript
import {config, TenantSchema, db} from 'node-tenancy';
import {Schema} from 'mongoose';

// Define schemas with TypeScript types
interface User {
username: string;
email: string;
active: boolean;
createdAt: Date;
}

const userSchema = new Schema<User>({
username: String,
email: {type: String, required: true},
active: {type: Boolean, default: true},
createdAt: {type: Date, default: Date.now}
});

// Configure tenancy
config.setConfig({
central_domains: ["admin.myapp.com"],
tenant_schemas: {
"User": userSchema
},
central_schemas: {
"Tenant": TenantSchema
}
});
```
74 changes: 74 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Type definitions for node-tenancy
// Project: https://github.com/johnabil/tenancy
// Definitions by: node-tenancy team

import { Schema, Connection, Model } from 'mongoose';
import { Sequelize, ModelOptions } from 'sequelize';

declare namespace NodeTenancy {
/**
* Configuration interface
*/
interface Config {
setConfig(config: ConfigOptions): void;
getConfig(): ConfigOptions;
}

/**
* Configuration options
*/
interface ConfigOptions {
connection?: string;
central_domains?: string[];
tenant_id?: string;
tenant_name?: string;
tenant_connection?: Connection | Sequelize;
central_connection?: Connection | Sequelize;
queue_connection?: string;
tenant_schemas?: Record<string, Schema> | Array<(sequelize: Sequelize) => any>;
central_schemas?: Record<string, Schema> | Array<(sequelize: Sequelize) => any>;
db_options?: Record<string, any>;
}

/**
* Database utility functions
*/
interface DatabaseUtils {
getDriverClass(): any;
resolveTenantConnection(connection: string, db_name: string, options?: object): Connection | Sequelize;
resolveCentralConnection(options?: object): Connection | Sequelize;
registerSchemas(connection: Connection | Sequelize, schemas: Record<string, Schema> | Array<(sequelize: Sequelize) => any>): void;
getModel(model_name: string): Model<any> | any;
getDefaultTenantSchema(): Schema | ((sequelize: Sequelize) => any);
}

/**
* Queue utility functions
*/
interface QueueUtils {
getConnectionUrl(): string;
connect(url?: string, options?: object): Promise<any>;
}

/**
* Express middleware function
*/
type Middleware = (req: any, res: any, next: any) => void | Promise<void>;

/**
* Main module interface
*/
interface NodeTenancy {
config: Config;
db: DatabaseUtils;
queue: QueueUtils;
TenantSchema: Schema;
DomainSchema: (sequelize: Sequelize) => any;
initializeTenancyMiddleware: Middleware;
initializeCentralMiddleware: Middleware;
}
}

declare const nodeTenancy: NodeTenancy.NodeTenancy;

export = nodeTenancy;
32 changes: 23 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading