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

node-casbin / prisma-adapter / 5988963719

27 Aug 2023 04:53AM UTC coverage: 71.533% (-12.8%) from 84.348%
5988963719

push

github

web-flow
feat: add loadFilteredPolicy() support (#50)

* issue-49 Include loadFilteredPolicy() support

* fix prettier

* mark isFiltered

19 of 40 branches covered (0.0%)

Branch coverage included in aggregate %.

10 of 10 new or added lines in 1 file covered. (100.0%)

79 of 97 relevant lines covered (81.44%)

5.6 hits per line

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

71.53
/src/adapter.ts
1
import type { Adapter, Model } from 'casbin';
2
import type { CasbinRule } from '@prisma/client';
3

4
import { Helper } from 'casbin';
1✔
5
import { PrismaClient } from '@prisma/client';
1✔
6
import { Prisma } from '@prisma/client';
7

8
export class PrismaAdapter implements Adapter {
1✔
9
  #option?: Prisma.PrismaClientOptions;
1✔
10
  #prisma: PrismaClient;
1✔
11

12
  filtered = false;
1✔
13

14
  public isFiltered(): boolean {
15
    return this.filtered;
×
16
  }
17

18
  public enableFiltered(enabled: boolean): void {
19
    this.filtered = enabled;
×
20
  }
21

22
  /**
23
   * @param option It should be PrismaClientOptions or PrismaClient.
24
   * You should later call open() to activate it.
25
   */
26
  constructor(option?: Prisma.PrismaClientOptions | PrismaClient) {
27
    if (option instanceof PrismaClient) {
1!
28
      this.#prisma = option;
×
29
    } else {
30
      this.#option = option;
1✔
31
    }
32
  }
33

34
  async loadPolicy(model: Model): Promise<void> {
35
    const lines = await this.#prisma.casbinRule.findMany();
6✔
36

37
    for (const line of lines) {
6✔
38
      this.#loadPolicyLine(line, model);
36✔
39
    }
40
  }
41

42
  /**
43
   * loadFilteredPolicy loads policy rules that match the filter from the storage;
44
   * use an empty string for selecting all values in a certain field.
45
   */
46
  async loadFilteredPolicy(
47
    model: Model,
48
    filter: { [key: string]: string[][] }
49
  ): Promise<void> {
50
    const whereFilter = Object.keys(filter)
×
51
      .map((ptype) => {
52
        const policyPatterns = filter[ptype];
×
53
        return policyPatterns.map((policyPattern) => {
×
54
          return {
×
55
            ptype,
56
            ...(policyPattern[0] && { v0: policyPattern[0] }),
×
57
            ...(policyPattern[1] && { v1: policyPattern[1] }),
×
58
            ...(policyPattern[2] && { v2: policyPattern[2] }),
×
59
            ...(policyPattern[3] && { v3: policyPattern[3] }),
×
60
            ...(policyPattern[4] && { v4: policyPattern[4] }),
×
61
            ...(policyPattern[5] && { v5: policyPattern[5] }),
×
62
          };
63
        });
64
      })
65
      .flat();
66
    const lines = await this.#prisma.casbinRule.findMany({
×
67
      where: {
68
        OR: whereFilter,
69
      },
70
    });
71
    lines.forEach((line) => this.#loadPolicyLine(line, model));
×
72
    this.enableFiltered(true);
×
73
  }
74

75
  async savePolicy(model: Model): Promise<boolean> {
76
    await this.#prisma.$executeRaw`DELETE FROM casbin_rule;`;
1✔
77

78
    let astMap = model.model.get('p')!;
1✔
79
    const processes: Array<Promise<CasbinRule>> = [];
1✔
80

81
    for (const [ptype, ast] of astMap) {
1✔
82
      for (const rule of ast.policy) {
1✔
83
        const line = this.#savePolicyLine(ptype, rule);
4✔
84
        const p = this.#prisma.casbinRule.create({
4✔
85
          data: line,
86
        });
87
        processes.push(p);
4✔
88
      }
89
    }
90

91
    astMap = model.model.get('g')!;
1✔
92
    for (const [ptype, ast] of astMap) {
1✔
93
      for (const rule of ast.policy) {
1✔
94
        const line = this.#savePolicyLine(ptype, rule);
1✔
95
        const p = this.#prisma.casbinRule.create({
1✔
96
          data: line,
97
        });
98
        processes.push(p);
1✔
99
      }
100
    }
101

102
    // https://github.com/prisma/prisma-client-js/issues/332
103
    await Promise.all(processes);
1✔
104

105
    return true;
1✔
106
  }
107

108
  async addPolicy(sec: string, ptype: string, rule: string[]): Promise<void> {
109
    const line = this.#savePolicyLine(ptype, rule);
1✔
110
    await this.#prisma.casbinRule.create({ data: line });
1✔
111
  }
112

