• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

node-casbin / sequelize-adapter / 5358173782

pending completion
5358173782

Pull #80

github

web-flow
Merge a3d8655a4 into 1724f2e17
Pull Request #80: fix: create new CasbinRule instance every time sequelize Adapter opens connection

25 of 39 branches covered (64.1%)

Branch coverage included in aggregate %.

14 of 14 new or added lines in 2 files covered. (100.0%)

117 of 126 relevant lines covered (92.86%)

6.06 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.23
/src/adapter.ts
1
// Copyright 2018 The Casbin Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
import { Adapter, Helper, Model } from 'casbin';
1✔
16
import { Op } from 'sequelize';
1✔
17
import { Sequelize, SequelizeOptions } from 'sequelize-typescript';
1✔
18
import { createCasbinRule, CasbinRule } from './casbinRule';
1✔
19

20
export interface SequelizeAdapterOptions extends SequelizeOptions {
21
  tableName?: string;
22
  schema?: string;
23
}
24

25
/**
26
 * SequelizeAdapter represents the Sequelize adapter for policy storage.
27
 */
28
export class SequelizeAdapter implements Adapter {
1✔
29
  private readonly option: SequelizeAdapterOptions;
30
  private sequelize: Sequelize;
31
  private filtered = false;
1✔
32
  private autoCreateTable = true;
1✔
33
  private CasbinRule: typeof CasbinRule;
34

35
  constructor(option: SequelizeAdapterOptions, autoCreateTable = true) {
1✔
36
    this.option = option;
1✔
37
    this.autoCreateTable = autoCreateTable;
1✔
38
  }
39

40
  public isFiltered(): boolean {
41
    return this.filtered;
×
42
  }
43

44
  public enabledFiltered(enabled: boolean): void {
45
    this.filtered = enabled;
3✔
46
  }
47

48
  /**
49
   * newAdapter is the constructor.
50
   * @param option sequelize connection option
51
   */
52
  public static async newAdapter(
53
    option: SequelizeAdapterOptions,
54
    autoCreateTable?: boolean
55
  ): Promise<SequelizeAdapter> {
56
    const a = new SequelizeAdapter(option, autoCreateTable);
1✔
57
    await a.open();
1✔
58

59
    return a;
1✔
60
  }
61

62
  private async open(): Promise<void> {
63
    this.sequelize = new Sequelize(this.option);
1✔
64
    this.CasbinRule = createCasbinRule(
1✔
65
      this.option.tableName,
66
      this.option.schema
67
    ); // Set the property here
68
    await this.sequelize.authenticate();
1✔
69
    this.sequelize.addModels([this.CasbinRule]);
1✔
70
    if (this.autoCreateTable) {
1✔
71
      await this.createTable();
1✔
72
    }
73
  }
74

75
  public async close(): Promise<void> {
76
    await this.sequelize.close();
1✔
77
  }
78

79
  private async createTable(): Promise<void> {
80
    await this.sequelize.sync();
1✔
81
  }
82

83
  private loadPolicyLine(line: CasbinRule, model: Model): void {
84
    const result =
85
      line.ptype +
47✔
86
      ', ' +
87
      [line.v0, line.v1, line.v2, line.v3, line.v4, line.v5]
88
        .filter((n) => n)
282✔
89
        .join(', ');
90
    Helper.loadPolicyLine(result, model);
47✔
91
  }
92

93
  /**
94
   * loadPolicy loads all policy rules from the storage.
95
   */
96
  public async loadPolicy(model: Model): Promise<void> {
97
    const lines = await this.sequelize.getRepository(this.CasbinRule).findAll();
7✔
98

99
    for (const line of lines) {
7✔
100
      this.loadPolicyLine(line, model);
40✔
101
    }
102
  }
103

104
  private savePolicyLine(ptype: string, rule: string[]): CasbinRule {
105
    const line = new this.CasbinRule();
11✔
106

107
    line.ptype = ptype;
11✔
108
    if (rule.length > 0) {
11✔
109
      line.v0 = rule[0];
11✔
110
    }
111
    if (rule.length > 1) {
11✔
112
      line.v1 = rule[1];
11✔
113
    }
114
    if (rule.length > 2) {
11✔
115
      line.v2 = rule[2];
10✔
116
    }
117
    if (rule.length > 3) {
11!
118
      line.v3 = rule[3];
×
119
    }
120
    if (rule.length > 4) {
11!
121
      line.v4 = rule[4];
×
122
    }
123
    if (rule.length > 5) {
11!
124
      line.v5 = rule[5];
×
125
    }
126

127
    return line;
11✔
128
  }
129

130
  /**
131
   * savePolicy saves all policy rules to the storage.
132
   */
133
  public async savePolicy(model: Model): Promise<boolean> {
134
    await this.sequelize.transaction(async (tx) => {
1✔
135
      // truncate casbin table
136
      await this.sequelize
1✔
137
        .getRepository(this.CasbinRule)
138
        .destroy({ where: {}, truncate: true, transaction: tx });
139

140
      const lines: CasbinRule[] = [];
1✔
141

142
      let astMap = model.model.get('p')!;
1✔
143
      for (const [ptype, ast] of astMap) {
1✔
144
        for (const rule of ast.policy) {
1✔
145
          const line = this.savePolicyLine(ptype, rule);
4✔
146
          lines.push(line);
4✔
147
        }
148
      }
149

150
      astMap = model.model.get('g')!;
1✔
151
      for (const [ptype, ast] of astMap) {
1✔
152
        for (const rule of ast.policy) {
1✔
153
          const line = this.savePolicyLine(ptype, rule);
1✔
154
          lines.push(line);
1✔
155
        }
156
      }
157

158
      await this.CasbinRule.bulkCreate(
1✔
159
        lines.map((l) => l.get({ plain: true })),
5✔
160
        { transaction: tx }
161
      );
162
    });
163
    return true;
1✔
164
  }
165

166
  /**
167
   * addPolicy adds a policy rule to the storage.
168
   */
169
  public async addPolicy(
170
    sec: string,
171
    ptype: string,
172
    rule: string[]
173
  ): Promise<void> {
174
    const line = this.savePolicyLine(ptype, rule);
1✔
175
    await line.save();
1✔
176
  }
177

178
  /**
179
   * addPolicies adds a policyList rules to the storage.
180
   */
181
  public async addPolicies(
182
    sec: string,
183
    ptype: string,
184
    rules: string[][]
185
  ): Promise<void> {
186
    const lines: CasbinRule[] = [];
1✔
187
    for (const rule of rules) {
1✔
188
      const line = this.savePolicyLine(ptype, rule);
2✔
189
      lines.push(line);
2✔
190
    }
191
    await this.sequelize.transaction(async (tx) => {
1✔
192
      await this.CasbinRule.bulkCreate(
1✔
193
        lines.map((l) => l.get({ plain: true })),
2✔
194
        { transaction: tx }
195
      );
196
    });
197
  }
198

199
  /**
200
   * removePolicies removes a policyList rule from the storage.
201
   */
202
  public async removePolicy(
203
    sec: string,
204
    ptype: string,
205
    rule: string[]
206
  ): Promise<void> {
207
    const line = this.savePolicyLine(ptype, rule);
1✔
208
    const where = {};
1✔
209

210
    Object.keys(line.get({ plain: true }))
1✔
211
      .filter((key) => key !== 'id')
5✔
212
      .forEach((key) => {
213
        // @ts-ignore
214
        where[key] = line[key];
4✔
215
      });
216

217
    await this.sequelize.getRepository(this.CasbinRule).destroy({ where });
1✔
218
  }
219

220
  /**
221
   * removePolicies removes a policyList rule from the storage.
222
   */
223
  public async removePolicies(
224
    sec: string,
225
    ptype: string,
226
    rules: string[][]
227
  ): Promise<void> {
228
    await this.sequelize.transaction(async (tx) => {
1✔
229
      for (const rule of rules) {
1✔
230
        const line = this.savePolicyLine(ptype, rule);
2✔
231
        const where = {};
2✔
232

233
        Object.keys(line.get({ plain: true }))
2✔
234
          .filter((key) => key !== 'id')
10✔
235
          .forEach((key) => {
236
            // @ts-ignore
237
            where[key] = line[key];
8✔
238
          });
239

240
        await this.sequelize
2✔
241
          .getRepository(this.CasbinRule)
242
          .destroy({ where, transaction: tx });
243
      }
244
    });
245
  }
246

247
  /**
248
   * loadFilteredPolicy loads policy rules that match the filter from the storage;
249
   * use an empty string for selecting all values in a certain field.
250
   */
251
  public async loadFilteredPolicy(
252
    model: Model,
253
    filter: { [key: string]: string[][] }
254
  ): Promise<void> {
255
    const whereStatements = Object.keys(filter).map((ptype) => {
3✔
256
      const policyPatterns = filter[ptype];
3✔
257
      return policyPatterns.map((policyPattern) => {
3✔
258
        return {
4✔
259
          ptype,
260
          ...(policyPattern[0] && { v0: policyPattern[0] }),
8✔
261
          ...(policyPattern[1] && { v1: policyPattern[1] }),
4!
262
          ...(policyPattern[2] && { v2: policyPattern[2] }),
4!
263
          ...(policyPattern[3] && { v3: policyPattern[3] }),
4!
264
          ...(policyPattern[4] && { v4: policyPattern[4] }),
4!
265
          ...(policyPattern[5] && { v5: policyPattern[5] }),
4!
266
        };
267
      });
268
    });
269

270
    const where = {
3✔
271
      [Op.or]: whereStatements.reduce(
272
        (accumulator, value) => accumulator.concat(value),
3✔
273
        []
274
      ),
275
    };
276

277
    const lines = await this.sequelize
3✔
278
      .getRepository(this.CasbinRule)
279
      .findAll({ where });
280

281
    lines.forEach((line) => this.loadPolicyLine(line, model));
7✔
282
    this.enabledFiltered(true);
3✔
283
  }
284

285
  /**
286
   * removeFilteredPolicy removes policy rules that match the filter from the storage.
287
   */
288
  public async removeFilteredPolicy(
289
    sec: string,
290
    ptype: string,
291
    fieldIndex: number,
292
    ...fieldValues: string[]
293
  ): Promise<void> {
294
    const line = new this.CasbinRule();
3✔
295
    line.ptype = ptype;
3✔
296

297
    const idx = fieldIndex + fieldValues.length;
3✔
298
    if (fieldIndex <= 0 && 0 < idx) {
3✔
299
      line.v0 = fieldValues[0 - fieldIndex];
3✔
300
    }
301
    if (fieldIndex <= 1 && 1 < idx) {
3!
302
      line.v1 = fieldValues[1 - fieldIndex];
×
303
    }
304
    if (fieldIndex <= 2 && 2 < idx) {
3!
305
      line.v2 = fieldValues[2 - fieldIndex];
×
306
    }
307
    if (fieldIndex <= 3 && 3 < idx) {
3!
308
      line.v3 = fieldValues[3 - fieldIndex];
×
309
    }
310
    if (fieldIndex <= 4 && 4 < idx) {
3!
311
      line.v4 = fieldValues[4 - fieldIndex];
×
312
    }
313
    if (fieldIndex <= 5 && 5 < idx) {
3!
314
      line.v5 = fieldValues[5 - fieldIndex];
×
315
    }
316

317
    const where = {};
3✔
318

319
    Object.keys(line.get({ plain: true }))
3✔
320
      .filter((key) => key !== 'id')
9✔
321
      .forEach((key) => {
322
        // @ts-ignore
323
        where[key] = line[key];
6✔
324
      });
325

326
    await this.sequelize.getRepository(this.CasbinRule).destroy({
3✔
327
      where,
328
    });
329
  }
330
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc