azion
Version:
Azion Packages for Edge Computing.
510 lines (509 loc) • 14.5 kB
JavaScript
const y = (r, t) => r?.length > t ? r.slice(0, t) : r;
async function m(r, t, s, o = !0) {
const e = await fetch(r, t);
if (!e.ok)
try {
const n = await e.json();
if (s && console.log("Error response body:", n), n.errors && Array.isArray(n.errors) && n.errors.length > 0 || n.detail || n.message)
return n;
const a = `HTTP error! Status: ${e.status} - ${e.statusText}`;
throw s && console.log(`Error in fetch: ${a}`), new Error(a);
} catch {
const n = `HTTP error! Status: ${e.status} - ${e.statusText}`;
throw s && console.log(`Error in fetch: ${n}`), new Error(n);
}
if (o) {
const n = e.headers.get("content-type");
if (!n || !n.includes("application/json")) {
const i = `Expected JSON response, but got: ${await e.text()}`;
throw s && console.log(`Error in fetch: ${i}`), new Error(i);
}
return await e.json();
} else
return await e.text();
}
const h = (r = "production") => ({
production: "https://api.azion.com/v4/workspace/sql/databases",
development: "/v4/workspace/sql/databases",
staging: "https://stage-api.azion.com/v4/workspace/sql/databases"
})[r], w = (r, t = {}) => {
const s = {
Accept: "application/json",
...t
};
return r ? {
...s,
Authorization: `Token ${r}`
} : s;
}, E = (r, t, s) => {
const o = {
method: r,
headers: t,
credentials: "include"
};
return s && (o.body = s), o;
}, D = (r, t, s) => {
let o = { message: "Error unknown", operation: s };
if (t.errors && Array.isArray(t.errors) && t.errors.length > 0) {
const e = t.errors[0];
if (e.detail)
return o = {
message: e.detail,
operation: s
}, o;
if (e.title)
return o = {
message: e.title,
operation: s
}, o;
}
return r.forEach((e) => {
t[e] && (o = {
message: Array.isArray(t[e]) ? t[e].join(", ") : t[e],
operation: s
});
}), o;
}, Q = async (r, t, s, o = "production") => {
try {
const e = h(o), n = w(r, { "Content-Type": "application/json" }), a = E("POST", n, JSON.stringify({ name: t })), c = await m(e, a, s);
if (c.errors)
return {
error: D([], c, "post database")
};
const i = c.data;
return s && console.log("Response Post Database", JSON.stringify(c)), {
state: c.state,
data: i
};
} catch (e) {
return s && console.error("Error creating EdgeDB:", e), {
error: { message: e.message, operation: "post database" }
};
}
}, z = async (r, t, s, o = "production") => {
try {
const e = h(o), n = w(r), a = E("DELETE", n), c = await m(`${e}/${t}`, a, s);
return c.errors ? {
error: D([], c, "delete database")
} : c;
} catch (e) {
return s && console.error("Error deleting EdgeDB:", e), {
error: { message: e.toString(), operation: "delete database" }
};
}
}, W = async (r, t, s, o, e = "production") => {
try {
const n = h(e), a = w(r, { "Content-Type": "application/json" }), c = E("POST", a, JSON.stringify({ statements: s })), i = await m(`${n}/${t}/query`, c, o);
if (i.errors)
return {
error: D([], i, "post query")
};
const d = i.data;
if (o) {
const p = {
...i,
data: i?.data?.map((u) => ({
...u,
results: {
...u.results,
rows: y(u.results?.rows, 10)
}
}))
};
console.log("Response Query:", JSON.stringify(p));
}
return {
state: i.state,
data: d
};
} catch (n) {
return o && console.error("Error querying EdgeDB:", n), {
error: { message: n.toString(), operation: "post query" }
};
}
}, A = async (r, t, s, o = "production") => {
try {
const e = h(o), n = new URL(e);
t && Object.entries(t).forEach(([p, u]) => {
u !== void 0 && n.searchParams.append(p, u.toString());
});
const a = w(r), c = E("GET", a), i = await m(n.toString(), c, s);
if (i.errors)
return {
error: D([], i, "get databases")
};
const d = i.results;
if (s) {
const p = {
...i,
results: y(i.results, 10)
};
console.log("Response Databases:", JSON.stringify(p));
}
return {
count: i.count,
results: d
};
} catch (e) {
return s && console.error("Error getting all EdgeDBs:", e), {
error: { message: e.message, operation: "get databases" }
};
}
}, R = ({ state: r, results: t }) => {
let s = [];
if (t instanceof Array) {
if (t.length === 0)
return {
results: []
};
let o = null;
s = t?.map((e) => (e?.rows && (o = e.rows.map((n) => {
const a = {};
return e?.columns && e.columns.forEach((c, i) => {
a[c] = n[i];
}), a;
})), {
statement: e.statement,
rows: o
}));
}
return {
state: r,
results: s
};
}, T = () => globalThis.Azion?.Sql || null;
class J {
database = null;
constructor() {
this.database = T()?.Database || null;
}
/**
* Maps query results to a structured format.
* @param {Array<{ statement: string; result: Azion.Sql.Rows }>} resultRows - The result rows from the query.
* @returns {Promise<Array<QueryResult | NonSelectQueryResult>>} The mapped query results.
*/
mapperQuery = async (t) => {
const s = [];
for (const o of t) {
const e = o.result.columnCount();
if (e === 0)
continue;
const n = [];
for (let i = 0; i < e; i++)
n.push(o.result.columnName(i));
let a = await o.result.next();
const c = [];
for (; a; ) {
const i = [];
for (let d = 0; d < e; d++)
i.push(a.getValue(d));
c.push(i), a = await o.result.next();
}
s.push({
statement: o?.statement?.split(" ")[0],
// TODO: This can improve
columns: n,
rows: c
});
}
return Promise.resolve(s);
};
/**
* Executes a series of SQL statements on the specified database.
* @param {string} name - The name of the database.
* @param {string[]} statements - The SQL statements to execute.
* @param {AzionClientOptions} [options] - Optional client options.
* @returns {Promise<Array<{ statement: string; result: Azion.Sql.Rows }>>} The results of the executed statements.
*/
query = async (t, s, o) => {
if (this.database?.open) {
const e = await this.database?.open(t), n = s.map(async (a) => {
const c = await e?.query(a);
return { statement: a, result: c };
});
try {
const a = await Promise.all(n);
if (a.every((c) => c.result?.columnCount() > 0))
return a;
} catch (a) {
throw o?.debug && console.error("Error querying:", a?.message), a;
}
}
return [];
};
}
const q = async (r, t, s, o) => {
const e = await A(r, { search: t, page_size: 1 }, o?.debug, o?.env);
if (e?.error)
return { error: e.error };
const n = e?.results?.[0];
if (!n?.name)
return {
error: {
message: `Database ${t} not found`,
operation: "apiQuery"
}
};
const { state: a, data: c, error: i } = await W(r, n.id, s, o?.debug, o?.env);
if (i)
return {
error: {
message: i.message || "Error executing query",
operation: "apiQuery"
}
};
const d = c?.map((u, f) => ({
statement: s[f]?.split(" ")[0],
columns: u?.results?.columns && u?.results?.columns.length > 0 ? u?.results?.columns : void 0,
rows: u?.results?.rows && u?.results?.rows.length > 0 ? u?.results?.rows : void 0,
error: u?.error || void 0
}));
if (o?.debug && d) {
const u = d.map((f) => ({
...f,
rows: y(f?.rows || [], 10)
}));
console.log(
"Response Query:",
JSON.stringify({
state: a,
results: u,
toObject: () => null
})
);
}
const p = d && d.filter((u) => u?.error !== void 0);
return {
data: {
state: a,
results: d,
toObject: () => R({
results: d,
state: a
})
},
// If there are, return an error response
error: p && p.length > 0 ? {
message: p.map((u) => u?.error || "Error executing query").join(", "),
operation: "apiQuery"
} : void 0
};
}, N = async (r, t, s, o) => {
try {
const e = new J(), n = await e.query(t, s, o), a = {
state: "executed-runtime",
results: [],
toObject: () => null
}, c = await e.mapperQuery(n);
if (c && c.length > 0 && (a.state = "executed-runtime", a.results = c), o?.debug) {
const i = {
...a,
results: a.results.map((d) => ({
...d,
rows: y(d?.rows || [], 10)
}))
};
console.log("Response Query:", JSON.stringify(i));
}
return {
data: {
...a,
toObject: () => R(a)
}
};
} catch (e) {
return {
error: {
message: e?.message || "Error executing query",
operation: "executing query"
}
};
}
};
function $(r, t) {
return console.error("An unexpected error occurred:", r), {
error: {
message: "An unexpected error occurred during the operation",
operation: t
}
};
}
const x = () => typeof window < "u" && typeof window.document < "u", _ = !x() && process?.env.AZION_DEBUG === "true", l = (r) => x() ? r ?? "" : r ?? process?.env.AZION_TOKEN ?? "", j = (r) => r ?? !!_, B = (r) => x() ? r ?? "production" : r ?? process?.env.AZION_ENV ?? "production", g = (r) => ({
...r,
debug: j(r?.debug),
env: B(r?.env)
}), O = {
parse: (r) => ({
id: r.id,
name: r.name,
status: r.status,
active: r.active,
lastModified: r.last_modified,
lastEditor: r.last_editor,
productVersion: r.product_version
})
}, P = async (r, t, s) => {
try {
const o = g(s), e = await Q(l(r), t, o.debug, o.env);
if (e.data) {
const n = O.parse(e.data);
return {
data: {
state: e.state ?? "executed",
...n,
query: (a) => b(l(r), t, a, o),
execute: (a) => v(l(r), t, a, o),
getTables: (a) => S(t, {
...a,
debug: o.debug
})
}
};
}
return {
error: e.error
};
} catch (o) {
return $(o, "create database");
}
}, U = async (r, t, s) => {
const o = g(s), e = await z(l(r), t, o.debug, o.env);
return e?.state ? {
data: {
state: e.state ?? "executed"
}
} : {
error: e.error
};
}, C = async (r, t, s) => {
try {
const o = g(s), e = await A(
l(r),
{ search: t, page_size: 1 },
o.debug,
o.env
);
if (e.results && e.results.length > 0) {
const n = e.results.filter((c) => c.name === t);
return n.length === 0 ? {
error: {
message: `Database ${t} not found`,
operation: "get database"
}
} : {
data: {
...O.parse(n[0]),
query: (c) => b(l(r), t, c, o),
execute: (c) => v(l(r), t, c, o),
getTables: (c) => S(t, {
...c,
debug: o.debug
})
}
};
}
return {
error: e.error
};
} catch (o) {
return $(o, "get database");
}
}, M = async (r, t, s) => {
const o = g(s), e = await A(l(r), t, o.debug, o.env);
return e.error ? {
error: e.error
} : !e?.results || e?.results?.length === 0 ? {
data: {
count: e.count ?? 0,
databases: []
}
} : {
data: {
count: e.count ?? 0,
databases: e.results.map((n) => ({
...O.parse(n),
query: (a) => b(l(r), n.name, a, o),
execute: (a) => v(l(r), n.name, a, o),
getTables: (a) => S(n.name, {
...a,
debug: o.debug
})
}))
}
};
}, b = async (r, t, s, o) => {
const e = g(o);
if (!t || t === "")
return {
error: {
message: "Database name is required",
operation: "query database"
}
};
if (e.debug && console.log(`Executing statements on database ${t}: ${s}`), !Array.isArray(s) || s.length === 0)
return {
error: {
message: 'No statements to execute. Please provide at least one statement. e.g ["SELECT * FROM users"]',
operation: "query database"
}
};
if (!s.some(
(a) => ["SELECT", "PRAGMA"].some((c) => a.trim().toUpperCase().startsWith(c))
))
throw new Error("Only read statements are allowed");
return e.external || !T() ? q(r, t, s, e) : N(r, t, s, e);
}, v = async (r, t, s, o) => {
const e = g(o);
if (e.debug && console.log(`Executing statements on database ${t}: ${s}`), !t || t === "")
return {
error: {
message: "Database name is required",
operation: "execute database"
}
};
if (!Array.isArray(s) || s.length === 0)
return {
error: {
message: `No statements to execute. Please provide at least one statement. e.g ["INSERT INTO users (name) VALUES ('John')"]`,
operation: "execute database"
}
};
const n = s.some(
(c) => ["INSERT", "UPDATE", "DELETE"].some((i) => c.trim().toUpperCase().startsWith(i))
), a = s.some(
(c) => c.toUpperCase().match(/^(CREATE|DROP|ALTER|ATTACH|VACUUM|PRAGMA)/)
);
return !a && !n ? {
error: {
message: "Only write statements are allowed",
operation: "execute database"
}
} : a && e.force === !1 ? {
error: {
message: "To admin statements, you need to set the force option to true",
operation: "execute database"
}
} : e.external || !T() ? q(r, t, s, e) : N(r, t, s, e);
}, I = async (r, t) => P(l(), r, t), L = (r, t) => U(l(), r, t), V = async (r, t) => C(l(), r, t), H = (r, t) => M(l(), r, t), S = async (r, t) => {
const s = g(t);
return b(l(), r, ["PRAGMA table_list"], s);
}, G = (r, t, s) => b(l(), r, t, s), F = async (r, t, s) => v(l(), r, t, s), Z = (r) => {
const t = l(r?.token), s = j(r?.options?.debug);
return {
createDatabase: (e) => P(t, e, { ...r?.options, debug: s }),
deleteDatabase: (e) => U(t, e, { ...r?.options, debug: s }),
getDatabase: (e) => C(t, e, { ...r?.options, debug: s }),
getDatabases: (e) => M(t, e, { ...r?.options, debug: s })
};
};
export {
Z as createClient,
I as createDatabase,
Z as default,
L as deleteDatabase,
V as getDatabase,
H as getDatabases,
S as getTables,
F as useExecute,
G as useQuery
};