mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-17 16:03:06 +00:00
feat: connect to a data table with every role of the job's viewer
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
9fa9b77926
commit
87c87facd2
@@ -111,6 +111,12 @@ export interface DatatableSqlTemplateFunction extends SqlTemplateFunction {
|
||||
export interface DatatableOptions {
|
||||
/** The data table role to connect as. Omit to get the data table's default role. */
|
||||
role?: string;
|
||||
/**
|
||||
* `"viewer"` connects with every role of the job's viewer at once: the user of the app the job
|
||||
* runs for, or whoever ran the script. The server resolves who that is; it cannot be combined
|
||||
* with `role`.
|
||||
*/
|
||||
as?: "viewer";
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -140,17 +146,27 @@ const ROLE_NAME_RE = /^[A-Za-z0-9_-]{1,63}$/;
|
||||
function datatableProvider(
|
||||
name: string,
|
||||
schema?: string,
|
||||
role?: string
|
||||
opts?: DatatableOptions
|
||||
): SqlProvider {
|
||||
const role = opts?.role;
|
||||
if (role !== undefined && !ROLE_NAME_RE.test(role)) {
|
||||
throw new Error(
|
||||
`Invalid data table role '${role}': only letters, digits, '_' and '-' are allowed`
|
||||
);
|
||||
}
|
||||
const as = opts?.as;
|
||||
if (as !== undefined && as !== "viewer") {
|
||||
throw new Error(`Invalid data table option as: '${as}': the only value is 'viewer'`);
|
||||
}
|
||||
if (as !== undefined && role !== undefined) {
|
||||
throw new Error("A data table is used as a role or as the viewer, not both");
|
||||
}
|
||||
return {
|
||||
providerName: "datatable",
|
||||
language: "postgresql",
|
||||
extraArgs: { database: `datatable://${name}` },
|
||||
// In the reference rather than an annotation: a worker that does not know `?as=` refuses
|
||||
// the reference, where it would skip an annotation and connect as the default role.
|
||||
extraArgs: { database: `datatable://${name}${as ? "?as=viewer" : ""}` },
|
||||
annotations: () => (role !== undefined ? `-- role ${role}\n` : ""),
|
||||
formatArgDecl: (argNum) => `-- $${argNum} arg${argNum}`,
|
||||
formatArgUsage: (argNum, explicitType, inferredType) =>
|
||||
@@ -348,6 +364,8 @@ function buildSqlTemplateFunction(provider: SqlProvider): SqlTemplateFunction {
|
||||
* @param name - Database/datatable name (default: "main")
|
||||
* @param opts.role - Connect as this data table role instead of the data table's default one.
|
||||
* Only meaningful on a data table under roles, and only for a role you are a tenant of.
|
||||
* @param opts.as - `"viewer"` connects with every role of the job's viewer at once, so row-level
|
||||
* security policies see the user of the app rather than its publisher.
|
||||
* @returns SQL template function for building parameterized queries
|
||||
* @example
|
||||
* let sql = wmill.datatable()
|
||||
@@ -360,13 +378,16 @@ function buildSqlTemplateFunction(provider: SqlProvider): SqlTemplateFunction {
|
||||
* @example
|
||||
* // Read through a restricted role
|
||||
* let sql = wmill.datatable("main", { role: "analytics" })
|
||||
* @example
|
||||
* // In an app's backend runnable: read what the app's viewer may read
|
||||
* let sql = wmill.datatable("main", { as: "viewer" })
|
||||
*/
|
||||
export function datatable(
|
||||
name: string = "main",
|
||||
opts?: DatatableOptions
|
||||
): DatatableSqlTemplateFunction {
|
||||
let { name: n, schema } = parseName(name);
|
||||
let provider = datatableProvider(n, schema, opts?.role);
|
||||
let provider = datatableProvider(n, schema, opts);
|
||||
let sqlFn = buildSqlTemplateFunction(provider) as DatatableSqlTemplateFunction;
|
||||
// `.query(sql, ...params)` is for SQL strings that already contain
|
||||
// positional placeholders ($1, $2, ...). We DON'T go through the template
|
||||
|
||||
Reference in New Issue
Block a user