Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 26 additions & 24 deletions graphql/node-type-registry/src/blueprint-types.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -610,22 +610,22 @@ export interface RelationManyToManyParams {
nodes?: {
[key: string]: unknown;
}[];
/* Database roles to grant privileges to. Forwarded to secure_table_provision as-is. Default: [authenticated] */
grant_roles?: string[];
/* Privilege grants for the junction table as [verb, columns] tuples (e.g. [['select','*'],['insert','*']]). Forwarded to secure_table_provision as-is. Default: select/insert/delete for all columns */
grant_privileges?: string[][];
/* RLS policy type for the junction table. Forwarded to secure_table_provision as-is. NULL means no policy. */
policy_type?: string;
/* Privileges the policy applies to. Forwarded to secure_table_provision as-is. NULL means derived from grant_privileges verbs. */
policy_privileges?: string[];
/* Database role the policy targets. Forwarded to secure_table_provision as-is. NULL means falls back to first grant_role. */
policy_role?: string;
/* Whether the policy is PERMISSIVE (true) or RESTRICTIVE (false). Forwarded to secure_table_provision as-is. */
policy_permissive?: boolean;
/* Policy configuration forwarded to secure_table_provision as-is. Structure varies by policy_type. */
policy_data?: {
[key: string]: unknown;
};
/* Unified grant objects for the junction table. Each entry is { roles: string[], privileges: string[][] }. Forwarded to secure_table_provision as-is. Default: [] */
grants?: {
roles: string[];
privileges: string[][];
}[];
/* RLS policy objects for the junction table. Each entry has $type (Authz* generator), optional data, privileges, policy_role, permissive, policy_name. Forwarded to secure_table_provision as-is. Default: [] */
policies?: {
$type: string;
data?: {
[key: string]: unknown;
};
privileges?: string[];
policy_role?: string;
permissive?: boolean;
policy_name?: string;
}[];
}
/** Declares a spatial predicate between two existing geometry/geography columns. Inserts a metaschema_public.spatial_relation row; the sync_spatial_relation_tags trigger then projects a @spatialRelation smart tag onto the owner column so graphile-postgis' PostgisSpatialRelationsPlugin can expose it as a cross-table filter in GraphQL. Metadata-only: both source_field and target_field must already exist on their tables. Idempotent on (source_table_id, name). One direction per tag — author two RelationSpatial entries if symmetry is desired. */
export interface RelationSpatialParams {
Expand Down Expand Up @@ -838,10 +838,11 @@ export interface BlueprintEntityTableProvision {
nodes?: BlueprintNode[];
/** Custom fields (columns) to add to the entity table. Forwarded to secure_table_provision as-is. */
fields?: BlueprintField[];
/** Privilege grants for the entity table as [verb, columns] tuples (e.g. [["select","*"],["insert","*"]]). Forwarded to secure_table_provision as-is. */
grant_privileges?: unknown[];
/** Database roles to grant privileges to. Forwarded to secure_table_provision as-is. Defaults to ["authenticated"]. */
grant_roles?: string[];
/** Unified grant objects for the entity table. Each entry is { roles: string[], privileges: unknown[] } where privileges are [verb, columns] tuples. Forwarded to secure_table_provision as-is. Defaults to []. */
grants?: {
roles: string[];
privileges: unknown[];
}[];
/** RLS policies for the entity table. When present, these policies fully replace the five default entity-table policies (is_visible becomes a no-op). */
policies?: BlueprintPolicy[];
}
Expand Down Expand Up @@ -1075,10 +1076,11 @@ export interface BlueprintTable {
fields?: BlueprintField[];
/** RLS policies for this table. */
policies?: BlueprintPolicy[];
/** Database roles to grant privileges to. Defaults to ["authenticated"]. */
grant_roles?: string[];
/** Privilege grants as [verb, column] tuples or objects. Defaults to empty (no grants — callers must explicitly specify). */
grants?: unknown[];
/** Unified grant objects. Each entry is { roles: string[], privileges: unknown[] } where privileges are [verb, columns] tuples (e.g. [["select","*"]]). Enables per-role targeting. Defaults to []. */
grants?: {
roles: string[];
privileges: unknown[];
}[];
/** Whether to enable RLS on this table. Defaults to true. */
use_rls?: boolean;
/** Table-level indexes (table_name inherited from parent). */
Expand Down
32 changes: 20 additions & 12 deletions graphql/node-type-registry/src/codegen/generate-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -642,12 +642,16 @@ function buildBlueprintEntityTableProvision(): t.ExportNamedDeclaration {
'Custom fields (columns) to add to the entity table. Forwarded to secure_table_provision as-is.'
),
addJSDoc(
optionalProp('grant_privileges', t.tsArrayType(t.tsUnknownKeyword())),
'Privilege grants for the entity table as [verb, columns] tuples (e.g. [["select","*"],["insert","*"]]). Forwarded to secure_table_provision as-is.'
),
addJSDoc(
optionalProp('grant_roles', t.tsArrayType(t.tsStringKeyword())),
'Database roles to grant privileges to. Forwarded to secure_table_provision as-is. Defaults to ["authenticated"].'
optionalProp(
'grants',
t.tsArrayType(
t.tsTypeLiteral([
requiredProp('roles', t.tsArrayType(t.tsStringKeyword())),
requiredProp('privileges', t.tsArrayType(t.tsUnknownKeyword())),
])
)
),
'Unified grant objects for the entity table. Each entry is { roles: string[], privileges: unknown[] } where privileges are [verb, columns] tuples. Forwarded to secure_table_provision as-is. Defaults to [].'
),
addJSDoc(
optionalProp(
Expand Down Expand Up @@ -749,12 +753,16 @@ function buildBlueprintTable(): t.ExportNamedDeclaration {
'RLS policies for this table.'
),
addJSDoc(
optionalProp('grant_roles', t.tsArrayType(t.tsStringKeyword())),
'Database roles to grant privileges to. Defaults to ["authenticated"].'
),
addJSDoc(
optionalProp('grants', t.tsArrayType(t.tsUnknownKeyword())),
'Privilege grants as [verb, column] tuples or objects. Defaults to empty (no grants — callers must explicitly specify).'
optionalProp(
'grants',
t.tsArrayType(
t.tsTypeLiteral([
requiredProp('roles', t.tsArrayType(t.tsStringKeyword())),
requiredProp('privileges', t.tsArrayType(t.tsUnknownKeyword())),
])
)
),
'Unified grant objects. Each entry is { roles: string[], privileges: unknown[] } where privileges are [verb, columns] tuples (e.g. [["select","*"]]). Enables per-role targeting. Defaults to [].'
),
addJSDoc(
optionalProp('use_rls', t.tsBooleanKeyword()),
Expand Down
53 changes: 20 additions & 33 deletions graphql/node-type-registry/src/relation/relation-many-to-many.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,46 +48,33 @@ export const RelationManyToMany: NodeTypeDefinition = {
},
"description": "Array of node objects for field creation on junction table. Each object has a $type key (e.g. DataId, DataEntityMembership) and optional data keys. Forwarded to secure_table_provision as-is. Empty array means no additional fields."
},
"grant_roles": {
"grants": {
"type": "array",
"items": {
"type": "string"
"type": "object",
"properties": {
"roles": { "type": "array", "items": { "type": "string" } },
"privileges": { "type": "array", "items": { "type": "array", "items": { "type": "string" } } }
},
"required": ["roles", "privileges"]
},
"description": "Database roles to grant privileges to. Forwarded to secure_table_provision as-is. Default: [authenticated]"
"description": "Unified grant objects for the junction table. Each entry is { roles: string[], privileges: string[][] }. Forwarded to secure_table_provision as-is. Default: []"
},
"grant_privileges": {
"policies": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "string"
}
"type": "object",
"properties": {
"$type": { "type": "string" },
"data": { "type": "object" },
"privileges": { "type": "array", "items": { "type": "string" } },
"policy_role": { "type": "string" },
"permissive": { "type": "boolean" },
"policy_name": { "type": "string" }
},
"required": ["$type"]
},
"description": "Privilege grants for the junction table as [verb, columns] tuples (e.g. [['select','*'],['insert','*']]). Forwarded to secure_table_provision as-is. Default: select/insert/delete for all columns"
},
"policy_type": {
"type": "string",
"description": "RLS policy type for the junction table. Forwarded to secure_table_provision as-is. NULL means no policy."
},
"policy_privileges": {
"type": "array",
"items": {
"type": "string"
},
"description": "Privileges the policy applies to. Forwarded to secure_table_provision as-is. NULL means derived from grant_privileges verbs."
},
"policy_role": {
"type": "string",
"description": "Database role the policy targets. Forwarded to secure_table_provision as-is. NULL means falls back to first grant_role."
},
"policy_permissive": {
"type": "boolean",
"description": "Whether the policy is PERMISSIVE (true) or RESTRICTIVE (false). Forwarded to secure_table_provision as-is.",
"default": true
},
"policy_data": {
"type": "object",
"description": "Policy configuration forwarded to secure_table_provision as-is. Structure varies by policy_type."
"description": "RLS policy objects for the junction table. Each entry has $type (Authz* generator), optional data, privileges, policy_role, permissive, policy_name. Forwarded to secure_table_provision as-is. Default: []"
}
},
"required": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ exports[`test case empty array fields emit empty array literal 1`] = `
id,
node_type,
fields,
grant_roles
out_fields
) VALUES
('450e3b3b-b68d-4abc-990c-65cb8a1dcdb4', 'DataTimestamps', '{}', '{}');"
`;
Expand Down Expand Up @@ -76,10 +76,9 @@ exports[`test case null array fields emit empty array literal instead of NULL 1`
id,
node_type,
fields,
grant_privileges,
out_fields
) VALUES
('450e3b3b-b68d-4abc-990c-65cb8a1dcdb4', 'DataTimestamps', '{}', '{}', '{}');"
('450e3b3b-b68d-4abc-990c-65cb8a1dcdb4', 'DataTimestamps', '{}', '{}');"
`;

exports[`test case test case 1`] = `Promise {}`;
Expand Down
6 changes: 2 additions & 4 deletions packages/csv-to-pg/__tests__/export.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,6 @@ it('null array fields emit empty array literal instead of NULL', async () => {
id: 'uuid',
node_type: 'text',
fields: 'jsonb[]',
grant_privileges: 'jsonb[]',
out_fields: 'uuid[]'
}
});
Expand All @@ -239,7 +238,6 @@ it('null array fields emit empty array literal instead of NULL', async () => {
id: '450e3b3b-b68d-4abc-990c-65cb8a1dcdb4',
node_type: 'DataTimestamps',
fields: null,
grant_privileges: null,
out_fields: null
}
]);
Expand All @@ -259,7 +257,7 @@ it('empty array fields emit empty array literal', async () => {
id: 'uuid',
node_type: 'text',
fields: 'jsonb[]',
grant_roles: 'text[]'
out_fields: 'uuid[]'
}
});

Expand All @@ -268,7 +266,7 @@ it('empty array fields emit empty array literal', async () => {
id: '450e3b3b-b68d-4abc-990c-65cb8a1dcdb4',
node_type: 'DataTimestamps',
fields: [],
grant_roles: []
out_fields: []
}
]);

Expand Down
9 changes: 2 additions & 7 deletions pgpm/export/src/export-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -985,14 +985,9 @@ export const META_TABLE_CONFIG: Record<string, TableConfig> = {
node_type: 'text',
use_rls: 'boolean',
node_data: 'jsonb',
grant_roles: 'text[]',
fields: 'jsonb[]',
grant_privileges: 'jsonb[]',
policy_type: 'text',
policy_privileges: 'text[]',
policy_role: 'text',
policy_permissive: 'boolean',
policy_data: 'jsonb',
grants: 'jsonb',
policies: 'jsonb',
out_fields: 'uuid[]'
}
},
Expand Down
Loading