safegres 1.28.3 → 1.28.4
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/checks/indexes.d.ts +5 -0
- package/checks/indexes.js +11 -3
- package/esm/checks/indexes.d.ts +5 -0
- package/esm/checks/indexes.js +11 -3
- package/esm/pg/indexes.d.ts +6 -0
- package/esm/pg/indexes.js +4 -2
- package/package.json +2 -2
- package/pg/indexes.d.ts +6 -0
- package/pg/indexes.js +4 -2
package/checks/indexes.d.ts
CHANGED
|
@@ -44,6 +44,11 @@ export declare function checkUnindexedForeignKeys(table: TableIndexSnapshot, pat
|
|
|
44
44
|
* leading-column prefix of a wider index. Both cost write throughput and
|
|
45
45
|
* disk for nothing. Constraint-backed indexes (PK/UNIQUE/EXCLUDE) are never
|
|
46
46
|
* reported — dropping them would drop the constraint.
|
|
47
|
+
*
|
|
48
|
+
* An index attached to a parent's partitioned index is never reported either:
|
|
49
|
+
* it can only be dropped with the parent's index, and the parent carries that
|
|
50
|
+
* finding once instead of every partition repeating it. An index created on
|
|
51
|
+
* the partition alone is the partition's own, and is reported there.
|
|
47
52
|
*/
|
|
48
53
|
export declare function checkRedundantIndexes(table: TableIndexSnapshot): Finding[];
|
|
49
54
|
/**
|
package/checks/indexes.js
CHANGED
|
@@ -69,10 +69,15 @@ function checkUnindexedForeignKeys(table, paths, onWriteOncePointer = 'report')
|
|
|
69
69
|
* leading-column prefix of a wider index. Both cost write throughput and
|
|
70
70
|
* disk for nothing. Constraint-backed indexes (PK/UNIQUE/EXCLUDE) are never
|
|
71
71
|
* reported — dropping them would drop the constraint.
|
|
72
|
+
*
|
|
73
|
+
* An index attached to a parent's partitioned index is never reported either:
|
|
74
|
+
* it can only be dropped with the parent's index, and the parent carries that
|
|
75
|
+
* finding once instead of every partition repeating it. An index created on
|
|
76
|
+
* the partition alone is the partition's own, and is reported there.
|
|
72
77
|
*/
|
|
73
78
|
function checkRedundantIndexes(table) {
|
|
74
79
|
const findings = [];
|
|
75
|
-
const candidates = table.indexes.filter((i) => !i.primary && !i.constraint && !i.partial && !i.expression && !i.unique);
|
|
80
|
+
const candidates = new Set(table.indexes.filter((i) => !i.primary && !i.constraint && !i.partial && !i.expression && !i.unique && !i.attached));
|
|
76
81
|
for (const idx of candidates) {
|
|
77
82
|
const covering = table.indexes.find((other) => {
|
|
78
83
|
if (other.name === idx.name)
|
|
@@ -83,8 +88,11 @@ function checkRedundantIndexes(table) {
|
|
|
83
88
|
return false;
|
|
84
89
|
if (!isPrefix(idx.columns, other.columns))
|
|
85
90
|
return false;
|
|
86
|
-
// Exact duplicates: report only one of the
|
|
87
|
-
|
|
91
|
+
// Exact duplicates: when both are droppable, report only one of the
|
|
92
|
+
// pair, deterministically.
|
|
93
|
+
if (idx.columns.length === other.columns.length
|
|
94
|
+
&& candidates.has(other)
|
|
95
|
+
&& idx.name < other.name)
|
|
88
96
|
return false;
|
|
89
97
|
return true;
|
|
90
98
|
});
|
package/esm/checks/indexes.d.ts
CHANGED
|
@@ -44,6 +44,11 @@ export declare function checkUnindexedForeignKeys(table: TableIndexSnapshot, pat
|
|
|
44
44
|
* leading-column prefix of a wider index. Both cost write throughput and
|
|
45
45
|
* disk for nothing. Constraint-backed indexes (PK/UNIQUE/EXCLUDE) are never
|
|
46
46
|
* reported — dropping them would drop the constraint.
|
|
47
|
+
*
|
|
48
|
+
* An index attached to a parent's partitioned index is never reported either:
|
|
49
|
+
* it can only be dropped with the parent's index, and the parent carries that
|
|
50
|
+
* finding once instead of every partition repeating it. An index created on
|
|
51
|
+
* the partition alone is the partition's own, and is reported there.
|
|
47
52
|
*/
|
|
48
53
|
export declare function checkRedundantIndexes(table: TableIndexSnapshot): Finding[];
|
|
49
54
|
/**
|
package/esm/checks/indexes.js
CHANGED
|
@@ -62,10 +62,15 @@ export function checkUnindexedForeignKeys(table, paths, onWriteOncePointer = 're
|
|
|
62
62
|
* leading-column prefix of a wider index. Both cost write throughput and
|
|
63
63
|
* disk for nothing. Constraint-backed indexes (PK/UNIQUE/EXCLUDE) are never
|
|
64
64
|
* reported — dropping them would drop the constraint.
|
|
65
|
+
*
|
|
66
|
+
* An index attached to a parent's partitioned index is never reported either:
|
|
67
|
+
* it can only be dropped with the parent's index, and the parent carries that
|
|
68
|
+
* finding once instead of every partition repeating it. An index created on
|
|
69
|
+
* the partition alone is the partition's own, and is reported there.
|
|
65
70
|
*/
|
|
66
71
|
export function checkRedundantIndexes(table) {
|
|
67
72
|
const findings = [];
|
|
68
|
-
const candidates = table.indexes.filter((i) => !i.primary && !i.constraint && !i.partial && !i.expression && !i.unique);
|
|
73
|
+
const candidates = new Set(table.indexes.filter((i) => !i.primary && !i.constraint && !i.partial && !i.expression && !i.unique && !i.attached));
|
|
69
74
|
for (const idx of candidates) {
|
|
70
75
|
const covering = table.indexes.find((other) => {
|
|
71
76
|
if (other.name === idx.name)
|
|
@@ -76,8 +81,11 @@ export function checkRedundantIndexes(table) {
|
|
|
76
81
|
return false;
|
|
77
82
|
if (!isPrefix(idx.columns, other.columns))
|
|
78
83
|
return false;
|
|
79
|
-
// Exact duplicates: report only one of the
|
|
80
|
-
|
|
84
|
+
// Exact duplicates: when both are droppable, report only one of the
|
|
85
|
+
// pair, deterministically.
|
|
86
|
+
if (idx.columns.length === other.columns.length
|
|
87
|
+
&& candidates.has(other)
|
|
88
|
+
&& idx.name < other.name)
|
|
81
89
|
return false;
|
|
82
90
|
return true;
|
|
83
91
|
});
|
package/esm/pg/indexes.d.ts
CHANGED
|
@@ -26,6 +26,12 @@ export interface IndexInfo {
|
|
|
26
26
|
/** Access method (`btree`, `gin`, …). */
|
|
27
27
|
method: string;
|
|
28
28
|
definition: string;
|
|
29
|
+
/**
|
|
30
|
+
* A partition of an index on the parent partitioned table
|
|
31
|
+
* (`pg_class.relispartition` on the index). Such an index cannot be dropped
|
|
32
|
+
* on its own; it exists because the parent's index does.
|
|
33
|
+
*/
|
|
34
|
+
attached: boolean;
|
|
29
35
|
}
|
|
30
36
|
export interface ColumnInfo {
|
|
31
37
|
name: string;
|
package/esm/pg/indexes.js
CHANGED
|
@@ -49,7 +49,8 @@ export async function introspectIndexes(exec, options = {}) {
|
|
|
49
49
|
(ix.indpred IS NOT NULL) AS is_partial,
|
|
50
50
|
(ix.indexprs IS NOT NULL) AS is_expression,
|
|
51
51
|
am.amname AS method,
|
|
52
|
-
pg_get_indexdef(i.oid) AS definition
|
|
52
|
+
pg_get_indexdef(i.oid) AS definition,
|
|
53
|
+
i.relispartition AS is_attached
|
|
53
54
|
FROM pg_index ix
|
|
54
55
|
JOIN pg_class i ON i.oid = ix.indexrelid
|
|
55
56
|
JOIN pg_am am ON am.oid = i.relam
|
|
@@ -84,7 +85,8 @@ export async function introspectIndexes(exec, options = {}) {
|
|
|
84
85
|
'partial', x.is_partial,
|
|
85
86
|
'expression', x.is_expression,
|
|
86
87
|
'method', x.method,
|
|
87
|
-
'definition', x.definition
|
|
88
|
+
'definition', x.definition,
|
|
89
|
+
'attached', x.is_attached
|
|
88
90
|
) ORDER BY x.name) FROM indexes x WHERE x.oid = r.oid),
|
|
89
91
|
'[]'::jsonb
|
|
90
92
|
) AS indexes,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "safegres",
|
|
3
|
-
"version": "1.28.
|
|
3
|
+
"version": "1.28.4",
|
|
4
4
|
"author": "Constructive <developers@constructive.io>",
|
|
5
5
|
"description": "Postgres security and performance auditor: RLS, grants and effective-access analysis plus index and policy-cost checks, scored on two independent axes. One connection, no framework.",
|
|
6
6
|
"main": "index.js",
|
|
@@ -85,5 +85,5 @@
|
|
|
85
85
|
"makage": "^0.8.0",
|
|
86
86
|
"pgsql-test": "^5.17.0"
|
|
87
87
|
},
|
|
88
|
-
"gitHead": "
|
|
88
|
+
"gitHead": "77c3196a3b35b3886f40413157e40c71634cc3fc"
|
|
89
89
|
}
|
package/pg/indexes.d.ts
CHANGED
|
@@ -26,6 +26,12 @@ export interface IndexInfo {
|
|
|
26
26
|
/** Access method (`btree`, `gin`, …). */
|
|
27
27
|
method: string;
|
|
28
28
|
definition: string;
|
|
29
|
+
/**
|
|
30
|
+
* A partition of an index on the parent partitioned table
|
|
31
|
+
* (`pg_class.relispartition` on the index). Such an index cannot be dropped
|
|
32
|
+
* on its own; it exists because the parent's index does.
|
|
33
|
+
*/
|
|
34
|
+
attached: boolean;
|
|
29
35
|
}
|
|
30
36
|
export interface ColumnInfo {
|
|
31
37
|
name: string;
|
package/pg/indexes.js
CHANGED
|
@@ -54,7 +54,8 @@ async function introspectIndexes(exec, options = {}) {
|
|
|
54
54
|
(ix.indpred IS NOT NULL) AS is_partial,
|
|
55
55
|
(ix.indexprs IS NOT NULL) AS is_expression,
|
|
56
56
|
am.amname AS method,
|
|
57
|
-
pg_get_indexdef(i.oid) AS definition
|
|
57
|
+
pg_get_indexdef(i.oid) AS definition,
|
|
58
|
+
i.relispartition AS is_attached
|
|
58
59
|
FROM pg_index ix
|
|
59
60
|
JOIN pg_class i ON i.oid = ix.indexrelid
|
|
60
61
|
JOIN pg_am am ON am.oid = i.relam
|
|
@@ -89,7 +90,8 @@ async function introspectIndexes(exec, options = {}) {
|
|
|
89
90
|
'partial', x.is_partial,
|
|
90
91
|
'expression', x.is_expression,
|
|
91
92
|
'method', x.method,
|
|
92
|
-
'definition', x.definition
|
|
93
|
+
'definition', x.definition,
|
|
94
|
+
'attached', x.is_attached
|
|
93
95
|
) ORDER BY x.name) FROM indexes x WHERE x.oid = r.oid),
|
|
94
96
|
'[]'::jsonb
|
|
95
97
|
) AS indexes,
|