Skip to content

feature: Add CRUD permissions #491

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 21 commits into from
Closed
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
9 changes: 9 additions & 0 deletions src/lib/PostgresMeta.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { PoolConfig } from 'pg'
import * as Parser from './Parser.js'
import PostgresMetaColumnPermissions from './PostgresMetaColumnPermissions.js'
import PostgresMetaColumns from './PostgresMetaColumns.js'
import PostgresMetaConfig from './PostgresMetaConfig.js'
import PostgresMetaExtensions from './PostgresMetaExtensions.js'
import PostgresMetaForeignTables from './PostgresMetaForeignTables.js'
import PostgresMetaFunctions from './PostgresMetaFunctions.js'
import PostgresMetaPermissions from './PostgresMetaPermissions.js'
import PostgresMetaPolicies from './PostgresMetaPolicies.js'
import PostgresMetaPublications from './PostgresMetaPublications.js'
import PostgresMetaRoles from './PostgresMetaRoles.js'
import PostgresMetaSchemas from './PostgresMetaSchemas.js'
import PostgresMetaTablePermissions from './PostgresMetaTablePermissions.js'
import PostgresMetaTables from './PostgresMetaTables.js'
import PostgresMetaTriggers from './PostgresMetaTriggers.js'
import PostgresMetaTypes from './PostgresMetaTypes.js'
Expand All @@ -20,15 +23,18 @@ import { PostgresMetaResult } from './types.js'
export default class PostgresMeta {
query: (sql: string) => Promise<PostgresMetaResult<any>>
end: () => Promise<void>
columnPermissions: PostgresMetaColumnPermissions
columns: PostgresMetaColumns
config: PostgresMetaConfig
extensions: PostgresMetaExtensions
foreignTables: PostgresMetaForeignTables
functions: PostgresMetaFunctions
permissions: PostgresMetaPermissions
policies: PostgresMetaPolicies
publications: PostgresMetaPublications
roles: PostgresMetaRoles
schemas: PostgresMetaSchemas
tablePermissions: PostgresMetaTablePermissions
tables: PostgresMetaTables
triggers: PostgresMetaTriggers
types: PostgresMetaTypes
Expand All @@ -44,14 +50,17 @@ export default class PostgresMeta {
this.query = query
this.end = end
this.columns = new PostgresMetaColumns(this.query)
this.columnPermissions = new PostgresMetaColumnPermissions(this.query)
this.config = new PostgresMetaConfig(this.query)
this.extensions = new PostgresMetaExtensions(this.query)
this.foreignTables = new PostgresMetaForeignTables(this.query)
this.functions = new PostgresMetaFunctions(this.query)
this.permissions = new PostgresMetaPermissions(this.query)
this.policies = new PostgresMetaPolicies(this.query)
this.publications = new PostgresMetaPublications(this.query)
this.roles = new PostgresMetaRoles(this.query)
this.schemas = new PostgresMetaSchemas(this.query)
this.tablePermissions = new PostgresMetaTablePermissions(this.query)
this.tables = new PostgresMetaTables(this.query)
this.triggers = new PostgresMetaTriggers(this.query)
this.types = new PostgresMetaTypes(this.query)
Expand Down
110 changes: 110 additions & 0 deletions src/lib/PostgresMetaColumnPermissions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { ident, literal } from 'pg-format'
import { ColumnPermissionListSchema } from './inputs.js'
import { columnPermissionsSql } from './sql/index.js'
import { PostgresMetaResult, PostgresColumnPermission } from './types.js'

export default class PostgresMetaColumns {
query: (sql: string) => Promise<PostgresMetaResult<any>>

constructor(query: (sql: string) => Promise<PostgresMetaResult<any>>) {
this.query = query
}

async list({
table_schema,
table_name,
column_name,
privilege,
include_system_schemas = false,
limit,
offset,
}: ColumnPermissionListSchema = {}): Promise<PostgresMetaResult<PostgresColumnPermission[]>> {
let sql = `
WITH
column_permissions AS (${columnPermissionsSql})
SELECT
*
FROM
column_permissions
WHERE
true`
if (table_schema) {
sql += ` AND table_schema = ${literal(table_schema)}`
}
if (table_name) {
sql += ` AND table_name = ${literal(table_name)}`
}
if (column_name) {
sql += ` AND column_name = ${literal(column_name)}`
}
if (privilege) {
sql += ` AND privilege = ${literal(privilege)}`
}
if (!include_system_schemas) {
sql += ` AND table_schema NOT LIKE 'pg_%'`
sql += ` AND table_schema != 'information_schema'`
}
if (limit) {
sql += ` LIMIT ${limit}`
}
if (offset) {
sql += ` OFFSET ${offset}`
}
console.log(sql)
return await this.query(sql)
}

async grant(
column_name: string,
{
table_schema,
table_name,
privilege_type,
role,
}: {
table_schema: string
table_name: string
privilege_type?: 'SELECT' | 'INSERT' | 'UPDATE'
role: string
}
): Promise<PostgresMetaResult<'OK'>> {
let sql = 'GRANT '
sql += privilege_type ?? 'ALL PRIVILEGES'
sql += ` (${ident(column_name)}) on ${ident(table_schema)}.${ident(table_name)}`
sql += ` to ${ident(role)}`
{
const { error } = await this.query(sql)
if (error) {
return { data: null, error }
}
}
return { data: 'OK', error: null }
}

async revoke(
column_name: string,
{
table_schema,
table_name,
privilege_type,
role,
}: {
table_schema: string
table_name: string
privilege_type?: 'SELECT' | 'INSERT' | 'UPDATE'
role: string
}
): Promise<PostgresMetaResult<'OK'>> {
let sql = 'REVOKE '
sql += privilege_type ?? 'ALL PRIVILEGES'
sql += ` (${ident(column_name)}) on ${ident(table_schema)}.${ident(table_name)}`
sql += ` to ${ident(role)}`
{
const { error } = await this.query(sql)
if (error) {
return { data: null, error }
}
}
return { data: 'OK', error: null }
}
}
56 changes: 56 additions & 0 deletions src/lib/PostgresMetaPermissions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { ident, literal } from 'pg-format'
import { PermissionListSchema } from './inputs.js'
import { permissionsSql } from './sql/index.js'
import { PostgresMetaResult, PostgresPermission } from './types.js'

export default class PostgresMetaColumns {
query: (sql: string) => Promise<PostgresMetaResult<any>>

constructor(query: (sql: string) => Promise<PostgresMetaResult<any>>) {
this.query = query
}

async list({
table_schema,
table_name,
column_name,
privilege,
include_system_schemas = false,
limit,
offset,
}: PermissionListSchema = {}): Promise<PostgresMetaResult<PostgresPermission[]>> {
let sql = `
WITH
permissions AS (${permissionsSql})
SELECT
*
FROM
permissions
WHERE
true`
if (table_schema) {
sql += ` AND table_schema = ${literal(table_schema)}`
}
if (table_name) {
sql += ` AND table_name = ${literal(table_name)}`
}
if (column_name) {
sql += ` AND column_name = ${literal(column_name)}`
}
if (privilege) {
sql += ` AND privilege = ${literal(privilege)}`
}
if (!include_system_schemas) {
sql += ` AND table_schema NOT LIKE 'pg_%'`
sql += ` AND table_schema != 'information_schema'`
}
if (limit) {
sql += ` LIMIT ${limit}`
}
if (offset) {
sql += ` OFFSET ${offset}`
}
console.log(sql)
return await this.query(sql)
}
}
102 changes: 102 additions & 0 deletions src/lib/PostgresMetaTablePermissions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { ident, literal } from 'pg-format'
import { tablePermissionsSql } from './sql/index.js'
import type { TablePermissionListSchema } from './inputs.js'
import type { PostgresMetaResult, PostgresTablePermission } from './types.js'

export default class PostgresMetaColumns {
query: (sql: string) => Promise<PostgresMetaResult<any>>

constructor(query: (sql: string) => Promise<PostgresMetaResult<any>>) {
this.query = query
}

async list({
table_schema,
table_name,
privilege,
include_system_schemas = false,
limit,
offset,
}: TablePermissionListSchema = {}): Promise<PostgresMetaResult<PostgresTablePermission[]>> {
let sql = `
WITH
table_permissions AS (${tablePermissionsSql})
SELECT
*
FROM
table_permissions
WHERE
true`
if (table_schema) {
sql += ` AND table_schema = ${literal(table_schema)}`
}
if (table_name) {
sql += ` AND table_name = ${literal(table_name)}`
}
if (privilege) {
sql += ` AND privilege = ${literal(privilege)}`
}
if (!include_system_schemas) {
sql += ` AND table_schema NOT LIKE 'pg_%'`
sql += ` AND table_schema != 'information_schema'`
}
if (limit) {
sql += ` LIMIT ${limit}`
}
if (offset) {
sql += ` OFFSET ${offset}`
}
console.log(sql)
return await this.query(sql)
}

async grant(
table_name: string,
{
table_schema,
privilege_type,
role,
}: {
table_schema: string
privilege_type?: 'SELECT' | 'INSERT' | 'UPDATE'
role: string
}
): Promise<PostgresMetaResult<'OK'>> {
let sql = 'GRANT '
sql += privilege_type ?? 'ALL PRIVILEGES'
sql += ` on ${ident(table_schema)}.${ident(table_name)}`
sql += ` to ${ident(role)}`
{
const { error } = await this.query(sql)
if (error) {
return { data: null, error }
}
}
return { data: 'OK', error: null }
}

async revoke(
table_name: string,
{
table_schema,
privilege_type,
role,
}: {
table_schema: string
privilege_type?: 'SELECT' | 'INSERT' | 'UPDATE'
role: string
}
): Promise<PostgresMetaResult<'OK'>> {
let sql = 'REVOKE '
sql += privilege_type ?? 'ALL PRIVILEGES'
sql += ` on ${ident(table_schema)}.${ident(table_name)}`
sql += ` to ${ident(role)}`
{
const { error } = await this.query(sql)
if (error) {
return { data: null, error }
}
}
return { data: 'OK', error: null }
}
}
3 changes: 3 additions & 0 deletions src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ export {
PostgresMetaOk,
PostgresMetaErr,
PostgresMetaResult,
PostgresColumnPermission,
PostgresColumn,
PostgresConfig,
PostgresExtension,
PostgresFunction,
PostgresFunctionCreate,
PostgresPermission,
PostgresPolicy,
PostgresPrimaryKey,
PostgresPublication,
Expand All @@ -16,6 +18,7 @@ export {
PostgresSchema,
PostgresSchemaCreate,
PostgresSchemaUpdate,
PostgresTablePermission,
PostgresTable,
PostgresTrigger,
PostgresType,
Expand Down
Loading