Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@kikko-land/kikko

Package Overview
Dependencies
Maintainers
1
Versions
20
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@kikko-land/kikko - npm Package Compare versions

Comparing version 0.4.0 to 0.5.0

dist/afterTransaction.d.ts

6

CHANGELOG.md
# @kikko-land/core
## 0.5.0
### Minor Changes
- 056a744: Add new fluent api
## 0.4.0

@@ -4,0 +10,0 @@

777

dist/index.es.js

@@ -1,42 +0,38 @@

import { sql as S } from "@kikko-land/sql";
const y = (t, e) => {
if (!t.localState.transactionsState)
import N from "lodash.isequal";
import { sql as S } from "@kikko-land/boono-sql";
export * from "@kikko-land/boono-sql";
const x = (e, r) => {
if (!e.__state.localState.transactionsState.current)
throw new Error("Not in transaction.");
const r = [], n = (a) => (c, o) => {
e(a, c, o);
for (const i of r)
i();
const t = e.__state.localState.transactionsState.current, i = [], a = (u) => (s, o) => {
if (t.id === o.id) {
r(u, s, t);
for (const c of i)
c();
}
};
r.push(
t.sharedState.eventsEmitter.on(
i.push(
e.__state.sharedState.eventsEmitter.on(
"transactionCommitted",
n("committed")
a("committed")
)
), r.push(
t.sharedState.eventsEmitter.on(
), i.push(
e.__state.sharedState.eventsEmitter.on(
"transactionRollbacked",
n("rollbacked")
a("rollbacked")
)
);
}, A = (t, e) => {
y(t, (r, n, a) => {
r === "committed" && e(n, a);
});
}, L = (t, e) => {
y(t, (r, n, a) => {
r === "rollbacked" && e(n, a);
});
};
function T() {
const t = {};
function Q() {
const e = {};
return {
async emit(e, ...r) {
const n = t[e] || [];
for (const a of n)
await a(...r);
async emit(r, ...t) {
const i = e[r] || [];
for (const a of i)
await a(...t);
},
on(e, r) {
return (t[e] = t[e] || []).push(r), () => {
const n = t[e] || [];
t[e] = n.filter((a) => a !== r);
on(r, t) {
return (e[r] = e[r] || []).push(t), () => {
const i = e[r] || [];
e[r] = i.filter((a) => a !== t);
};

@@ -46,331 +42,504 @@ }

}
class h extends Error {
class g extends Error {
}
class b extends Error {
class E extends Error {
}
const v = (t, e) => ({
__state: {
subscriptions: [],
value: t,
isStopped: !1,
onStop: []
},
get isStopped() {
return this.__state.isStopped;
},
set value(r) {
if (this.isStopped)
throw new Error(`reactiveVar ${e} is stopped!`);
this.__state.value = r;
for (const n of this.__state.subscriptions)
n(r);
},
get value() {
if (this.isStopped)
throw new Error(`reactiveVar ${e} is stopped!`);
return this.__state.value;
},
subscribe(r, n = !0) {
if (this.isStopped)
throw new Error(`reactiveVar ${e} is stopped!`);
return this.__state.subscriptions.push(r), n && r(this.__state.value), () => {
this.__state.subscriptions = this.__state.subscriptions.filter((a) => a !== r);
};
},
waitTill(r, n) {
if (this.isStopped)
throw new Error(`reactiveVar ${e} is stopped!`);
return new Promise((c, o) => {
var l;
const i = [], s = () => {
for (const u of i)
u();
const A = (e, r) => {
const t = r.deduplicate === void 0 ? !0 : r.deduplicate;
return {
__state: {
subscriptions: [],
value: e,
isStopped: !1,
onStop: []
},
get isStopped() {
return this.__state.isStopped;
},
set value(i) {
if (this.isStopped)
throw new Error(`reactiveVar ${r.label} is stopped!`);
if (!(t && N(this.__state.value, i))) {
this.__state.value = i;
for (const a of this.__state.subscriptions)
a(i);
}
},
get value() {
if (this.isStopped)
throw new Error(`reactiveVar ${r.label} is stopped!`);
return this.__state.value;
},
subscribe(i, a = !0) {
if (this.isStopped)
throw new Error(`reactiveVar ${r.label} is stopped!`);
let u;
const s = (o) => {
u && u(), u = i(o);
};
if (i.push(
((l = n == null ? void 0 : n.stopIf) == null ? void 0 : l.subscribe((u) => {
!u || (s(), o(
new b(
`waitUntil for reactiveVar ${e} is stopped due to stop signal`
)
));
}, !0)) || (() => {
})
), i.push(
this.subscribe((u) => {
!r(u) || (s(), c());
}, !0)
), (n == null ? void 0 : n.timeout) === void 0 || (n == null ? void 0 : n.timeout) !== "infinite") {
const u = setTimeout(
() => {
s(), o(
new h(
`waitUntil for reactiveVar ${e} is timed out`
)
);
},
(n == null ? void 0 : n.timeout) === void 0 ? 5e3 : n.timeout
);
i.push(() => {
clearTimeout(u);
return this.__state.subscriptions.push(s), a && s(this.__state.value), () => {
this.__state.subscriptions = this.__state.subscriptions.filter((o) => o !== s);
};
},
waitTill(i, a) {
const u = new E(
`waitUntil for reactiveVar ${r.label} is stopped due to stop signal`
), s = new g(
`waitUntil for reactiveVar ${r.label} is timed out`
), o = new E(
`waitUntil for reactiveVar ${r.label} is stopped due to reactive var stop`
);
if (this.isStopped)
throw new Error(`reactiveVar ${r.label} is stopped!`);
return new Promise((h, l) => {
var d;
const n = [], m = () => {
for (const f of n)
f();
};
if (n.push(
((d = a == null ? void 0 : a.stopIf) == null ? void 0 : d.subscribe((f) => {
!f || (m(), l(u));
}, !0)) || (() => {
})
), n.push(
this.subscribe((f) => {
!i(f) || (m(), h());
}, !0)
), (a == null ? void 0 : a.timeout) === void 0 || typeof (a == null ? void 0 : a.timeout) == "number") {
const f = setTimeout(
() => {
m(), l(s);
},
(a == null ? void 0 : a.timeout) === void 0 ? 6e4 : a.timeout
);
n.push(() => {
clearTimeout(f);
});
}
this.__state.onStop.push(() => {
m(), l(o);
});
}
this.__state.onStop.push(() => {
s(), o(
new b(
`waitUntil for reactiveVar ${e} is stopped due to reactive var stop`
)
);
});
});
},
stop() {
if (this.isStopped)
throw new Error(`reactiveVar ${e} is already stopped!`);
this.__state.subscriptions = [];
for (const r of this.__state.onStop)
r();
this.__state.isStopped = !0;
}
}), E = (t, e) => {
},
stop() {
if (this.isStopped)
throw new Error(`reactiveVar ${r.label} is already stopped!`);
this.__state.subscriptions = [];
for (const i of this.__state.onStop)
i();
this.__state.isStopped = !0;
}
};
}, q = (e, r) => {
const {
sharedState: { runningState: r, dbName: n }
} = t;
if (r.value !== "running")
throw new Error(`Failed to start ${e()}, db ${n} is stopping`);
}, p = (t) => t.map((e) => e.preparedQuery);
function w() {
let t = "";
const e = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", r = e.length;
for (let n = 0; n < 32; n++)
t += e.charAt(Math.floor(Math.random() * r));
return t;
__state: {
sharedState: { runningState: t, dbName: i }
}
} = e;
if (t.value !== "running")
throw new Error(`Failed to start ${r()}, db ${i} is stopping`);
}, R = (e) => e.map((r) => r.preparedQuery);
function v() {
let e = "";
const r = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", t = r.length;
for (let i = 0; i < 32; i++)
e += r.charAt(Math.floor(Math.random() * t));
return e;
}
const _ = (t) => {
const { current: e, queue: r } = t;
const C = (e) => {
const { current: r, queue: t } = e;
return `current running job: ${JSON.stringify(
e,
r,
null,
2
)}, queue: ${JSON.stringify(r, null, 2)}`;
}, f = async (t, e) => {
const r = w(), n = { ...e, id: r }, { current: a, queue: c } = t.value;
if (a || c.length > 0) {
const o = t.waitTill((i) => {
var s;
return ((s = i.current) == null ? void 0 : s.id) === r;
)}, queue: ${JSON.stringify(t, null, 2)}`;
}, y = async (e, r) => {
const t = v(), i = { ...r, id: t }, { current: a, queue: u } = e.value;
if (a || u.length > 0) {
const s = e.waitTill((o) => {
var c;
return ((c = o.current) == null ? void 0 : c.id) === t;
});
t.value = {
queue: [...c, n],
e.value = {
queue: [...u, i],
current: a
};
try {
await o;
} catch (i) {
throw i instanceof h ? new h(
`Timeout error while job acquire: '${i.message}'. Is it a dead lock? ${_(
t.value
)}, jobToAcquire: ${JSON.stringify(n, null, 2)}`
) : i;
await s;
} catch (o) {
throw o instanceof g ? new g(
`Timeout error while job acquire: '${o.message}'. Is it a dead lock? ${C(
e.value
)}, jobToAcquire: ${JSON.stringify(i, null, 2)}`
) : o;
}
} else
t.value = {
e.value = {
queue: [],
current: n
current: i
};
return n;
}, m = (t, e) => {
const { current: r, queue: n } = t.value;
if ((r == null ? void 0 : r.id) !== e.id)
return i;
}, b = (e, r) => {
const { current: t, queue: i } = e.value;
if ((t == null ? void 0 : t.id) !== r.id)
throw new Error(
`Can't release job that is not currently running, ${_(
t.value
)}, toRelease: ${JSON.stringify(e, null, 2)}`
`Can't release job that is not currently running, ${C(
e.value
)}, toRelease: ${JSON.stringify(r, null, 2)}`
);
t.value = { queue: n.slice(1), current: n[0] };
}, I = async (t) => {
e.value = { queue: i.slice(1), current: i[0] };
}, F = async (e) => {
try {
return t.waitTill(
({ queue: e, current: r }) => e.length === 0 && r === void 0,
return e.waitTill(
({ queue: r, current: t }) => r.length === 0 && t === void 0,
{ timeout: 3e4 }
);
} catch (e) {
throw e instanceof h ? new h(
`Timeout error while awaiting all jobs done: '${e.message}'. Is it a dead lock?`
) : e;
} catch (r) {
throw r instanceof g ? new g(
`Timeout error while awaiting all jobs done: '${r.message}'. Is it a dead lock?`
) : r;
}
}, R = async ({
dbName: t,
plugins: e,
queriesMiddlewares: r,
dbBackend: n
}) => {
const a = v(
"running",
"runningState"
), c = (await n)({
dbName: t
}), o = v(
{
queue: [],
current: void 0
},
"jobsState"
), i = {
}, k = ["yellow", "cyan", "magenta"], M = async ({ db: e, queries: r }) => {
var h, l, n;
const {
localState: { transactionsState: t },
sharedState: {
clientId: w(),
dbBackend: c,
dbName: t,
runningState: a,
eventsEmitter: T(),
jobsState: o,
transactionsState: {}
transactionsState: i,
jobsState: a,
dbBackend: u
},
localState: {
queriesMiddlewares: r || [],
transactionsState: {}
}
}, s = await f(i.sharedState.jobsState, {
type: "initDb",
name: t
});
let l = i;
try {
const u = () => i.sharedState.runningState.value;
if (u() !== "running" || (await c.initialize(), u() !== "running"))
return i;
for (const d of e || [])
l = d(l);
} finally {
m(o, s);
}
return await i.sharedState.eventsEmitter.emit("initialized", i), l;
}, x = async (t) => {
t.sharedState.runningState.value = "stopping", await I(t.sharedState.jobsState), await t.sharedState.dbBackend.stop(), t.sharedState.runningState.value = "stopped", queueMicrotask(() => {
t.sharedState.runningState.stop(), t.sharedState.jobsState.stop();
});
}, $ = async ({
dbState: t,
queries: e
}) => {
var l;
const {
localState: { transactionsState: r, suppressLog: n },
sharedState: {
transactionsState: a,
jobsState: c,
dbBackend: o
}
} = t;
if (r.current || E(t, () => JSON.stringify(e)), r.current && a.current && r.current.id !== a.current.id)
sharedState: s
} = e.__state;
if (t.current || q(e, () => JSON.stringify(r)), t.current && (i == null ? void 0 : i.current) && t.current.id !== i.current.id)
throw new Error(
"Internal error: local running transaction is not the same as shared state transaction"
);
let i;
r.current || (i = await f(c, {
let o;
const c = R(r.map((m) => m.toSql()));
t.current || (o = await y(a, {
type: "runQueries",
queries: e.map((u) => u.toSql())
queries: r.map((m) => m.toSql())
}));
const s = {
log: {
suppress: Boolean(n),
transactionId: (l = r.current) == null ? void 0 : l.id
try {
const m = performance.now(), { result: d, performance: f } = await u.execQueries(
c
), I = performance.now();
if (!e.__state.localState.suppressLog) {
t.current && t.current.id !== s.transactionLoggingState.id && (s.transactionLoggingState.id = t.current.id, s.transactionLoggingState.i++), (h = t == null ? void 0 : t.current) != null && h.id || (s.transactionLoggingState.id = void 0);
const _ = d.map(({ performance: T }, w) => {
const j = [
T.prepareTime !== void 0 ? `prepareTime=${(T.prepareTime / 1e3).toFixed(4)}` : "",
T.execTime !== void 0 ? `execTime=${(T.execTime / 1e3).toFixed(4)}` : "",
T.freeTime !== void 0 ? `freeTime=${(T.freeTime / 1e3).toFixed(4)}` : ""
].filter(($) => $.length !== 0).join(" ");
return "{" + [c[w].text.slice(0, 1e3), j].filter(($) => $.length !== 0).join(" ") + "}";
}).join(`
`), p = `%c[${e.__state.sharedState.dbName}] ` + [
(l = t.current) != null && l.id ? `[tr_id=${(n = t.current) == null ? void 0 : n.id.substring(0, 6)}]` : "",
_,
(f == null ? void 0 : f.sendTime) !== void 0 ? `sendTime=${(f.sendTime / 1e3).toFixed(4)}` : "",
(f == null ? void 0 : f.receiveTime) !== void 0 ? `receiveTime=${(f.receiveTime / 1e3).toFixed(4)}` : "",
`totalTime=${((I - m) / 1e3).toFixed(4)}`
].filter((T) => T.length !== 0).join(" ");
console.log(
p,
`color: ${s.transactionLoggingState.id ? k[s.transactionLoggingState.i % k.length] : "white"}`
);
}
};
try {
const u = await o.execQueries(
p(e.map((d) => d.toSql())),
s
);
return { dbState: t, result: u, queries: e };
if (t.current && (i == null ? void 0 : i.current) && t.current.id === i.current.id) {
const _ = i.performance;
d.some((p) => p.performance.execTime !== void 0) && (_.execTime === void 0 && (_.execTime = 0), _.execTime += d.reduce(
(p, T) => {
var w;
return p + ((w = T.performance.execTime) != null ? w : 0);
},
0
)), d.some((p) => p.performance.freeTime !== void 0) && (_.freeTime === void 0 && (_.freeTime = 0), _.freeTime += d.reduce(
(p, T) => {
var w;
return p + ((w = T.performance.freeTime) != null ? w : 0);
},
0
)), d.some((p) => p.performance.prepareTime !== void 0) && (_.prepareTime === void 0 && (_.prepareTime = 0), _.prepareTime += d.reduce(
(p, T) => {
var w;
return p + ((w = T.performance.prepareTime) != null ? w : 0);
},
0
)), f.sendTime && (_.sendTime || (_.sendTime = 0), _.sendTime += f.sendTime), f.receiveTime && (_.receiveTime || (_.receiveTime = 0), _.receiveTime += f.receiveTime);
}
return { db: e, result: d, performance: f, queries: r };
} finally {
i && m(c, i);
o && b(a, o);
}
}, q = async (t, e) => {
const r = [
...t.localState.queriesMiddlewares,
$
}, V = async (e, r) => {
const t = [
...e.__state.localState.queriesMiddlewares,
M
].reverse();
let n = (a) => Promise.resolve(a);
for (const a of r) {
const c = n;
n = (o) => a({ ...o, next: c });
let i = (a) => Promise.resolve(a);
for (const a of t) {
const u = i;
i = (s) => a({ ...s, next: u });
}
return (await n({
dbState: t,
return await i({
db: e,
result: [],
queries: e.map((a) => a.toSql())
})).result;
}, D = async (t, e) => (await q(t, [e]))[0] || [], M = (t, e) => e({
...t,
localState: { ...t.localState, suppressLog: !0 }
}), O = (t) => ({ ...t, localState: { ...t.localState, suppressLog: !0 } }), g = async (t, e, r, n) => {
performance: {
sendTime: void 0,
receiveTime: void 0,
totalTime: 0
},
queries: r.map((a) => a.toSql())
});
}, L = (e, r, t) => {
if (e.__state.localState.suppressLog)
return;
const i = [
t.prepareTime === void 0 ? "" : `prepareTime=${(t.prepareTime / 1e3).toFixed(4)}`,
t.execTime === void 0 ? "" : `execTime=${(t.execTime / 1e3).toFixed(4)}`,
t.freeTime === void 0 ? "" : `freeTime=${(t.freeTime / 1e3).toFixed(4)}`,
t.sendTime === void 0 ? "" : `sendTime=${(t.sendTime / 1e3).toFixed(4)}`,
t.receiveTime === void 0 ? "" : `receiveTime=${(t.receiveTime / 1e3).toFixed(4)}`,
`totalTime=${(t.totalTime / 1e3).toFixed(4)}`
].filter((a) => a.length !== 0).join(" ");
console.log(
`%c[${e.__state.sharedState.dbName}][tr_id=${r.slice(
0,
6
)}] Transaction finished with ${i}`,
"color: #fff; background-color: #1da1f2; padding: 2px 4px; border-radius: 2px"
);
}, B = async (e, r, t, i) => {
const {
localState: { transactionsState: a },
sharedState: {
transactionsState: c,
eventsEmitter: o,
dbBackend: i
}
} = t;
if (a.current && c.current) {
if (a.current.id !== c.current.id)
sharedState: { transactionsState: u, eventsEmitter: s },
sharedState: o
} = e.__state;
if (a.current && (u == null ? void 0 : u.current)) {
if (a.current.id !== (u == null ? void 0 : u.current.id))
throw new Error(
"Internal error: local running transaction is not the same as shared state transaction"
);
return await r(t);
return await t(e);
}
E(t, () => "transaction");
const s = {
id: w()
q(e, () => "transaction");
const c = {
id: v(),
type: "async"
};
t = {
...t,
localState: {
...t.localState,
transactionsState: { current: s }
e = {
...e,
__state: {
...e.__state,
localState: {
...e.__state.localState,
transactionsState: { current: c }
}
}
};
const l = await f(t.sharedState.jobsState, {
const h = await y(e.__state.sharedState.jobsState, {
type: "runTransaction",
transaction: s,
label: n == null ? void 0 : n.label
}), u = {
log: {
suppress: Boolean(t.localState.suppressLog),
transactionId: s.id
transaction: c,
label: i == null ? void 0 : i.label
}), l = performance.now(), n = {
current: c,
performance: {
prepareTime: 0,
execTime: 0,
freeTime: 0,
sendTime: 0,
receiveTime: 0,
totalTime: 0
}
};
o.transactionsState = n;
try {
c.current = s, await o.emit("transactionWillStart", t, s), await i.execQueries(
p([S`BEGIN ${S.raw(e)} TRANSACTION;`]),
u
), await o.emit("transactionStarted", t, s);
await s.emit("transactionWillStart", e, c), await e.runQuery(
S`BEGIN ${S.raw(r.toUpperCase())} TRANSACTION;`
), await s.emit("transactionStarted", e, c);
try {
const d = await r(t);
return await o.emit("transactionWillCommit", t, s), await i.execQueries(p([S`COMMIT`]), u), await o.emit("transactionCommitted", t, s), d;
} catch (d) {
throw console.error("Rollback transaction", d), await o.emit("transactionWillRollback", t, s), await i.execQueries(p([S`ROLLBACK`]), u), await o.emit("transactionRollbacked", t, s), d;
const m = await t(e);
return await s.emit("transactionWillCommit", e, c), await e.runQuery(S`COMMIT`), await s.emit("transactionCommitted", e, c), m;
} catch (m) {
throw console.error("Rollback transaction", m), await s.emit("transactionWillRollback", e, c), await e.runQuery(S`ROLLBACK`), await s.emit("transactionRollbacked", e, c), m;
}
} finally {
m(t.sharedState.jobsState, l);
n.performance.totalTime = performance.now() - l, L(e, c.id, n.performance), b(e.__state.sharedState.jobsState, h);
}
}, k = (t, e, r) => g(t, "DEFERRED", e, r), Q = (t, e, r) => g(t, "IMMEDIATE", e, r), V = (t, e, r) => g(t, "EXCLUSIVE", e, r), B = (t, e, r) => k(t, e, r);
}, D = () => ({
__state: {
queries: []
},
addQuery(e) {
this.__state.queries.push(e);
}
}), J = async (e, r, t, i) => {
const {
localState: { transactionsState: a },
sharedState: { eventsEmitter: u },
sharedState: s
} = e.__state;
if (a.current)
throw new Error(
"You are running atomic transaction inside of a transaction. Consider moving atomic transaction call to runAfterTransaction callback."
);
const o = await (async () => {
if (Array.isArray(t))
return t;
{
const d = D();
return await t(d), d.__state.queries;
}
})(), c = {
id: v(),
type: "atomic"
}, h = await y(e.__state.sharedState.jobsState, {
type: "runAtomicTransaction",
transaction: c,
label: i == null ? void 0 : i.label
}), l = {
current: c,
performance: {
prepareTime: 0,
execTime: 0,
freeTime: 0,
sendTime: 0,
receiveTime: 0,
totalTime: 0
}
};
s.transactionsState = l, e = {
...e,
__state: {
...e.__state,
localState: {
...e.__state.localState,
transactionsState: { current: c }
}
}
};
const n = performance.now(), m = [
S`BEGIN ${S.raw(r.toUpperCase())} TRANSACTION`,
...o,
S`COMMIT`
];
try {
await u.emit("transactionWillStart", e, c), await e.runQueries(m), await u.emit("transactionCommitted", e, c);
} catch (d) {
throw console.error("Rollback transaction", d), await u.emit("transactionWillRollback", e, c), await e.runQuery(S`ROLLBACK`), await u.emit("transactionRollbacked", e, c), d;
} finally {
l.performance.totalTime = performance.now() - n, L(e, c.id, l.performance), b(e.__state.sharedState.jobsState, h);
}
}, z = async ({
dbName: e,
plugins: r,
queriesMiddlewares: t,
dbBackend: i
}) => {
const a = A(
"running",
{ label: "runningState" }
), u = (await i)({
dbName: e
}), s = A(
{
queue: [],
current: void 0
},
{ label: "jobsState" }
), o = {
__state: {
sharedState: {
clientId: v(),
dbBackend: u,
dbName: e,
runningState: a,
eventsEmitter: Q(),
jobsState: s,
transactionLoggingState: {
id: void 0,
i: 0
}
},
localState: {
queriesMiddlewares: t || [],
transactionsState: {}
}
},
runInTransaction(l, n) {
return B(this, (n == null ? void 0 : n.type) || "deferred", l, {
label: n == null ? void 0 : n.label
});
},
async runAtomicTransaction(l, n) {
return await J(
this,
(n == null ? void 0 : n.type) || "deferred",
l,
n
);
},
async runQueries(l) {
return (await V(this, l)).result.map(({ rows: m }) => m);
},
async runQuery(l) {
return (await this.runQueries([l]))[0];
},
runAfterTransactionCommitted(l) {
return x(this, (n, m, d) => {
n === "committed" && l(m, d);
});
},
runAfterTransactionRollbacked(l) {
x(o, (n, m, d) => {
n === "rollbacked" && l(m, d);
});
}
}, c = await y(o.__state.sharedState.jobsState, {
type: "initDb",
name: e
});
let h = o;
try {
const l = () => o.__state.sharedState.runningState.value;
if (l() !== "running" || (await u.initialize(), l() !== "running"))
return o;
for (const n of r || [])
h = n(h);
} finally {
b(s, c);
}
return await o.__state.sharedState.eventsEmitter.emit("initialized", o), h;
}, G = async (e) => {
e.__state.sharedState.runningState.value = "stopping", await F(e.__state.sharedState.jobsState), await e.__state.sharedState.dbBackend.stop(), e.__state.sharedState.runningState.value = "stopped", queueMicrotask(() => {
e.__state.sharedState.runningState.stop(), e.__state.sharedState.jobsState.stop();
});
}, K = (e, r) => r({
...e,
__state: {
...e.__state,
localState: {
...e.__state.localState,
suppressLog: !0
}
}
}), Y = (e) => ({
...e,
__state: {
...e.__state,
localState: { ...e.__state.localState, suppressLog: !0 }
}
});
export {
b as StoppedError,
h as TimeoutError,
R as initDbClient,
w as makeId,
v as reactiveVar,
A as runAfterTransactionCommitted,
L as runAfterTransactionRollbacked,
k as runInDeferredTransaction,
V as runInExclusiveTransaction,
Q as runInImmediateTransaction,
B as runInTransaction,
q as runQueries,
D as runQuery,
x as stopDb,
M as suppressLog,
O as withSuppressedLog
E as StoppedError,
g as TimeoutError,
z as initDbClient,
v as makeId,
A as reactiveVar,
G as stopDb,
K as suppressLog,
Y as withSuppressedLog
};
//# sourceMappingURL=index.es.js.map

@@ -1,2 +0,3 @@

(function(s,h){typeof exports=="object"&&typeof module<"u"?h(exports,require("@kikko-land/sql")):typeof define=="function"&&define.amd?define(["exports","@kikko-land/sql"],h):(s=typeof globalThis<"u"?globalThis:s||self,h(s.core={},s.sql))})(this,function(s,h){"use strict";const T=(t,e)=>{if(!t.localState.transactionsState)throw new Error("Not in transaction.");const n=[],r=a=>(u,c)=>{e(a,u,c);for(const i of n)i()};n.push(t.sharedState.eventsEmitter.on("transactionCommitted",r("committed"))),n.push(t.sharedState.eventsEmitter.on("transactionRollbacked",r("rollbacked")))},q=(t,e)=>{T(t,(n,r,a)=>{n==="committed"&&e(r,a)})},$=(t,e)=>{T(t,(n,r,a)=>{n==="rollbacked"&&e(r,a)})};function C(){const t={};return{async emit(e,...n){const r=t[e]||[];for(const a of r)await a(...n)},on(e,n){return(t[e]=t[e]||[]).push(n),()=>{const r=t[e]||[];t[e]=r.filter(a=>a!==n)}}}}class f extends Error{}class m extends Error{}const g=(t,e)=>({__state:{subscriptions:[],value:t,isStopped:!1,onStop:[]},get isStopped(){return this.__state.isStopped},set value(n){if(this.isStopped)throw new Error(`reactiveVar ${e} is stopped!`);this.__state.value=n;for(const r of this.__state.subscriptions)r(n)},get value(){if(this.isStopped)throw new Error(`reactiveVar ${e} is stopped!`);return this.__state.value},subscribe(n,r=!0){if(this.isStopped)throw new Error(`reactiveVar ${e} is stopped!`);return this.__state.subscriptions.push(n),r&&n(this.__state.value),()=>{this.__state.subscriptions=this.__state.subscriptions.filter(a=>a!==n)}},waitTill(n,r){if(this.isStopped)throw new Error(`reactiveVar ${e} is stopped!`);return new Promise((u,c)=>{var d;const i=[],o=()=>{for(const l of i)l()};if(i.push(((d=r==null?void 0:r.stopIf)==null?void 0:d.subscribe(l=>{!l||(o(),c(new m(`waitUntil for reactiveVar ${e} is stopped due to stop signal`)))},!0))||(()=>{})),i.push(this.subscribe(l=>{!n(l)||(o(),u())},!0)),(r==null?void 0:r.timeout)===void 0||(r==null?void 0:r.timeout)!=="infinite"){const l=setTimeout(()=>{o(),c(new f(`waitUntil for reactiveVar ${e} is timed out`))},(r==null?void 0:r.timeout)===void 0?5e3:r.timeout);i.push(()=>{clearTimeout(l)})}this.__state.onStop.push(()=>{o(),c(new m(`waitUntil for reactiveVar ${e} is stopped due to reactive var stop`))})})},stop(){if(this.isStopped)throw new Error(`reactiveVar ${e} is already stopped!`);this.__state.subscriptions=[];for(const n of this.__state.onStop)n();this.__state.isStopped=!0}}),E=(t,e)=>{const{sharedState:{runningState:n,dbName:r}}=t;if(n.value!=="running")throw new Error(`Failed to start ${e()}, db ${r} is stopping`)},w=t=>t.map(e=>e.preparedQuery);function p(){let t="";const e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",n=e.length;for(let r=0;r<32;r++)t+=e.charAt(Math.floor(Math.random()*n));return t}const I=t=>{const{current:e,queue:n}=t;return`current running job: ${JSON.stringify(e,null,2)}, queue: ${JSON.stringify(n,null,2)}`},b=async(t,e)=>{const n=p(),r={...e,id:n},{current:a,queue:u}=t.value;if(a||u.length>0){const c=t.waitTill(i=>{var o;return((o=i.current)==null?void 0:o.id)===n});t.value={queue:[...u,r],current:a};try{await c}catch(i){throw i instanceof f?new f(`Timeout error while job acquire: '${i.message}'. Is it a dead lock? ${I(t.value)}, jobToAcquire: ${JSON.stringify(r,null,2)}`):i}}else t.value={queue:[],current:r};return r},v=(t,e)=>{const{current:n,queue:r}=t.value;if((n==null?void 0:n.id)!==e.id)throw new Error(`Can't release job that is not currently running, ${I(t.value)}, toRelease: ${JSON.stringify(e,null,2)}`);t.value={queue:r.slice(1),current:r[0]}},A=async t=>{try{return t.waitTill(({queue:e,current:n})=>e.length===0&&n===void 0,{timeout:3e4})}catch(e){throw e instanceof f?new f(`Timeout error while awaiting all jobs done: '${e.message}'. Is it a dead lock?`):e}},L=async({dbName:t,plugins:e,queriesMiddlewares:n,dbBackend:r})=>{const a=g("running","runningState"),u=(await r)({dbName:t}),c=g({queue:[],current:void 0},"jobsState"),i={sharedState:{clientId:p(),dbBackend:u,dbName:t,runningState:a,eventsEmitter:C(),jobsState:c,transactionsState:{}},localState:{queriesMiddlewares:n||[],transactionsState:{}}},o=await b(i.sharedState.jobsState,{type:"initDb",name:t});let d=i;try{const l=()=>i.sharedState.runningState.value;if(l()!=="running"||(await u.initialize(),l()!=="running"))return i;for(const S of e||[])d=S(d)}finally{v(c,o)}return await i.sharedState.eventsEmitter.emit("initialized",i),d},D=async t=>{t.sharedState.runningState.value="stopping",await A(t.sharedState.jobsState),await t.sharedState.dbBackend.stop(),t.sharedState.runningState.value="stopped",queueMicrotask(()=>{t.sharedState.runningState.stop(),t.sharedState.jobsState.stop()})},R=async({dbState:t,queries:e})=>{var d;const{localState:{transactionsState:n,suppressLog:r},sharedState:{transactionsState:a,jobsState:u,dbBackend:c}}=t;if(n.current||E(t,()=>JSON.stringify(e)),n.current&&a.current&&n.current.id!==a.current.id)throw new Error("Internal error: local running transaction is not the same as shared state transaction");let i;n.current||(i=await b(u,{type:"runQueries",queries:e.map(l=>l.toSql())}));const o={log:{suppress:Boolean(r),transactionId:(d=n.current)==null?void 0:d.id}};try{const l=await c.execQueries(w(e.map(S=>S.toSql())),o);return{dbState:t,result:l,queries:e}}finally{i&&v(u,i)}},_=async(t,e)=>{const n=[...t.localState.queriesMiddlewares,R].reverse();let r=a=>Promise.resolve(a);for(const a of n){const u=r;r=c=>a({...c,next:u})}return(await r({dbState:t,result:[],queries:e.map(a=>a.toSql())})).result},M=async(t,e)=>(await _(t,[e]))[0]||[],Q=(t,e)=>e({...t,localState:{...t.localState,suppressLog:!0}}),O=t=>({...t,localState:{...t.localState,suppressLog:!0}}),y=async(t,e,n,r)=>{const{localState:{transactionsState:a},sharedState:{transactionsState:u,eventsEmitter:c,dbBackend:i}}=t;if(a.current&&u.current){if(a.current.id!==u.current.id)throw new Error("Internal error: local running transaction is not the same as shared state transaction");return await n(t)}E(t,()=>"transaction");const o={id:p()};t={...t,localState:{...t.localState,transactionsState:{current:o}}};const d=await b(t.sharedState.jobsState,{type:"runTransaction",transaction:o,label:r==null?void 0:r.label}),l={log:{suppress:Boolean(t.localState.suppressLog),transactionId:o.id}};try{u.current=o,await c.emit("transactionWillStart",t,o),await i.execQueries(w([h.sql`BEGIN ${h.sql.raw(e)} TRANSACTION;`]),l),await c.emit("transactionStarted",t,o);try{const S=await n(t);return await c.emit("transactionWillCommit",t,o),await i.execQueries(w([h.sql`COMMIT`]),l),await c.emit("transactionCommitted",t,o),S}catch(S){throw console.error("Rollback transaction",S),await c.emit("transactionWillRollback",t,o),await i.execQueries(w([h.sql`ROLLBACK`]),l),await c.emit("transactionRollbacked",t,o),S}}finally{v(t.sharedState.jobsState,d)}},k=(t,e,n)=>y(t,"DEFERRED",e,n),V=(t,e,n)=>y(t,"IMMEDIATE",e,n),j=(t,e,n)=>y(t,"EXCLUSIVE",e,n),B=(t,e,n)=>k(t,e,n);s.StoppedError=m,s.TimeoutError=f,s.initDbClient=L,s.makeId=p,s.reactiveVar=g,s.runAfterTransactionCommitted=q,s.runAfterTransactionRollbacked=$,s.runInDeferredTransaction=k,s.runInExclusiveTransaction=j,s.runInImmediateTransaction=V,s.runInTransaction=B,s.runQueries=_,s.runQuery=M,s.stopDb=D,s.suppressLog=Q,s.withSuppressedLog=O,Object.defineProperties(s,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
(function(_,y){typeof exports=="object"&&typeof module<"u"?y(exports,require("lodash.isequal"),require("@kikko-land/boono-sql")):typeof define=="function"&&define.amd?define(["exports","lodash.isequal","@kikko-land/boono-sql"],y):(_=typeof globalThis<"u"?globalThis:_||self,y(_.core={},_.isEqual,_.boonoSql))})(this,function(_,y,S){"use strict";const N=(e=>e&&typeof e=="object"&&"default"in e?e:{default:e})(y),A=(e,i)=>{if(!e.__state.localState.transactionsState.current)throw new Error("Not in transaction.");const t=e.__state.localState.transactionsState.current,r=[],a=u=>(s,o)=>{if(t.id===o.id){i(u,s,t);for(const c of r)c()}};r.push(e.__state.sharedState.eventsEmitter.on("transactionCommitted",a("committed"))),r.push(e.__state.sharedState.eventsEmitter.on("transactionRollbacked",a("rollbacked")))};function Q(){const e={};return{async emit(i,...t){const r=e[i]||[];for(const a of r)await a(...t)},on(i,t){return(e[i]=e[i]||[]).push(t),()=>{const r=e[i]||[];e[i]=r.filter(a=>a!==t)}}}}class v extends Error{}class k extends Error{}const x=(e,i)=>{const t=i.deduplicate===void 0?!0:i.deduplicate;return{__state:{subscriptions:[],value:e,isStopped:!1,onStop:[]},get isStopped(){return this.__state.isStopped},set value(r){if(this.isStopped)throw new Error(`reactiveVar ${i.label} is stopped!`);if(!(t&&N.default(this.__state.value,r))){this.__state.value=r;for(const a of this.__state.subscriptions)a(r)}},get value(){if(this.isStopped)throw new Error(`reactiveVar ${i.label} is stopped!`);return this.__state.value},subscribe(r,a=!0){if(this.isStopped)throw new Error(`reactiveVar ${i.label} is stopped!`);let u;const s=o=>{u&&u(),u=r(o)};return this.__state.subscriptions.push(s),a&&s(this.__state.value),()=>{this.__state.subscriptions=this.__state.subscriptions.filter(o=>o!==s)}},waitTill(r,a){const u=new k(`waitUntil for reactiveVar ${i.label} is stopped due to stop signal`),s=new v(`waitUntil for reactiveVar ${i.label} is timed out`),o=new k(`waitUntil for reactiveVar ${i.label} is stopped due to reactive var stop`);if(this.isStopped)throw new Error(`reactiveVar ${i.label} is stopped!`);return new Promise((w,l)=>{var m;const n=[],d=()=>{for(const f of n)f()};if(n.push(((m=a==null?void 0:a.stopIf)==null?void 0:m.subscribe(f=>{!f||(d(),l(u))},!0))||(()=>{})),n.push(this.subscribe(f=>{!r(f)||(d(),w())},!0)),(a==null?void 0:a.timeout)===void 0||typeof(a==null?void 0:a.timeout)=="number"){const f=setTimeout(()=>{d(),l(s)},(a==null?void 0:a.timeout)===void 0?6e4:a.timeout);n.push(()=>{clearTimeout(f)})}this.__state.onStop.push(()=>{d(),l(o)})})},stop(){if(this.isStopped)throw new Error(`reactiveVar ${i.label} is already stopped!`);this.__state.subscriptions=[];for(const r of this.__state.onStop)r();this.__state.isStopped=!0}}},L=(e,i)=>{const{__state:{sharedState:{runningState:t,dbName:r}}}=e;if(t.value!=="running")throw new Error(`Failed to start ${i()}, db ${r} is stopping`)},R=e=>e.map(i=>i.preparedQuery);function b(){let e="";const i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",t=i.length;for(let r=0;r<32;r++)e+=i.charAt(Math.floor(Math.random()*t));return e}const C=e=>{const{current:i,queue:t}=e;return`current running job: ${JSON.stringify(i,null,2)}, queue: ${JSON.stringify(t,null,2)}`},$=async(e,i)=>{const t=b(),r={...i,id:t},{current:a,queue:u}=e.value;if(a||u.length>0){const s=e.waitTill(o=>{var c;return((c=o.current)==null?void 0:c.id)===t});e.value={queue:[...u,r],current:a};try{await s}catch(o){throw o instanceof v?new v(`Timeout error while job acquire: '${o.message}'. Is it a dead lock? ${C(e.value)}, jobToAcquire: ${JSON.stringify(r,null,2)}`):o}}else e.value={queue:[],current:r};return r},E=(e,i)=>{const{current:t,queue:r}=e.value;if((t==null?void 0:t.id)!==i.id)throw new Error(`Can't release job that is not currently running, ${C(e.value)}, toRelease: ${JSON.stringify(i,null,2)}`);e.value={queue:r.slice(1),current:r[0]}},F=async e=>{try{return e.waitTill(({queue:i,current:t})=>i.length===0&&t===void 0,{timeout:3e4})}catch(i){throw i instanceof v?new v(`Timeout error while awaiting all jobs done: '${i.message}'. Is it a dead lock?`):i}},j=["yellow","cyan","magenta"],D=async({db:e,queries:i})=>{var w,l,n;const{localState:{transactionsState:t},sharedState:{transactionsState:r,jobsState:a,dbBackend:u},sharedState:s}=e.__state;if(t.current||L(e,()=>JSON.stringify(i)),t.current&&(r==null?void 0:r.current)&&t.current.id!==r.current.id)throw new Error("Internal error: local running transaction is not the same as shared state transaction");let o;const c=R(i.map(d=>d.toSql()));t.current||(o=await $(a,{type:"runQueries",queries:i.map(d=>d.toSql())}));try{const d=performance.now(),{result:m,performance:f}=await u.execQueries(c),G=performance.now();if(!e.__state.localState.suppressLog){t.current&&t.current.id!==s.transactionLoggingState.id&&(s.transactionLoggingState.id=t.current.id,s.transactionLoggingState.i++),(w=t==null?void 0:t.current)!=null&&w.id||(s.transactionLoggingState.id=void 0);const T=m.map(({performance:p},g)=>{const K=[p.prepareTime!==void 0?`prepareTime=${(p.prepareTime/1e3).toFixed(4)}`:"",p.execTime!==void 0?`execTime=${(p.execTime/1e3).toFixed(4)}`:"",p.freeTime!==void 0?`freeTime=${(p.freeTime/1e3).toFixed(4)}`:""].filter(q=>q.length!==0).join(" ");return"{"+[c[g].text.slice(0,1e3),K].filter(q=>q.length!==0).join(" ")+"}"}).join(`
`),h=`%c[${e.__state.sharedState.dbName}] `+[(l=t.current)!=null&&l.id?`[tr_id=${(n=t.current)==null?void 0:n.id.substring(0,6)}]`:"",T,(f==null?void 0:f.sendTime)!==void 0?`sendTime=${(f.sendTime/1e3).toFixed(4)}`:"",(f==null?void 0:f.receiveTime)!==void 0?`receiveTime=${(f.receiveTime/1e3).toFixed(4)}`:"",`totalTime=${((G-d)/1e3).toFixed(4)}`].filter(p=>p.length!==0).join(" ");console.log(h,`color: ${s.transactionLoggingState.id?j[s.transactionLoggingState.i%j.length]:"white"}`)}if(t.current&&(r==null?void 0:r.current)&&t.current.id===r.current.id){const T=r.performance;m.some(h=>h.performance.execTime!==void 0)&&(T.execTime===void 0&&(T.execTime=0),T.execTime+=m.reduce((h,p)=>{var g;return h+((g=p.performance.execTime)!=null?g:0)},0)),m.some(h=>h.performance.freeTime!==void 0)&&(T.freeTime===void 0&&(T.freeTime=0),T.freeTime+=m.reduce((h,p)=>{var g;return h+((g=p.performance.freeTime)!=null?g:0)},0)),m.some(h=>h.performance.prepareTime!==void 0)&&(T.prepareTime===void 0&&(T.prepareTime=0),T.prepareTime+=m.reduce((h,p)=>{var g;return h+((g=p.performance.prepareTime)!=null?g:0)},0)),f.sendTime&&(T.sendTime||(T.sendTime=0),T.sendTime+=f.sendTime),f.receiveTime&&(T.receiveTime||(T.receiveTime=0),T.receiveTime+=f.receiveTime)}return{db:e,result:m,performance:f,queries:i}}finally{o&&E(a,o)}},M=async(e,i)=>{const t=[...e.__state.localState.queriesMiddlewares,D].reverse();let r=a=>Promise.resolve(a);for(const a of t){const u=r;r=s=>a({...s,next:u})}return await r({db:e,result:[],performance:{sendTime:void 0,receiveTime:void 0,totalTime:0},queries:i.map(a=>a.toSql())})},I=(e,i,t)=>{if(e.__state.localState.suppressLog)return;const r=[t.prepareTime===void 0?"":`prepareTime=${(t.prepareTime/1e3).toFixed(4)}`,t.execTime===void 0?"":`execTime=${(t.execTime/1e3).toFixed(4)}`,t.freeTime===void 0?"":`freeTime=${(t.freeTime/1e3).toFixed(4)}`,t.sendTime===void 0?"":`sendTime=${(t.sendTime/1e3).toFixed(4)}`,t.receiveTime===void 0?"":`receiveTime=${(t.receiveTime/1e3).toFixed(4)}`,`totalTime=${(t.totalTime/1e3).toFixed(4)}`].filter(a=>a.length!==0).join(" ");console.log(`%c[${e.__state.sharedState.dbName}][tr_id=${i.slice(0,6)}] Transaction finished with ${r}`,"color: #fff; background-color: #1da1f2; padding: 2px 4px; border-radius: 2px")},V=async(e,i,t,r)=>{const{localState:{transactionsState:a},sharedState:{transactionsState:u,eventsEmitter:s},sharedState:o}=e.__state;if(a.current&&(u==null?void 0:u.current)){if(a.current.id!==(u==null?void 0:u.current.id))throw new Error("Internal error: local running transaction is not the same as shared state transaction");return await t(e)}L(e,()=>"transaction");const c={id:b(),type:"async"};e={...e,__state:{...e.__state,localState:{...e.__state.localState,transactionsState:{current:c}}}};const w=await $(e.__state.sharedState.jobsState,{type:"runTransaction",transaction:c,label:r==null?void 0:r.label}),l=performance.now(),n={current:c,performance:{prepareTime:0,execTime:0,freeTime:0,sendTime:0,receiveTime:0,totalTime:0}};o.transactionsState=n;try{await s.emit("transactionWillStart",e,c),await e.runQuery(S.sql`BEGIN ${S.sql.raw(i.toUpperCase())} TRANSACTION;`),await s.emit("transactionStarted",e,c);try{const d=await t(e);return await s.emit("transactionWillCommit",e,c),await e.runQuery(S.sql`COMMIT`),await s.emit("transactionCommitted",e,c),d}catch(d){throw console.error("Rollback transaction",d),await s.emit("transactionWillRollback",e,c),await e.runQuery(S.sql`ROLLBACK`),await s.emit("transactionRollbacked",e,c),d}}finally{n.performance.totalTime=performance.now()-l,I(e,c.id,n.performance),E(e.__state.sharedState.jobsState,w)}},B=()=>({__state:{queries:[]},addQuery(e){this.__state.queries.push(e)}}),J=async(e,i,t,r)=>{const{localState:{transactionsState:a},sharedState:{eventsEmitter:u},sharedState:s}=e.__state;if(a.current)throw new Error("You are running atomic transaction inside of a transaction. Consider moving atomic transaction call to runAfterTransaction callback.");const o=await(async()=>{if(Array.isArray(t))return t;{const m=B();return await t(m),m.__state.queries}})(),c={id:b(),type:"atomic"},w=await $(e.__state.sharedState.jobsState,{type:"runAtomicTransaction",transaction:c,label:r==null?void 0:r.label}),l={current:c,performance:{prepareTime:0,execTime:0,freeTime:0,sendTime:0,receiveTime:0,totalTime:0}};s.transactionsState=l,e={...e,__state:{...e.__state,localState:{...e.__state.localState,transactionsState:{current:c}}}};const n=performance.now(),d=[S.sql`BEGIN ${S.sql.raw(i.toUpperCase())} TRANSACTION`,...o,S.sql`COMMIT`];try{await u.emit("transactionWillStart",e,c),await e.runQueries(d),await u.emit("transactionCommitted",e,c)}catch(m){throw console.error("Rollback transaction",m),await u.emit("transactionWillRollback",e,c),await e.runQuery(S.sql`ROLLBACK`),await u.emit("transactionRollbacked",e,c),m}finally{l.performance.totalTime=performance.now()-n,I(e,c.id,l.performance),E(e.__state.sharedState.jobsState,w)}},W=async({dbName:e,plugins:i,queriesMiddlewares:t,dbBackend:r})=>{const a=x("running",{label:"runningState"}),u=(await r)({dbName:e}),s=x({queue:[],current:void 0},{label:"jobsState"}),o={__state:{sharedState:{clientId:b(),dbBackend:u,dbName:e,runningState:a,eventsEmitter:Q(),jobsState:s,transactionLoggingState:{id:void 0,i:0}},localState:{queriesMiddlewares:t||[],transactionsState:{}}},runInTransaction(l,n){return V(this,(n==null?void 0:n.type)||"deferred",l,{label:n==null?void 0:n.label})},async runAtomicTransaction(l,n){return await J(this,(n==null?void 0:n.type)||"deferred",l,n)},async runQueries(l){return(await M(this,l)).result.map(({rows:d})=>d)},async runQuery(l){return(await this.runQueries([l]))[0]},runAfterTransactionCommitted(l){return A(this,(n,d,m)=>{n==="committed"&&l(d,m)})},runAfterTransactionRollbacked(l){A(o,(n,d,m)=>{n==="rollbacked"&&l(d,m)})}},c=await $(o.__state.sharedState.jobsState,{type:"initDb",name:e});let w=o;try{const l=()=>o.__state.sharedState.runningState.value;if(l()!=="running"||(await u.initialize(),l()!=="running"))return o;for(const n of i||[])w=n(w)}finally{E(s,c)}return await o.__state.sharedState.eventsEmitter.emit("initialized",o),w},U=async e=>{e.__state.sharedState.runningState.value="stopping",await F(e.__state.sharedState.jobsState),await e.__state.sharedState.dbBackend.stop(),e.__state.sharedState.runningState.value="stopped",queueMicrotask(()=>{e.__state.sharedState.runningState.stop(),e.__state.sharedState.jobsState.stop()})},O=(e,i)=>i({...e,__state:{...e.__state,localState:{...e.__state.localState,suppressLog:!0}}}),z=e=>({...e,__state:{...e.__state,localState:{...e.__state.localState,suppressLog:!0}}});_.StoppedError=k,_.TimeoutError=v,_.initDbClient=W,_.makeId=b,_.reactiveVar=x,_.stopDb=U,_.suppressLog=O,_.withSuppressedLog=z;for(const e in S)e!=="default"&&!_.hasOwnProperty(e)&&Object.defineProperty(_,e,{enumerable:!0,get:()=>S[e]});Object.defineProperties(_,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
//# sourceMappingURL=index.umd.js.map
{
"name": "@kikko-land/kikko",
"version": "0.4.0",
"version": "0.5.0",
"author": "Sergey Popov",

@@ -38,10 +38,11 @@ "license": "MIT",

"dependencies": {
"@kikko-land/query-builder": "^0.2.0",
"@kikko-land/sql": "^0.2.0",
"@kikko-land/boono-sql": "^0.3.0",
"lodash.isequal": "^4.5.0",
"ts-essentials": "^9.3.0"
},
"devDependencies": {
"@kikko-land/common-scripts": "^0.3.0",
"@types/emscripten": "^1.39.6"
"@kikko-land/common-scripts": "^0.4.0",
"@types/emscripten": "^1.39.6",
"@types/lodash.isequal": "^4.5.6"
}
}

@@ -1,14 +0,15 @@

import { IDbState, ITransaction } from "./types";
import { IDb, ITransaction } from "./types";
const runAfterTransaction = (
db: IDbState,
export const runAfterTransaction = (
db: IDb,
func: (
event: "committed" | "rollbacked",
db: IDbState,
db: IDb,
transaction: ITransaction
) => void
) => {
if (!db.localState.transactionsState) {
if (!db.__state.localState.transactionsState.current) {
throw new Error("Not in transaction.");
}
const transaction = db.__state.localState.transactionsState.current;

@@ -19,3 +20,5 @@ const unsubscribes: (() => void)[] = [];

(event: "committed" | "rollbacked") =>
(db: IDbState, transaction: ITransaction) => {
(db: IDb, evTransaction: ITransaction) => {
if (transaction.id !== evTransaction.id) return;
func(event, db, transaction);

@@ -29,3 +32,3 @@

unsubscribes.push(
db.sharedState.eventsEmitter.on(
db.__state.sharedState.eventsEmitter.on(
"transactionCommitted",

@@ -37,3 +40,3 @@ listener("committed")

unsubscribes.push(
db.sharedState.eventsEmitter.on(
db.__state.sharedState.eventsEmitter.on(
"transactionRollbacked",

@@ -44,23 +47,1 @@ listener("rollbacked")

};
export const runAfterTransactionCommitted = (
db: IDbState,
func: (db: IDbState, transaction: ITransaction) => void
) => {
runAfterTransaction(db, (ev, db, transaction) => {
if (ev === "committed") {
func(db, transaction);
}
});
};
export const runAfterTransactionRollbacked = (
db: IDbState,
func: (db: IDbState, transaction: ITransaction) => void
) => {
runAfterTransaction(db, (ev, db, transaction) => {
if (ev === "rollbacked") {
func(db, transaction);
}
});
};

@@ -1,4 +0,4 @@

import { IPrimitiveValue, ISql } from "@kikko-land/sql";
import { IPrimitiveValue, ISql } from "@kikko-land/boono-sql";
import { IDbState } from "./types";
import { IDb } from "./types";
import { makeId } from "./utils";

@@ -42,3 +42,3 @@

export const buildRunQueriesCommand = (
state: IDbState,
state: IDb,
queries: ISql[]

@@ -54,4 +54,3 @@ ): IExecQueriesCommand => {

commandId: makeId(),
suppressLog: state.localState.suppressLog,
};
};

@@ -19,5 +19,5 @@ // Adopted from https://github.com/ai/nanoevents/blob/main/index.js

export function createNanoEvents<Events extends EventsMap>(): INanoEmitter<
Events
> {
export function createNanoEvents<
Events extends EventsMap
>(): INanoEmitter<Events> {
const events: Partial<{ [E in keyof Events]: Events[E][] }> = {};

@@ -24,0 +24,0 @@

@@ -1,8 +0,6 @@

export * from "./afterTransaction";
export * from "./initDb";
export * from "./reactiveVar";
export * from "./runQueries";
export * from "./suppressLog";
export * from "./transaction";
export * from "./types";
export { makeId } from "./utils";
export * from "@kikko-land/boono-sql";

@@ -0,13 +1,20 @@

import { ISqlAdapter } from "@kikko-land/boono-sql";
import { runAfterTransaction } from "./afterTransaction";
import { createNanoEvents } from "./createNanoEvents";
import { acquireJob, IJobsState, releaseJob, whenAllJobsDone } from "./job";
import { reactiveVar } from "./reactiveVar";
import { runQueries } from "./runQueries";
import { execAtomicTransaction, runInTransactionFunc } from "./transaction";
import {
IAtomicTransactionScope,
IDb,
IDbBackend,
IDbState,
IKikkoEvents,
IQueriesMiddleware,
ITransaction,
} from "./types";
import { makeId } from "./utils";
export type IDbClientPlugin = (state: IDbState) => IDbState;
export type IDbClientPlugin = (state: IDb) => IDb;

@@ -26,6 +33,6 @@ export type IInitDbClientConfig = {

dbBackend,
}: IInitDbClientConfig): Promise<IDbState> => {
}: IInitDbClientConfig): Promise<IDb> => {
const runningState = reactiveVar<"running" | "stopping" | "stopped">(
"running",
"runningState"
{ label: "runningState" }
);

@@ -41,25 +48,81 @@ const dbBackendCalled = (await dbBackend)({

} as IJobsState,
"jobsState"
{ label: "jobsState" }
);
const state: IDbState = {
sharedState: {
clientId: makeId(),
dbBackend: dbBackendCalled,
dbName,
const db: IDb = {
__state: {
sharedState: {
clientId: makeId(),
dbBackend: dbBackendCalled,
dbName,
runningState: runningState,
runningState: runningState,
eventsEmitter: createNanoEvents<IKikkoEvents>(),
eventsEmitter: createNanoEvents<IKikkoEvents>(),
jobsState: jobsState,
transactionsState: {},
jobsState: jobsState,
transactionLoggingState: {
id: undefined,
i: 0,
},
},
localState: {
queriesMiddlewares: queriesMiddlewares || [],
transactionsState: {},
},
},
localState: {
queriesMiddlewares: queriesMiddlewares || [],
transactionsState: {},
runInTransaction<T>(
func: (state: IDb) => Promise<T>,
opts?: { label?: string; type?: "deferred" | "immediate" | "exclusive" }
): Promise<T> {
return runInTransactionFunc<T>(this, opts?.type || "deferred", func, {
label: opts?.label,
});
},
async runAtomicTransaction(
func:
| ((scope: IAtomicTransactionScope) => Promise<void> | void)
| ISqlAdapter[],
opts?: { label?: string; type?: "deferred" | "immediate" | "exclusive" }
): Promise<void> {
return await execAtomicTransaction(
this,
opts?.type || "deferred",
func,
opts
);
},
async runQueries<D extends Record<string, unknown>>(
queries: ISqlAdapter[]
): Promise<D[][]> {
const res = await runQueries(this, queries);
return res.result.map(({ rows }) => rows) as D[][];
},
async runQuery<D extends Record<string, unknown>>(
query: ISqlAdapter
): Promise<D[]> {
return (await this.runQueries<D>([query]))[0];
},
runAfterTransactionCommitted(
func: (db: IDb, transaction: ITransaction) => void
) {
return runAfterTransaction(this, (ev, db, transaction) => {
if (ev === "committed") {
func(db, transaction);
}
});
},
runAfterTransactionRollbacked(
func: (db: IDb, transaction: ITransaction) => void
) {
runAfterTransaction(db, (ev, db, transaction) => {
if (ev === "rollbacked") {
func(db, transaction);
}
});
},
};
const job = await acquireJob(state.sharedState.jobsState, {
const job = await acquireJob(db.__state.sharedState.jobsState, {
type: "initDb",

@@ -69,12 +132,12 @@ name: dbName,

let currentState = state;
let currentState = db;
try {
const getRunningState = () => state.sharedState.runningState.value;
const getRunningState = () => db.__state.sharedState.runningState.value;
if (getRunningState() !== "running") return state;
if (getRunningState() !== "running") return db;
await dbBackendCalled.initialize();
if (getRunningState() !== "running") return state;
if (getRunningState() !== "running") return db;

@@ -88,3 +151,3 @@ for (const plugin of plugins || []) {

await state.sharedState.eventsEmitter.emit("initialized", state);
await db.__state.sharedState.eventsEmitter.emit("initialized", db);

@@ -94,14 +157,14 @@ return currentState;

export const stopDb = async (state: IDbState) => {
state.sharedState.runningState.value = "stopping";
export const stopDb = async (state: IDb) => {
state.__state.sharedState.runningState.value = "stopping";
await whenAllJobsDone(state.sharedState.jobsState);
await state.sharedState.dbBackend.stop();
await whenAllJobsDone(state.__state.sharedState.jobsState);
await state.__state.sharedState.dbBackend.stop();
state.sharedState.runningState.value = "stopped";
state.__state.sharedState.runningState.value = "stopped";
queueMicrotask(() => {
state.sharedState.runningState.stop();
state.sharedState.jobsState.stop();
state.__state.sharedState.runningState.stop();
state.__state.sharedState.jobsState.stop();
});
};

@@ -1,2 +0,2 @@

import { ISql } from "@kikko-land/sql";
import { ISql } from "@kikko-land/boono-sql";
import { DeepReadonly } from "ts-essentials";

@@ -15,3 +15,3 @@

| {
type: "runTransaction";
type: "runTransaction" | "runAtomicTransaction";
id: string;

@@ -18,0 +18,0 @@ transaction: ITransaction;

@@ -0,1 +1,3 @@

import isEqual from "lodash.isequal";
export interface ReactiveVar<T> {

@@ -9,6 +11,3 @@ __state: {

value: T;
subscribe(
sub: (val: T) => void | (() => void),
emitValueOnSubscribe?: boolean
): () => void;
subscribe(sub: (val: T) => void, emitValueOnSubscribe?: boolean): () => void;
waitTill(

@@ -29,3 +28,9 @@ filter: (val: T) => boolean,

export const reactiveVar = <T>(val: T, label: string): ReactiveVar<T> => {
export const reactiveVar = <T>(
val: T,
rOpts: { label: string; deduplicate?: boolean }
): ReactiveVar<T> => {
const shouldDeduplicate =
rOpts.deduplicate === undefined ? true : rOpts.deduplicate;
return {

@@ -42,4 +47,9 @@ __state: {

set value(val: T) {
if (this.isStopped) throw new Error(`reactiveVar ${label} is stopped!`);
if (this.isStopped)
throw new Error(`reactiveVar ${rOpts.label} is stopped!`);
if (shouldDeduplicate && isEqual(this.__state.value, val)) {
return;
}
this.__state.value = val;

@@ -52,3 +62,4 @@

get value() {
if (this.isStopped) throw new Error(`reactiveVar ${label} is stopped!`);
if (this.isStopped)
throw new Error(`reactiveVar ${rOpts.label} is stopped!`);

@@ -58,11 +69,21 @@ return this.__state.value;

subscribe(
sub: (val: T) => void | (() => void),
emitValueOnSubscribe: boolean = true
func: (val: T) => void | (() => void),
emitValueOnSubscribe = true
) {
if (this.isStopped) throw new Error(`reactiveVar ${label} is stopped!`);
if (this.isStopped)
throw new Error(`reactiveVar ${rOpts.label} is stopped!`);
this.__state.subscriptions.push(sub);
let currentUnsubscribe: undefined | void | (() => void);
const subscriber = (val: T) => {
if (currentUnsubscribe) {
currentUnsubscribe();
}
currentUnsubscribe = func(val);
};
this.__state.subscriptions.push(subscriber);
if (emitValueOnSubscribe) {
sub(this.__state.value);
subscriber(this.__state.value);
}

@@ -72,3 +93,3 @@

this.__state.subscriptions = this.__state.subscriptions.filter((s) => {
return s !== sub;
return s !== subscriber;
});

@@ -84,4 +105,15 @@ };

) {
if (this.isStopped) throw new Error(`reactiveVar ${label} is stopped!`);
const stopError = new StoppedError(
`waitUntil for reactiveVar ${rOpts.label} is stopped due to stop signal`
);
const timeoutError = new TimeoutError(
`waitUntil for reactiveVar ${rOpts.label} is timed out`
);
const stoppedError = new StoppedError(
`waitUntil for reactiveVar ${rOpts.label} is stopped due to reactive var stop`
);
if (this.isStopped)
throw new Error(`reactiveVar ${rOpts.label} is stopped!`);
const toWait = new Promise<void>((resolve, reject) => {

@@ -102,8 +134,7 @@ const unsubscriptions: (() => void)[] = [];

reject(
new StoppedError(
`waitUntil for reactiveVar ${label} is stopped due to stop signal`
)
);
}, true) || (() => {})
reject(stopError);
}, true) ||
(() => {
return undefined;
})
);

@@ -121,3 +152,3 @@

if (opts?.timeout === undefined || opts?.timeout !== "infinite") {
if (opts?.timeout === undefined || typeof opts?.timeout === "number") {
const id = setTimeout(

@@ -127,9 +158,5 @@ () => {

reject(
new TimeoutError(
`waitUntil for reactiveVar ${label} is timed out`
)
);
reject(timeoutError);
},
opts?.timeout === undefined ? 5000 : opts.timeout
opts?.timeout === undefined ? 60_000 : opts.timeout
);

@@ -145,7 +172,3 @@

reject(
new StoppedError(
`waitUntil for reactiveVar ${label} is stopped due to reactive var stop`
)
);
reject(stoppedError);
});

@@ -158,3 +181,3 @@ });

if (this.isStopped)
throw new Error(`reactiveVar ${label} is already stopped!`);
throw new Error(`reactiveVar ${rOpts.label} is already stopped!`);

@@ -161,0 +184,0 @@ this.__state.subscriptions = [];

@@ -1,6 +0,6 @@

import { ISqlAdapter } from "@kikko-land/sql";
import { ISqlAdapter } from "@kikko-land/boono-sql";
import { acquireJob, IJob, releaseJob } from "./job";
import {
IDbState,
IDb,
INextQueriesMiddleware,

@@ -12,8 +12,7 @@ IQueriesMiddleware,

const runQueriesMiddleware: IQueriesMiddleware = async ({
dbState,
queries,
}) => {
const colors = ["yellow", "cyan", "magenta"];
const runQueriesMiddleware: IQueriesMiddleware = async ({ db, queries }) => {
const {
localState: { transactionsState: transactionsLocalState, suppressLog },
localState: { transactionsState: transactionsLocalState },
sharedState: {

@@ -24,9 +23,10 @@ transactionsState: transactionsSharedState,

},
} = dbState;
sharedState,
} = db.__state;
if (!transactionsLocalState.current) {
assureDbIsRunning(dbState, () => JSON.stringify(queries));
assureDbIsRunning(db, () => JSON.stringify(queries));
}
if (transactionsLocalState.current && transactionsSharedState.current) {
if (transactionsLocalState.current && transactionsSharedState?.current) {
if (

@@ -44,2 +44,4 @@ transactionsLocalState.current.id !== transactionsSharedState.current.id

const unwrappedQueries = unwrapQueries(queries.map((q) => q.toSql()));
if (!transactionsLocalState.current) {

@@ -52,16 +54,136 @@ job = await acquireJob(jobsState, {

const execOpts = {
log: {
suppress: Boolean(suppressLog),
transactionId: transactionsLocalState.current?.id,
},
};
try {
const result = await dbBackend.execQueries(
unwrapQueries(queries.map((q) => q.toSql())),
execOpts
const startedAt = performance.now();
const { result, performance: qPerformance } = await dbBackend.execQueries(
unwrappedQueries
);
const endedAt = performance.now();
return { dbState, result, queries };
if (!db.__state.localState.suppressLog) {
if (
transactionsLocalState.current &&
transactionsLocalState.current.id !==
sharedState.transactionLoggingState.id
) {
sharedState.transactionLoggingState.id =
transactionsLocalState.current.id;
sharedState.transactionLoggingState.i++;
}
if (!transactionsLocalState?.current?.id) {
sharedState.transactionLoggingState.id = undefined;
}
const queriesTimings = result
.map(({ performance }, i) => {
const times = [
performance.prepareTime !== undefined
? `prepareTime=${(performance.prepareTime / 1000).toFixed(4)}`
: "",
performance.execTime !== undefined
? `execTime=${(performance.execTime / 1000).toFixed(4)}`
: "",
performance.freeTime !== undefined
? `freeTime=${(performance.freeTime / 1000).toFixed(4)}`
: "",
]
.filter((t) => t.length !== 0)
.join(" ");
return (
"{" +
[unwrappedQueries[i].text.slice(0, 1000), times]
.filter((v) => v.length !== 0)
.join(" ") +
"}"
);
})
.join("\n");
const totalTiming =
`%c[${db.__state.sharedState.dbName}] ` +
[
transactionsLocalState.current?.id
? `[tr_id=${transactionsLocalState.current?.id.substring(0, 6)}]`
: "",
queriesTimings,
qPerformance?.sendTime !== undefined
? `sendTime=${(qPerformance.sendTime / 1000).toFixed(4)}`
: "",
qPerformance?.receiveTime !== undefined
? `receiveTime=${(qPerformance.receiveTime / 1000).toFixed(4)}`
: "",
`totalTime=${((endedAt - startedAt) / 1000).toFixed(4)}`,
]
.filter((t) => t.length !== 0)
.join(" ");
console.log(
totalTiming,
`color: ${
sharedState.transactionLoggingState.id
? colors[sharedState.transactionLoggingState.i % colors.length]
: "white"
}`
);
}
if (transactionsLocalState.current && transactionsSharedState?.current) {
if (
transactionsLocalState.current.id === transactionsSharedState.current.id
) {
const perfData = transactionsSharedState.performance;
if (result.some((d) => d.performance.execTime !== undefined)) {
if (perfData.execTime === undefined) {
perfData.execTime = 0;
}
perfData.execTime += result.reduce(
(partialSum, a) => partialSum + (a.performance.execTime ?? 0),
0
);
}
if (result.some((d) => d.performance.freeTime !== undefined)) {
if (perfData.freeTime === undefined) {
perfData.freeTime = 0;
}
perfData.freeTime += result.reduce(
(partialSum, a) => partialSum + (a.performance.freeTime ?? 0),
0
);
}
if (result.some((d) => d.performance.prepareTime !== undefined)) {
if (perfData.prepareTime === undefined) {
perfData.prepareTime = 0;
}
perfData.prepareTime += result.reduce(
(partialSum, a) => partialSum + (a.performance.prepareTime ?? 0),
0
);
}
if (qPerformance.sendTime) {
if (!perfData.sendTime) {
perfData.sendTime = 0;
}
perfData.sendTime += qPerformance.sendTime;
}
if (qPerformance.receiveTime) {
if (!perfData.receiveTime) {
perfData.receiveTime = 0;
}
perfData.receiveTime += qPerformance.receiveTime;
}
}
}
return { db: db, result, performance: qPerformance, queries };
} finally {

@@ -74,8 +196,5 @@ if (job) {

export const runQueries = async <D extends Record<string, unknown>>(
state: IDbState,
queries: ISqlAdapter[]
): Promise<D[][]> => {
export const runQueries = async (db: IDb, queries: ISqlAdapter[]) => {
const middlewares: IQueriesMiddleware[] = [
...state.localState.queriesMiddlewares,
...db.__state.localState.queriesMiddlewares,
runQueriesMiddleware,

@@ -93,16 +212,12 @@ ].reverse();

return (
await toCall({
dbState: state,
result: [],
queries: queries.map((q) => q.toSql()),
})
).result as D[][];
return await toCall({
db: db,
result: [],
performance: {
sendTime: undefined,
receiveTime: undefined,
totalTime: 0,
},
queries: queries.map((q) => q.toSql()),
});
};
export const runQuery = async <D extends Record<string, unknown>>(
state: IDbState,
query: ISqlAdapter
) => {
return (await runQueries<D>(state, [query]))[0] || [];
};

@@ -1,15 +0,24 @@

import { IDbState } from "./types";
import { IDb } from "./types";
export const suppressLog = <T>(
state: IDbState,
func: (state: IDbState) => T
): T => {
export const suppressLog = <T>(db: IDb, func: (state: IDb) => T): T => {
return func({
...state,
localState: { ...state.localState, suppressLog: true },
...db,
__state: {
...db.__state,
localState: {
...db.__state.localState,
suppressLog: true,
},
},
});
};
export const withSuppressedLog = (state: IDbState): IDbState => {
return { ...state, localState: { ...state.localState, suppressLog: true } };
export const withSuppressedLog = (db: IDb): IDb => {
return {
...db,
__state: {
...db.__state,
localState: { ...db.__state.localState, suppressLog: true },
},
};
};

@@ -1,11 +0,53 @@

import { sql } from "@kikko-land/sql";
import { ISqlAdapter, sql } from "@kikko-land/boono-sql";
import { acquireJob, releaseJob } from "./job";
import { IDbState, ITransaction } from "./types";
import { assureDbIsRunning, makeId, unwrapQueries } from "./utils";
import {
IAtomicTransactionScope,
IDb,
ITransaction,
ITransactionPerformance,
} from "./types";
import { assureDbIsRunning, makeId } from "./utils";
const runInTransactionFunc = async <T>(
state: IDbState,
transactionType: "DEFERRED" | "IMMEDIATE" | "EXCLUSIVE",
func: (state: IDbState) => Promise<T>,
const logTimeIfNeeded = (
db: IDb,
transactionId: string,
performance: ITransactionPerformance
) => {
if (db.__state.localState.suppressLog) return;
const data = [
performance.prepareTime === undefined
? ""
: `prepareTime=${(performance.prepareTime / 1000).toFixed(4)}`,
performance.execTime === undefined
? ""
: `execTime=${(performance.execTime / 1000).toFixed(4)}`,
performance.freeTime === undefined
? ""
: `freeTime=${(performance.freeTime / 1000).toFixed(4)}`,
performance.sendTime === undefined
? ""
: `sendTime=${(performance.sendTime / 1000).toFixed(4)}`,
performance.receiveTime === undefined
? ""
: `receiveTime=${(performance.receiveTime / 1000).toFixed(4)}`,
`totalTime=${(performance.totalTime / 1000).toFixed(4)}`,
]
.filter((v) => v.length !== 0)
.join(" ");
console.log(
`%c[${db.__state.sharedState.dbName}][tr_id=${transactionId.slice(
0,
6
)}] Transaction finished with ${data}`,
`color: #fff; background-color: #1da1f2; padding: 2px 4px; border-radius: 2px`
);
};
export const runInTransactionFunc = async <T>(
db: IDb,
transactionType: "deferred" | "immediate" | "exclusive",
func: (state: IDb) => Promise<T>,
opts?: { label?: string }

@@ -15,14 +57,11 @@ ) => {

localState: { transactionsState: transactionsLocalState },
sharedState: {
transactionsState: transactionsSharedState,
eventsEmitter,
dbBackend,
},
} = state;
sharedState: { transactionsState: transactionsSharedState, eventsEmitter },
sharedState,
} = db.__state;
// It's indeed that function in same transaction don't need to check db is running
// Cause all transaction will await to execute on DB before stop
if (transactionsLocalState.current && transactionsSharedState.current) {
if (transactionsLocalState.current && transactionsSharedState?.current) {
if (
transactionsLocalState.current.id !== transactionsSharedState.current.id
transactionsLocalState.current.id !== transactionsSharedState?.current.id
) {

@@ -36,20 +75,24 @@ // Is it possible?

// we already in same transaction
return await func(state);
return await func(db);
}
assureDbIsRunning(state, () => "transaction");
assureDbIsRunning(db, () => "transaction");
const transaction: ITransaction = {
id: makeId(),
type: "async",
};
state = {
...state,
localState: {
...state.localState,
transactionsState: { current: transaction },
db = {
...db,
__state: {
...db.__state,
localState: {
...db.__state.localState,
transactionsState: { current: transaction },
},
},
};
const job = await acquireJob(state.sharedState.jobsState, {
const job = await acquireJob(db.__state.sharedState.jobsState, {
type: "runTransaction",

@@ -60,39 +103,43 @@ transaction,

const execOpts = {
log: {
suppress: Boolean(state.localState.suppressLog),
transactionId: transaction.id,
const startTime = performance.now();
const transactionState = {
current: transaction,
performance: {
prepareTime: 0,
execTime: 0,
freeTime: 0,
sendTime: 0,
receiveTime: 0,
totalTime: 0,
},
};
sharedState.transactionsState = transactionState;
try {
transactionsSharedState.current = transaction;
await eventsEmitter.emit("transactionWillStart", db, transaction);
await eventsEmitter.emit("transactionWillStart", state, transaction);
await dbBackend.execQueries(
unwrapQueries([sql`BEGIN ${sql.raw(transactionType)} TRANSACTION;`]),
execOpts
await db.runQuery(
sql`BEGIN ${sql.raw(transactionType.toUpperCase())} TRANSACTION;`
);
await eventsEmitter.emit("transactionStarted", state, transaction);
await eventsEmitter.emit("transactionStarted", db, transaction);
try {
const res = await func(state);
const result = await func(db);
await eventsEmitter.emit("transactionWillCommit", state, transaction);
await eventsEmitter.emit("transactionWillCommit", db, transaction);
await dbBackend.execQueries(unwrapQueries([sql`COMMIT`]), execOpts);
await db.runQuery(sql`COMMIT`);
await eventsEmitter.emit("transactionCommitted", state, transaction);
await eventsEmitter.emit("transactionCommitted", db, transaction);
return res;
return result;
} catch (e) {
console.error("Rollback transaction", e);
await eventsEmitter.emit("transactionWillRollback", state, transaction);
await eventsEmitter.emit("transactionWillRollback", db, transaction);
await dbBackend.execQueries(unwrapQueries([sql`ROLLBACK`]), execOpts);
await db.runQuery(sql`ROLLBACK`);
await eventsEmitter.emit("transactionRollbacked", state, transaction);
await eventsEmitter.emit("transactionRollbacked", db, transaction);

@@ -102,27 +149,116 @@ throw e;

} finally {
releaseJob(state.sharedState.jobsState, job);
transactionState.performance.totalTime = performance.now() - startTime;
logTimeIfNeeded(db, transaction.id, transactionState.performance);
releaseJob(db.__state.sharedState.jobsState, job);
}
};
// By default it is deferred
export const runInDeferredTransaction = <T>(
state: IDbState,
func: (state: IDbState) => Promise<T>,
const initAtomicTransaction = (): IAtomicTransactionScope => {
return {
__state: {
queries: [],
},
addQuery(q: ISqlAdapter): void {
this.__state.queries.push(q);
},
};
};
export const execAtomicTransaction = async (
db: IDb,
transactionType: "deferred" | "immediate" | "exclusive",
funcOrQueries:
| ((scope: IAtomicTransactionScope) => Promise<void> | void)
| ISqlAdapter[],
opts?: { label?: string }
) => runInTransactionFunc(state, "DEFERRED", func, opts);
export const runInImmediateTransaction = <T>(
state: IDbState,
func: (state: IDbState) => Promise<T>,
opts?: { label?: string }
) => runInTransactionFunc(state, "IMMEDIATE", func, opts);
export const runInExclusiveTransaction = <T>(
state: IDbState,
func: (state: IDbState) => Promise<T>,
opts?: { label?: string }
) => runInTransactionFunc(state, "EXCLUSIVE", func, opts);
): Promise<void> => {
const {
localState: { transactionsState: transactionsLocalState },
sharedState: { eventsEmitter },
sharedState,
} = db.__state;
if (transactionsLocalState.current) {
throw new Error(
"You are running atomic transaction inside of a transaction. Consider moving atomic transaction call to runAfterTransaction callback."
);
}
export const runInTransaction = <T>(
state: IDbState,
func: (state: IDbState) => Promise<T>,
opts?: { label?: string }
) => runInDeferredTransaction(state, func, opts);
const inputQueries = await (async () => {
if (Array.isArray(funcOrQueries)) {
return funcOrQueries;
} else {
const atomicTransaction = initAtomicTransaction();
await funcOrQueries(atomicTransaction);
return atomicTransaction.__state.queries;
}
})();
const transaction: ITransaction = {
id: makeId(),
type: "atomic",
};
const job = await acquireJob(db.__state.sharedState.jobsState, {
type: "runAtomicTransaction",
transaction,
label: opts?.label,
});
const transactionState = {
current: transaction,
performance: {
prepareTime: 0,
execTime: 0,
freeTime: 0,
sendTime: 0,
receiveTime: 0,
totalTime: 0,
},
};
sharedState.transactionsState = transactionState;
db = {
...db,
__state: {
...db.__state,
localState: {
...db.__state.localState,
transactionsState: { current: transaction },
},
},
};
const startTime = performance.now();
const queries = [
sql`BEGIN ${sql.raw(transactionType.toUpperCase())} TRANSACTION`,
...inputQueries,
sql`COMMIT`,
];
try {
await eventsEmitter.emit("transactionWillStart", db, transaction);
await db.runQueries(queries);
await eventsEmitter.emit("transactionCommitted", db, transaction);
} catch (e) {
console.error("Rollback transaction", e);
await eventsEmitter.emit("transactionWillRollback", db, transaction);
await db.runQuery(sql`ROLLBACK`);
await eventsEmitter.emit("transactionRollbacked", db, transaction);
throw e;
} finally {
transactionState.performance.totalTime = performance.now() - startTime;
logTimeIfNeeded(db, transaction.id, transactionState.performance);
releaseJob(db.__state.sharedState.jobsState, job);
}
};

@@ -1,3 +0,2 @@

import { IBaseToken } from "@kikko-land/query-builder/src/types";
import { ISqlAdapter } from "@kikko-land/sql";
import { ISqlAdapter } from "@kikko-land/boono-sql";
import { DeepReadonly } from "ts-essentials";

@@ -10,25 +9,25 @@

export type IKikkoEvents = {
initialized: (db: IDbState) => Promise<void> | void;
initialized: (db: IDb) => Promise<void> | void;
transactionWillStart: (
db: IDbState,
db: IDb,
transaction: ITransaction
) => Promise<void> | void;
transactionStarted: (
db: IDbState,
db: IDb,
transaction: ITransaction
) => Promise<void> | void;
transactionWillCommit: (
db: IDbState,
db: IDb,
transaction: ITransaction
) => Promise<void> | void;
transactionCommitted: (
db: IDbState,
db: IDb,
transaction: ITransaction
) => Promise<void> | void;
transactionWillRollback: (
db: IDbState,
db: IDb,
transaction: ITransaction
) => Promise<void> | void;
transactionRollbacked: (
db: IDbState,
db: IDb,
transaction: ITransaction

@@ -40,8 +39,21 @@ ) => Promise<void> | void;

id: string;
type: "atomic" | "async";
}
export type IQueriesMiddlewareState = {
dbState: IDbState;
result: IQueryResult[];
queries: (IBaseToken | ISqlAdapter)[];
db: IDb;
result: {
rows: IQueryResult;
performance: {
execTime?: number;
prepareTime?: number;
freeTime?: number;
};
}[];
performance: {
sendTime?: number;
receiveTime?: number;
totalTime: number;
};
queries: ISqlAdapter[];
};

@@ -59,19 +71,63 @@

export interface IDbState {
// mutable object
sharedState: ISharedDbState;
// immutable object
localState: DeepReadonly<ILocalDbState>;
export interface IAtomicTransactionScope {
__state: {
queries: ISqlAdapter[];
};
addQuery(q: ISqlAdapter): void;
}
export interface IDb {
__state: {
// mutable object
sharedState: ISharedDbState;
// immutable object
localState: DeepReadonly<ILocalDbState>;
};
runInTransaction<T>(
func: (state: IDb) => Promise<T>,
opts?: { label?: string; type?: "deferred" | "immediate" | "exclusive" }
): Promise<T>;
runAtomicTransaction(
func:
| ((scope: IAtomicTransactionScope) => Promise<void> | void)
| ISqlAdapter[],
opts?: { label?: string; type?: "deferred" | "immediate" | "exclusive" }
): Promise<void>;
runQueries<D extends Record<string, unknown>>(
queries: ISqlAdapter[]
): Promise<D[][]>;
runQuery<D extends Record<string, unknown>>(query: ISqlAdapter): Promise<D[]>;
runAfterTransactionCommitted(
func: (db: IDb, transaction: ITransaction) => void
): void;
runAfterTransactionRollbacked(
func: (db: IDb, transaction: ITransaction) => void
): void;
}
export type IQueryValue = number | string | Uint8Array | null;
export type IQuery = { values: IQueryValue[]; text: string };
export type IQueryResult = Record<string, IQueryValue>[];
export type IExecQueriesResult = {
result: {
rows: IQueryResult;
performance: {
prepareTime?: number;
freeTime?: number;
execTime?: number;
};
}[];
performance: {
sendTime?: number;
receiveTime?: number;
totalTime: number;
};
};
type IDbInstance = {
initialize(): Promise<void>;
execQueries(
queries: IQuery[],
opts: { log: { suppress: boolean; transactionId?: string } }
): Promise<IQueryResult[]>;
execQueries(queries: IQuery[]): Promise<IExecQueriesResult>;
stop(): Promise<void>;

@@ -81,2 +137,11 @@ };

export type ITransactionPerformance = {
freeTime?: number;
sendTime?: number;
receiveTime?: number;
prepareTime?: number;
execTime?: number;
totalTime: number;
};
export interface ISharedDbState {

@@ -95,5 +160,10 @@ dbName: string;

transactionsState: {
current?: ITransaction;
transactionsState?: {
current: ITransaction;
performance: ITransactionPerformance;
};
transactionLoggingState: {
i: number;
id: string | undefined;
};
}

@@ -100,0 +170,0 @@

@@ -1,8 +0,10 @@

import { ISql } from "@kikko-land/sql";
import { ISql } from "@kikko-land/boono-sql";
import { IDbState, IQuery } from "./types";
import { IDb, IQuery } from "./types";
export const assureDbIsRunning = (state: IDbState, toStart: () => string) => {
export const assureDbIsRunning = (state: IDb, toStart: () => string) => {
const {
sharedState: { runningState, dbName },
__state: {
sharedState: { runningState, dbName },
},
} = state;

@@ -9,0 +11,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc