rake-db 2.33.4 → 2.33.5

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/dist/index.d.ts CHANGED
@@ -5,10 +5,15 @@ declare namespace DbStructure {
5
5
  schemaName: string;
6
6
  tableName: string;
7
7
  }
8
+ interface TableRls {
9
+ enable: boolean;
10
+ force: boolean;
11
+ }
8
12
  interface Table {
9
13
  schemaName: string;
10
14
  name: string;
11
15
  comment?: string;
16
+ rls?: TableRls;
12
17
  columns: Column[];
13
18
  }
14
19
  interface View {
@@ -194,6 +199,7 @@ interface IntrospectedStructure {
194
199
  managedRolesSql?: string;
195
200
  }
196
201
  interface IntrospectDbStructureParams {
202
+ rls?: boolean;
197
203
  roles?: {
198
204
  whereSql?: string;
199
205
  };
@@ -201,7 +207,7 @@ interface IntrospectDbStructureParams {
201
207
  }
202
208
  declare function getDbVersion(db: Adapter): Promise<number>;
203
209
  declare function introspectDbSchema(db: Adapter, params?: IntrospectDbStructureParams): Promise<IntrospectedStructure>;
204
- type RakeDbAst = RakeDbAst.Table | RakeDbAst.ChangeTable | RakeDbAst.RenameType | RakeDbAst.Schema | RakeDbAst.RenameSchema | RakeDbAst.Extension | RakeDbAst.Enum | RakeDbAst.EnumValues | RakeDbAst.RenameEnumValues | RakeDbAst.ChangeEnumValues | RakeDbAst.Domain | RakeDbAst.Collation | RakeDbAst.Constraint | RakeDbAst.RenameTableItem | RakeDbAst.View | RakeDbAst.Role | RakeDbAst.RenameRole | RakeDbAst.ChangeRole | RakeDbAst.DefaultPrivilege;
210
+ type RakeDbAst = RakeDbAst.Table | RakeDbAst.ChangeTable | RakeDbAst.RenameType | RakeDbAst.Schema | RakeDbAst.RenameSchema | RakeDbAst.Extension | RakeDbAst.Enum | RakeDbAst.EnumValues | RakeDbAst.RenameEnumValues | RakeDbAst.ChangeEnumValues | RakeDbAst.Domain | RakeDbAst.Collation | RakeDbAst.Constraint | RakeDbAst.RenameTableItem | RakeDbAst.View | RakeDbAst.Role | RakeDbAst.RenameRole | RakeDbAst.ChangeRole | RakeDbAst.DefaultPrivilege | RakeDbAst.TableRls;
205
211
  declare namespace RakeDbAst {
206
212
  export interface Table extends TableData {
207
213
  type: 'table';
@@ -427,6 +433,12 @@ declare namespace RakeDbAst {
427
433
  grant?: DefaultPrivilegeObjectConfig;
428
434
  revoke?: DefaultPrivilegeObjectConfig;
429
435
  }
436
+ export interface TableRls {
437
+ type: 'tableRls';
438
+ action: 'enable' | 'disable' | 'force' | 'noForce';
439
+ schema?: string;
440
+ table: string;
441
+ }
430
442
  export {};
431
443
  }
432
444
  interface TableMethods {
@@ -1441,6 +1453,10 @@ declare class Migration<CT = unknown> {
1441
1453
  to: Partial<DbStructure.Role>;
1442
1454
  }): Promise<void>;
1443
1455
  changeDefaultPrivileges(params: ChangeDefaultPrivilegesArg): Promise<void>;
1456
+ enableRls(tableName: string): Promise<void>;
1457
+ disableRls(tableName: string): Promise<void>;
1458
+ forceRls(tableName: string): Promise<void>;
1459
+ noForceRls(tableName: string): Promise<void>;
1444
1460
  }
1445
1461
  interface AddEnumValueOptions {
1446
1462
  ifNotExists?: boolean;
package/dist/index.js CHANGED
@@ -1226,6 +1226,22 @@ const buildQuery = (ast, objectType, privileges, grantable, action) => {
1226
1226
  } else parts.push(`REVOKE ${privilegeList} ON ${objectTypeToSql[objectType]} FROM "${ast.grantee}"`);
1227
1227
  return parts.join(" ");
1228
1228
  };
1229
+ const actionToSql = {
1230
+ enable: "ENABLE ROW LEVEL SECURITY",
1231
+ disable: "DISABLE ROW LEVEL SECURITY",
1232
+ force: "FORCE ROW LEVEL SECURITY",
1233
+ noForce: "NO FORCE ROW LEVEL SECURITY"
1234
+ };
1235
+ const setRls = async (migration, tableName, action) => {
1236
+ const [schema, table] = getSchemaAndTableFromName(migration.adapter.getSchema(), tableName);
1237
+ await migration.adapter.arrays(`ALTER TABLE ${quoteTable(schema, table)} ${actionToSql[action]}`);
1238
+ };
1239
+ const enableOrDisableRls = (migration, up, tableName) => {
1240
+ return setRls(migration, tableName, up ? "enable" : "disable");
1241
+ };
1242
+ const forceOrNoForceRls = (migration, up, tableName) => {
1243
+ return setRls(migration, tableName, up ? "force" : "noForce");
1244
+ };
1229
1245
  /**
1230
1246
  * Creates a new `db` instance that is an instance of `pqb` with mixed in migration methods from the `Migration` class.
1231
1247
  * It overrides `query` and `array` db adapter methods to intercept SQL for the logging.
@@ -2087,6 +2103,18 @@ var Migration = class {
2087
2103
  changeDefaultPrivileges(params) {
2088
2104
  return changeDefaultPrivileges(this, this.up, params);
2089
2105
  }
2106
+ enableRls(tableName) {
2107
+ return enableOrDisableRls(this, this.up, tableName);
2108
+ }
2109
+ disableRls(tableName) {
2110
+ return enableOrDisableRls(this, !this.up, tableName);
2111
+ }
2112
+ forceRls(tableName) {
2113
+ return forceOrNoForceRls(this, this.up, tableName);
2114
+ }
2115
+ noForceRls(tableName) {
2116
+ return forceOrNoForceRls(this, !this.up, tableName);
2117
+ }
2090
2118
  };
2091
2119
  const wrapWithEnhancingError = async (text, values, promise) => {
2092
2120
  try {
@@ -3431,6 +3459,11 @@ const astToGenerateItem = (config, ast, currentSchema) => {
3431
3459
  if (ast.owner) deps.push(`role:${ast.owner}`);
3432
3460
  deps.push(`role:${ast.grantee}`);
3433
3461
  break;
3462
+ case "tableRls": {
3463
+ const { schema = currentSchema } = ast;
3464
+ deps.push(schema, `${schema}.${ast.table}`);
3465
+ break;
3466
+ }
3434
3467
  default: (0, pqb_internal.exhaustive)(ast);
3435
3468
  }
3436
3469
  return {
@@ -3896,6 +3929,13 @@ const astEncoders = {
3896
3929
  code.push(props);
3897
3930
  (0, pqb_internal.addCode)(code, "});");
3898
3931
  return code;
3932
+ },
3933
+ tableRls(ast, _config, currentSchema) {
3934
+ const table = quoteSchemaTable({
3935
+ schema: ast.schema,
3936
+ name: ast.table
3937
+ }, currentSchema);
3938
+ return `await db.${ast.action === "enable" ? "enableRls" : ast.action === "disable" ? "disableRls" : ast.action === "force" ? "forceRls" : "noForceRls"}(${table});`;
3899
3939
  }
3900
3940
  };
3901
3941
  const roleParams = (name, ast, compare, to) => {
@@ -4028,10 +4068,18 @@ ORDER BY a.attnum`;
4028
4068
  const schemasSql = `SELECT coalesce(json_agg(nspname ORDER BY nspname), '[]')
4029
4069
  FROM pg_catalog.pg_namespace n
4030
4070
  WHERE ${filterSchema("nspname")}`;
4031
- const tablesSql = `SELECT
4071
+ const tablesSql = (rls) => `SELECT
4032
4072
  nspname AS "schemaName",
4033
4073
  relname AS "name",
4034
4074
  obj_description(c.oid) AS comment,
4075
+ ${rls ? `(SELECT json_build_object(
4076
+ 'enable', rc.relrowsecurity,
4077
+ 'force', rc.relforcerowsecurity
4078
+ )
4079
+ FROM pg_class rc
4080
+ JOIN pg_namespace nr ON nr.oid = rc.relnamespace
4081
+ WHERE rc.relname = c.relname
4082
+ AND nr.nspname = n.nspname) AS "rls",` : ""}
4035
4083
  (SELECT coalesce(json_agg(t), '[]') FROM (${columnsSql({
4036
4084
  schema: "n",
4037
4085
  table: "c",
@@ -4351,7 +4399,7 @@ const defaultPrivilegesSql = `SELECT COALESCE(json_agg(t.*), '[]') FROM (
4351
4399
  JOIN LATERAL aclexplode(d.defaclacl) ae ON true
4352
4400
  GROUP BY "grantor", "grantee", "schema", "object"
4353
4401
  ) t`;
4354
- const sql = (version, params) => `SELECT (${schemasSql}) AS "schemas", ${jsonAgg(tablesSql, "tables")}, ${jsonAgg(viewsSql, "views")}, ${jsonAgg(indexesSql, "indexes")}, ${jsonAgg(constraintsSql, "constraints")}, ${jsonAgg(triggersSql, "triggers")}, ${jsonAgg(extensionsSql, "extensions")}, ${jsonAgg(enumsSql, "enums")}, ${jsonAgg(domainsSql, "domains")}, ${jsonAgg(collationsSql(version), "collations")}${params?.roles ? `, (${roleSql(params.roles)}) AS "roles"` : ""}${params?.loadDefaultPrivileges ? `, (${defaultPrivilegesSql}) AS "defaultPrivileges"` : ""}`;
4402
+ const sql = (version, params) => `SELECT (${schemasSql}) AS "schemas", ${jsonAgg(tablesSql(params?.rls), "tables")}, ${jsonAgg(viewsSql, "views")}, ${jsonAgg(indexesSql, "indexes")}, ${jsonAgg(constraintsSql, "constraints")}, ${jsonAgg(triggersSql, "triggers")}, ${jsonAgg(extensionsSql, "extensions")}, ${jsonAgg(enumsSql, "enums")}, ${jsonAgg(domainsSql, "domains")}, ${jsonAgg(collationsSql(version), "collations")}${params?.roles ? `, (${roleSql(params.roles)}) AS "roles"` : ""}${params?.loadDefaultPrivileges ? `, (${defaultPrivilegesSql}) AS "defaultPrivileges"` : ""}`;
4355
4403
  async function getDbVersion(db) {
4356
4404
  const { rows: [{ version: versionString }] } = await db.query("SELECT version()");
4357
4405
  return +versionString.match(/\d+/)[0];
@@ -4498,6 +4546,18 @@ const structureToAst = async (ctx, adapter, config) => {
4498
4546
  for (const table of data.tables) {
4499
4547
  if (table.name === migrationsTable && table.schemaName === migrationsSchema) continue;
4500
4548
  ast.push(tableToAst(ctx, data, table, "create", domains));
4549
+ if (table.rls?.enable) ast.push({
4550
+ type: "tableRls",
4551
+ action: "enable",
4552
+ schema: table.schemaName === ctx.currentSchema ? void 0 : table.schemaName,
4553
+ table: table.name
4554
+ });
4555
+ if (table.rls?.force) ast.push({
4556
+ type: "tableRls",
4557
+ action: "force",
4558
+ schema: table.schemaName === ctx.currentSchema ? void 0 : table.schemaName,
4559
+ table: table.name
4560
+ });
4501
4561
  }
4502
4562
  for (const it of data.extensions) ast.push({
4503
4563
  type: "extension",