Public
Script
Readme

LLM-Safe Fork of @std/sqlite

We found that LLMs have trouble with the inputs and outputs of our @std/sqlite method.

  1. It expects the input to be (sql: string, args: any[]) but it's { sql: string, args: any[] }
  2. It expects the output to be objects, but they are arrays

Instead of struggling to teach it, we built this val to be a wrapper around @std/sqlite that adheres to what the LLMs expect.

This val is also backwards-compatible with @std/sqlite, so we're considering merging it in.

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
import { API_URL } from "https://esm.town/v/std/API_URL";
import { LibsqlError, type ResultSet, type Row, type TransactionMode } from "npm:@libsql/client";
import { z } from "npm:zod";
/**
* Every Val Town account comes with its own private
* [SQLite database](https://www.sqlite.org/) that
* is accessible from any of your vals.
* ([Docs ↗](https://docs.val.town/std/sqlite))
*/
export const sqlite = {
/**
* Executes a SQLite statement.
*
* @param {InStatement} statement - The SQLite statement to execute.
* @example String query:
* `sqlite.execute("SELECT 1;")`
* @example Query with arguments:
* `sqlite.execute({sql: "SELECT * from books WHERE year > ?;", args: [2020]})`
*/
execute,
/**
* Executes a batch of SQLite statements.
*
* @param {InStatement[]} statements - An array of SQLite statements to execute.
* @param {TransactionMode} [mode] - The transaction mode for the batch execution.
*/
batch,
};
// ------------
// Functions
// ------------
async function execute(statement: InStatement, args?: InArgs): Promise<ResultSet> {
const res = await fetch(`${API_URL}/v1/sqlite/execute`, {
method: "POST",
headers: {
Authorization: `Bearer ${Deno.env.get("valtown")}`,
},
body: JSON.stringify({ statement: normalizeStatement(statement, args) }),
});
if (!res.ok) {
throw createResError(await res.text());
}
const resultSet = await res.json();
return upgradeResultSet(resultSet);
}
async function batch(statements: InStatement[], mode?: TransactionMode): Promise<ResultSet[]> {
const res = await fetch(`${API_URL}/v1/sqlite/batch`, {
method: "POST",
headers: {
Authorization: `Bearer ${Deno.env.get("valtown")}`,
},
body: JSON.stringify({ statements: statements.map(s => normalizeStatement(s)), mode }),
});
if (!res.ok) {
throw createResError(await res.text());
}
const resultSets = await res.json();
return resultSets.map(upgradeResultSet);
}
function createResError(body: string) {
try {
const e = zLibsqlError.parse(JSON.parse(body));
// e.message already contains the code, and LibsqlError adds the
// code to the beginning, so we remove it here
const msg = e.message.replace(e.code, "").replace(/^:\s+/, "");
return new LibsqlError(msg, e.code, e.rawCode);
} catch (_) {
// Failed to parse libsql error
}
return new Error(body);
}
/* Val Town's Turso Proxy returns rows as an array of values
* Yet the LibSQL API has a Row type which behave as an array or object,
* ie you can access it via numerical index or string
*/
interface ImpoverishedResultSet extends ResultSet {
rows: any[];
}
function normalizeStatement(statement: InStatement, args?: InArgs) {
if (Array.isArray(statement)) {
// for the case of an array of arrays
return normalizeStatement(statement[0], statement[1]);
}
if (typeof statement === "string") {
if (args) {
return { sql: statement, args };
} else return statement;
}
else if (typeof statement === "object") {
if (statement.args) {
return statement;
}
Val Town is a social website to write and deploy JavaScript.
Build APIs and schedule functions from your browser.
Comments
Nobody has commented on this val yet: be the first!
August 19, 2024