-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathaction.js
More file actions
114 lines (108 loc) · 3.52 KB
/
action.js
File metadata and controls
114 lines (108 loc) · 3.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
const db = require("@saltcorn/data/db");
const { eval_expression } = require("@saltcorn/data/models/expression");
const Table = require("@saltcorn/data/models/table");
module.exports = {
run_sql_code: {
namespace: "Code",
copilot_generate_trigger_prompt: async () => {
const tables = (await Table.find({})).filter(
(t) => !t.external && !t.provider_name,
);
if (!tables.length) return "";
const schemaPrefix = db.getTenantSchemaPrefix();
const ddl = tables
.map(
(t) =>
`CREATE TABLE "${t.name}" (${t.description ? `\n /* ${t.description} */` : ""}\n${t.fields
.map(
(f) =>
` "${f.name}" ${
f.primary_key && f.type?.name === "Integer"
? "SERIAL PRIMARY KEY"
: f.sql_type.replace(schemaPrefix, "")
}`,
)
.join(",\n")}\n)`,
)
.join(";\n\n");
return `The database has the following tables in PostgreSQL:\n\n${ddl}`;
},
configFields: ({ mode }) => [
{
name: "sql",
label: "SQL",
input_type: "code",
attributes: { mode: "text/x-sql" },
sublabel:
"Refer to row parameters in the order below with <code>$1</code>, <code>$2</code> etc",
},
{
name: "row_parameters",
label: "Row parameters",
sublabel:
"Comma separated list of row variables to use as SQL query parameters. User variables can be used as <code>user.id</code> etc",
type: "String",
},
{
name: "read_only",
label: "Read only",
sublabel: "Run the SQL in a read-only transactions",
type: "Bool",
},
...(mode === "workflow"
? [
{
label: "Variable",
name: "results_variable",
class: "validate-identifier",
sublabel: "Context variable to write to query results to",
type: "String",
required: true,
},
]
: []),
],
run: async ({
row,
configuration: { sql, row_parameters, read_only, results_variable },
user,
mode,
}) => {
const is_sqlite = db.isSQLite;
const phValues = [];
(row_parameters || "")
.split(",")
.filter((s) => s)
.forEach((sp0) => {
const sp = sp0.trim();
if (sp.startsWith("user.")) {
phValues.push(eval_expression(sp, {}, user));
} else if (typeof row[sp] === "undefined") phValues.push(null);
else phValues.push(row[sp]);
});
const client = is_sqlite ? db : await db.getClient();
db.sql_log("BEGIN;");
await client.query(`BEGIN;`);
if (!is_sqlite) {
db.sql_log(`SET LOCAL search_path TO "${db.getTenantSchema()}";`);
await client.query(
`SET LOCAL search_path TO "${db.getTenantSchema()}";`
);
if (read_only) {
db.sql_log(`SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY;`);
await client.query(
`SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY;`
);
}
}
db.sql_log(sql, phValues);
const qres = await client.query(sql, phValues);
db.sql_log("COMMIT;");
await client.query(`COMMIT;`);
if (!is_sqlite) client.release(true);
if (mode === "workflow" && results_variable)
return { [results_variable]: qres.rows };
else return qres.rows;
},
},
};