113
  async addPolicies(
114
    sec: string,
115
    ptype: string,
116
    rules: string[][]
117
  ): Promise<void> {
118
    const processes: Array<Promise<CasbinRule>> = [];
1✔
119
    for (const rule of rules) {
1✔
120
      const line = this.#savePolicyLine(ptype, rule);
2✔
121
      const p = this.#prisma.casbinRule.create({ data: line });
2✔
122
      processes.push(p);
2✔
123
    }
124

125
    // https://github.com/prisma/prisma-client-js/issues/332
126
    await Promise.all(processes);
1✔
127
  }
128

129
  async removePolicy(
130
    sec: string,
131
    ptype: string,
132
    rule: string[]
133
  ): Promise<void> {
134
    const line = this.#savePolicyLine(ptype, rule);
1✔
135
    await this.#prisma.casbinRule.deleteMany({ where: line });
1✔
136
  }
137

138
  async removePolicies(
139
    sec: string,
140
    ptype: string,
141
    rules: string[][]
142
  ): Promise<void> {
143
    const processes: Array<Promise<Prisma.BatchPayload>> = [];
1✔
144
    for (const rule of rules) {
1✔
145
      const line = this.#savePolicyLine(ptype, rule);
2✔
146
      const p = this.#prisma.casbinRule.deleteMany({ where: line });
2✔
147
      processes.push(p);
2✔
148
    }
149

150
    // https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client/transactions#bulk-operations
151
    await Promise.all(processes);
1✔
152
  }
153

154
  async removeFilteredPolicy(
155
    sec: string,
156
    ptype: string,
157
    fieldIndex: number,
158
    ...fieldValues: string[]
159
  ): Promise<void> {
160
    const line: Prisma.CasbinRuleCreateInput = { ptype };
2✔
161

162
    const idx = fieldIndex + fieldValues.length;
2✔
163
    if (fieldIndex <= 0 && 0 < idx) {
2✔
164
      line.v0 = fieldValues[0 - fieldIndex];
2✔
165
    }
166
    if (fieldIndex <= 1 && 1 < idx) {
2!
167
      line.v1 = fieldValues[1 - fieldIndex];
×
168
    }
169
    if (fieldIndex <= 2 && 2 < idx) {
2!
170
      line.v2 = fieldValues[2 - fieldIndex];
×
171
    }
172
    if (fieldIndex <= 3 && 3 < idx) {
2!
173
      line.v3 = fieldValues[3 - fieldIndex];
×
174
    }
175
    if (fieldIndex <= 4 && 4 < idx) {
2!
176
      line.v4 = fieldValues[4 - fieldIndex];
×
177
    }
178
    if (fieldIndex <= 5 && 5 < idx) {
2!
179
      line.v5 = fieldValues[5 - fieldIndex];
×
180
    }
181

182
    await this.#prisma.casbinRule.deleteMany({ where: line });
2✔
183
  }
184

185
  async close(): Promise<any> {
186
    return this.#prisma.$disconnect();
1✔
187
  }
188

189
  static async newAdapter(
190
    option?: Prisma.PrismaClientOptions | PrismaClient
191
  ): Promise<PrismaAdapter> {
192
    const a = new PrismaAdapter(option);
1✔
193
    await a.#open();
1✔
194

195
    return a;
1✔
196
  }
197

198
  #open = async (): Promise<void> => {
1✔
199
    if (!this.#option) {
1✔
200
      this.#option = {};
1✔
201
    }
202
    if (!this.#prisma) {
1✔
203
      this.#prisma = new PrismaClient(this.#option);
1✔
204
    }
205
    await this.#prisma.$connect();
1✔
206
  };
207

208
  #loadPolicyLine = (
1✔
209
    line: Prisma.CasbinRuleCreateInput,
210
    model: Model
211
  ): void => {
212
    const result =
213
      line.ptype +
36✔
214
      ', ' +
215
      [line.v0, line.v1, line.v2, line.v3, line.v4, line.v5]
216
        .filter((n) => n)
216✔
217
        .join(', ');
218
    Helper.loadPolicyLine(result, model);
36✔
219
  };
220

221
  #savePolicyLine = (
1✔
222
    ptype: string,
223
    rule: string[]
224
  ): Prisma.CasbinRuleCreateInput => {
225
    const line: Prisma.CasbinRuleCreateInput = { ptype };
11✔
226

227
    if (rule.length > 0) {
11✔
228
      line.v0 = rule[0];
11✔
229
    }
230
    if (rule.length > 1) {
11✔
231
      line.v1 = rule[1];
11✔
232
    }
233
    if (rule.length > 2) {
11✔
234
      line.v2 = rule[2];
10✔
235
    }
236
    if (rule.length > 3) {
11!
237
      line.v3 = rule[3];
×
238
    }
239
    if (rule.length > 4) {
11!
240
      line.v4 = rule[4];
×
241
    }
242
    if (rule.length > 5) {
11!
243
      line.v5 = rule[5];
×
244
    }
245

246
    return line;
11✔
247
  };
248
}
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