|
| 1 | +-- |
| 2 | +-- OpenWorkers Database Schema - Tenant Helper Functions |
| 3 | +-- |
| 4 | +-- Functions callable by tenants via PostGate using qualified names: |
| 5 | +-- SELECT * FROM postgate_helpers.list_tables(); |
| 6 | +-- SELECT * FROM postgate_helpers.describe_table('users'); |
| 7 | +-- |
| 8 | + |
| 9 | +BEGIN; |
| 10 | + |
| 11 | +-- ============================================================================ |
| 12 | +-- SCHEMA: postgate_helpers |
| 13 | +-- ============================================================================ |
| 14 | + |
| 15 | +CREATE SCHEMA IF NOT EXISTS postgate_helpers; |
| 16 | + |
| 17 | +COMMENT ON SCHEMA postgate_helpers IS 'Utility functions for tenants (accessible via PostGate)'; |
| 18 | + |
| 19 | +-- ============================================================================ |
| 20 | +-- FUNCTION: list_tables() |
| 21 | +-- ============================================================================ |
| 22 | +-- Lists all tables in the current tenant's schema with row counts. |
| 23 | +-- |
| 24 | +-- Returns: |
| 25 | +-- table_name: Name of the table |
| 26 | +-- row_count: Number of rows in the table |
| 27 | +-- |
| 28 | +-- Example: |
| 29 | +-- SELECT * FROM postgate_helpers.list_tables(); |
| 30 | + |
| 31 | +CREATE OR REPLACE FUNCTION postgate_helpers.list_tables() |
| 32 | +RETURNS TABLE(table_name text, row_count bigint) |
| 33 | +LANGUAGE plpgsql |
| 34 | +SECURITY DEFINER |
| 35 | +AS $$ |
| 36 | +DECLARE |
| 37 | + v_schema text; |
| 38 | + tbl record; |
| 39 | + cnt bigint; |
| 40 | +BEGIN |
| 41 | + v_schema := current_schema(); |
| 42 | + |
| 43 | + -- Prevent access to system schemas |
| 44 | + IF v_schema IN ('public', 'postgate_helpers') THEN |
| 45 | + RAISE EXCEPTION 'Cannot list tables in system schemas'; |
| 46 | + END IF; |
| 47 | + |
| 48 | + FOR tbl IN |
| 49 | + SELECT tablename |
| 50 | + FROM pg_tables |
| 51 | + WHERE schemaname = v_schema |
| 52 | + ORDER BY tablename |
| 53 | + LOOP |
| 54 | + EXECUTE format('SELECT count(*) FROM %I.%I', v_schema, tbl.tablename) INTO cnt; |
| 55 | + table_name := tbl.tablename; |
| 56 | + row_count := cnt; |
| 57 | + RETURN NEXT; |
| 58 | + END LOOP; |
| 59 | +END; |
| 60 | +$$; |
| 61 | + |
| 62 | +COMMENT ON FUNCTION postgate_helpers.list_tables() IS 'List all tables in the current tenant schema with row counts'; |
| 63 | + |
| 64 | +-- ============================================================================ |
| 65 | +-- FUNCTION: describe_table(table_name) |
| 66 | +-- ============================================================================ |
| 67 | +-- Describes columns of a table in the current tenant's schema. |
| 68 | +-- |
| 69 | +-- Parameters: |
| 70 | +-- p_table_name: Name of the table to describe |
| 71 | +-- |
| 72 | +-- Returns: |
| 73 | +-- column_name: Name of the column |
| 74 | +-- data_type: PostgreSQL data type |
| 75 | +-- is_nullable: Whether the column allows NULL |
| 76 | +-- column_default: Default value expression |
| 77 | +-- is_primary_key: Whether the column is part of the primary key |
| 78 | +-- |
| 79 | +-- Example: |
| 80 | +-- SELECT * FROM postgate_helpers.describe_table('users'); |
| 81 | + |
| 82 | +CREATE OR REPLACE FUNCTION postgate_helpers.describe_table(p_table_name text) |
| 83 | +RETURNS TABLE( |
| 84 | + column_name text, |
| 85 | + data_type text, |
| 86 | + is_nullable boolean, |
| 87 | + column_default text, |
| 88 | + is_primary_key boolean |
| 89 | +) |
| 90 | +LANGUAGE plpgsql |
| 91 | +SECURITY DEFINER |
| 92 | +AS $$ |
| 93 | +DECLARE |
| 94 | + v_schema text; |
| 95 | +BEGIN |
| 96 | + v_schema := current_schema(); |
| 97 | + |
| 98 | + -- Prevent access to system schemas |
| 99 | + IF v_schema IN ('public', 'postgate_helpers') THEN |
| 100 | + RAISE EXCEPTION 'Cannot describe tables in system schemas'; |
| 101 | + END IF; |
| 102 | + |
| 103 | + RETURN QUERY |
| 104 | + SELECT |
| 105 | + c.column_name::text, |
| 106 | + c.data_type::text, |
| 107 | + (c.is_nullable = 'YES')::boolean, |
| 108 | + c.column_default::text, |
| 109 | + COALESCE( |
| 110 | + (SELECT true |
| 111 | + FROM information_schema.table_constraints tc |
| 112 | + JOIN information_schema.key_column_usage kcu |
| 113 | + ON tc.constraint_name = kcu.constraint_name |
| 114 | + AND tc.table_schema = kcu.table_schema |
| 115 | + WHERE tc.constraint_type = 'PRIMARY KEY' |
| 116 | + AND tc.table_schema = v_schema |
| 117 | + AND tc.table_name = p_table_name |
| 118 | + AND kcu.column_name = c.column_name |
| 119 | + LIMIT 1), |
| 120 | + false |
| 121 | + )::boolean |
| 122 | + FROM information_schema.columns c |
| 123 | + WHERE c.table_schema = v_schema |
| 124 | + AND c.table_name = p_table_name |
| 125 | + ORDER BY c.ordinal_position; |
| 126 | +END; |
| 127 | +$$; |
| 128 | + |
| 129 | +COMMENT ON FUNCTION postgate_helpers.describe_table(text) IS 'Describe columns of a table in the current tenant schema'; |
| 130 | + |
| 131 | +-- ============================================================================ |
| 132 | +-- PERMISSIONS |
| 133 | +-- ============================================================================ |
| 134 | + |
| 135 | +GRANT USAGE ON SCHEMA postgate_helpers TO PUBLIC; |
| 136 | +GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA postgate_helpers TO PUBLIC; |
| 137 | + |
| 138 | +COMMIT; |
0 commit comments