typeorm-adapter
Advanced tools
Comparing version
import { Model, FilteredAdapter } from 'casbin'; | ||
import { Connection, ConnectionOptions } from 'typeorm'; | ||
import { CasbinRule } from './casbinRule'; | ||
import { DataSource, DataSourceOptions, FindOptionsWhere } from 'typeorm'; | ||
import { CasbinMongoRule } from './casbinMongoRule'; | ||
declare type GenericCasbinRule = CasbinRule | CasbinMongoRule; | ||
declare type CasbinRuleConstructor = new (...args: any[]) => GenericCasbinRule; | ||
interface ExistentConnection { | ||
connection: Connection; | ||
connection: DataSource; | ||
} | ||
export declare type TypeORMAdapterOptions = ExistentConnection | ConnectionOptions; | ||
export declare type TypeORMAdapterOptions = ExistentConnection | DataSourceOptions; | ||
export interface TypeORMAdapterConfig { | ||
customCasbinRuleEntity?: CasbinRuleConstructor; | ||
} | ||
/** | ||
@@ -11,2 +18,3 @@ * TypeORMAdapter represents the TypeORM filtered adapter for policy storage. | ||
export default class TypeORMAdapter implements FilteredAdapter { | ||
private adapterConfig?; | ||
private option; | ||
@@ -20,4 +28,5 @@ private typeorm; | ||
* @param option typeorm connection option | ||
* @param adapterConfig additional configuration options for the adapter | ||
*/ | ||
static newAdapter(option: TypeORMAdapterOptions): Promise<TypeORMAdapter>; | ||
static newAdapter(option: TypeORMAdapterOptions, adapterConfig?: TypeORMAdapterConfig): Promise<TypeORMAdapter>; | ||
private open; | ||
@@ -31,3 +40,3 @@ close(): Promise<void>; | ||
loadPolicy(model: Model): Promise<void>; | ||
loadFilteredPolicy(model: Model, filter: object): Promise<void>; | ||
loadFilteredPolicy(model: Model, filter: FindOptionsWhere<GenericCasbinRule>): Promise<void>; | ||
private savePolicyLine; | ||
@@ -60,8 +69,9 @@ /** | ||
/** | ||
* Returns either a {@link CasbinRule} or a {@link CasbinMongoRule}, depending on the type. This switch is required as the normal | ||
* {@link CasbinRule} does not work when using MongoDB as a backend (due to a missing ObjectID field). | ||
* Returns either a {@link CasbinRule} or a {@link CasbinMongoRule}, depending on the type. If passed a custom entity through the adapter config it will use that entity type. | ||
* This switch is required as the normal {@link CasbinRule} does not work when using MongoDB as a backend (due to a missing ObjectID field). | ||
* @param type | ||
*/ | ||
private static getCasbinRuleType; | ||
private getRepository; | ||
} | ||
export {}; |
@@ -33,4 +33,5 @@ "use strict"; | ||
class TypeORMAdapter { | ||
constructor(option) { | ||
constructor(option, adapterConfig) { | ||
this.filtered = false; | ||
this.adapterConfig = adapterConfig; | ||
if (option.connection) { | ||
@@ -50,4 +51,5 @@ this.typeorm = option.connection; | ||
* @param option typeorm connection option | ||
* @param adapterConfig additional configuration options for the adapter | ||
*/ | ||
static newAdapter(option) { | ||
static newAdapter(option, adapterConfig) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
@@ -60,9 +62,13 @@ let a; | ||
if (option.connection) { | ||
a = new TypeORMAdapter(option); | ||
a = new TypeORMAdapter(option, adapterConfig); | ||
} | ||
else { | ||
const options = option; | ||
const entities = { entities: [this.getCasbinRuleType(options.type)] }; | ||
const entities = { | ||
entities: [ | ||
TypeORMAdapter.getCasbinRuleType(options.type, adapterConfig), | ||
], | ||
}; | ||
const configuration = Object.assign(defaults, options); | ||
a = new TypeORMAdapter(Object.assign(configuration, entities)); | ||
a = new TypeORMAdapter(Object.assign(configuration, entities), adapterConfig); | ||
} | ||
@@ -76,6 +82,6 @@ yield a.open(); | ||
if (!this.typeorm) { | ||
this.typeorm = yield (0, typeorm_1.createConnection)(this.option); | ||
this.typeorm = new typeorm_1.DataSource(this.option); | ||
} | ||
if (!this.typeorm.isConnected) { | ||
yield this.typeorm.connect(); | ||
if (!this.typeorm.isInitialized) { | ||
yield this.typeorm.initialize(); | ||
} | ||
@@ -86,4 +92,4 @@ }); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (this.typeorm.isConnected) { | ||
yield this.typeorm.close(); | ||
if (this.typeorm.isInitialized) { | ||
yield this.typeorm.destroy(); | ||
} | ||
@@ -94,3 +100,3 @@ }); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
yield (0, typeorm_1.getRepository)(this.getCasbinRuleConstructor(), this.option.name).clear(); | ||
yield this.getRepository().clear(); | ||
}); | ||
@@ -112,3 +118,3 @@ } | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const lines = yield (0, typeorm_1.getRepository)(this.getCasbinRuleConstructor(), this.option.name).find(); | ||
const lines = yield this.getRepository().find(); | ||
for (const line of lines) { | ||
@@ -122,3 +128,3 @@ this.loadPolicyLine(line, model); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const filteredLines = yield (0, typeorm_1.getRepository)(this.getCasbinRuleConstructor(), this.option.name).find(filter); | ||
const filteredLines = yield this.getRepository().find({ where: filter }); | ||
for (const line of filteredLines) { | ||
@@ -202,3 +208,3 @@ this.loadPolicyLine(line, model); | ||
const line = this.savePolicyLine(ptype, rule); | ||
yield (0, typeorm_1.getRepository)(this.getCasbinRuleConstructor(), this.option.name).save(line); | ||
yield this.getRepository().save(line); | ||
}); | ||
@@ -238,3 +244,3 @@ } | ||
const line = this.savePolicyLine(ptype, rule); | ||
yield (0, typeorm_1.getRepository)(this.getCasbinRuleConstructor(), this.option.name).delete(Object.assign({}, line)); | ||
yield this.getRepository().delete(Object.assign({}, line)); | ||
}); | ||
@@ -248,3 +254,3 @@ } | ||
const queryRunner = this.typeorm.createQueryRunner(); | ||
const type = TypeORMAdapter.getCasbinRuleType(this.option.type); | ||
const type = TypeORMAdapter.getCasbinRuleType(this.option.type, this.adapterConfig); | ||
yield queryRunner.connect(); | ||
@@ -296,14 +302,17 @@ yield queryRunner.startTransaction(); | ||
} | ||
yield (0, typeorm_1.getRepository)(this.getCasbinRuleConstructor(), this.option.name).delete(Object.assign({}, line)); | ||
yield this.getRepository().delete(Object.assign({}, line)); | ||
}); | ||
} | ||
getCasbinRuleConstructor() { | ||
return TypeORMAdapter.getCasbinRuleType(this.option.type); | ||
return TypeORMAdapter.getCasbinRuleType(this.option.type, this.adapterConfig); | ||
} | ||
/** | ||
* Returns either a {@link CasbinRule} or a {@link CasbinMongoRule}, depending on the type. This switch is required as the normal | ||
* {@link CasbinRule} does not work when using MongoDB as a backend (due to a missing ObjectID field). | ||
* Returns either a {@link CasbinRule} or a {@link CasbinMongoRule}, depending on the type. If passed a custom entity through the adapter config it will use that entity type. | ||
* This switch is required as the normal {@link CasbinRule} does not work when using MongoDB as a backend (due to a missing ObjectID field). | ||
* @param type | ||
*/ | ||
static getCasbinRuleType(type) { | ||
static getCasbinRuleType(type, adapterConfig) { | ||
if (adapterConfig === null || adapterConfig === void 0 ? void 0 : adapterConfig.customCasbinRuleEntity) { | ||
return adapterConfig.customCasbinRuleEntity; | ||
} | ||
if (type === 'mongodb') { | ||
@@ -314,3 +323,6 @@ return casbinMongoRule_1.CasbinMongoRule; | ||
} | ||
getRepository() { | ||
return this.typeorm.getRepository(this.getCasbinRuleConstructor()); | ||
} | ||
} | ||
exports.default = TypeORMAdapter; |
{ | ||
"name": "typeorm-adapter", | ||
"version": "1.5.1", | ||
"version": "1.5.2", | ||
"description": "TypeORM adapter for Casbin", | ||
@@ -23,3 +23,3 @@ "main": "lib/index.js", | ||
"husky": "^1.1.2", | ||
"jest": "^23.6.0", | ||
"jest": "^28.1.3", | ||
"lint-staged": "^7.3.0", | ||
@@ -29,3 +29,3 @@ "mysql2": "^2.1.0", | ||
"rimraf": "^2.6.2", | ||
"ts-jest": "22.4.6", | ||
"ts-jest": "28.0.7", | ||
"tslint": "^5.11.0", | ||
@@ -36,2 +36,3 @@ "typescript": "^4.7.3" | ||
"casbin": "^5.11.5", | ||
"reflect-metadata": "^0.1.13", | ||
"typeorm": "^0.3.6" | ||
@@ -38,0 +39,0 @@ }, |
@@ -113,2 +113,61 @@ TypeORM Adapter | ||
``` | ||
## Custom Entity Example | ||
Use a custom entity that matches the CasbinRule or MongoCasbinRule in order to add additional fields or metadata to the entity. | ||
```typescript | ||
import { newEnforcer } from 'casbin'; | ||
import { | ||
CreateDateColumn, | ||
UpdateDateColumn, | ||
} from 'typeorm'; | ||
import TypeORMAdapter from 'typeorm-adapter'; | ||
@Entity('custom_rule') | ||
class CustomCasbinRule extends CasbinRule { | ||
@CreateDateColumn() | ||
createdDate: Date; | ||
@UpdateDateColumn() | ||
updatedDate: Date; | ||
} | ||
async function myFunction() { | ||
// Initialize a TypeORM adapter and use it in a Node-Casbin enforcer: | ||
// The adapter can not automatically create database. | ||
// But the adapter will automatically and use the table named "casbin_rule". | ||
// I think ORM should not automatically create databases. | ||
const a = await TypeORMAdapter.newAdapter( | ||
{ | ||
type: 'mysql', | ||
host: 'localhost', | ||
port: 3306, | ||
username: 'root', | ||
password: '', | ||
database: 'casbin', | ||
}, | ||
{ | ||
customCasbinRuleEntity: CustomCasbinRule, | ||
}, | ||
); | ||
const e = await newEnforcer('examples/rbac_model.conf', a); | ||
// Load the filtered policy from DB. | ||
await e.loadFilteredPolicy({ | ||
'ptype': 'p', | ||
'v0': 'alice' | ||
}); | ||
// Check the permission. | ||
await e.enforce('alice', 'data1', 'read'); | ||
// Modify the policy. | ||
// await e.addPolicy(...); | ||
// await e.removePolicy(...); | ||
// Save the policy back to DB. | ||
await e.savePolicy(); | ||
} | ||
``` | ||
## Getting Help | ||
@@ -115,0 +174,0 @@ |
41416
6.51%605
3.77%179
49.17%3
50%+ Added
+ Added
- Removed