Kikko is a wrapper around SQLite interfaces. It brings transaction support, middlewares for queries, and SQLite adapters for the most popular platforms.
It also allows you to build data heavy reactive interfaces on top of SQLite for any platform with any framework or lib.
Full documentation can be found on the site.
Also you can check React example at CodeSanbox (multi-tab is not supported due to CORS).
Actually, what kikko is:
- Correct transaction handling, with transaction and queries queue
- Middlewares api, to intercept all running queries
- Built-in profiler information
And it also require db backend, that should implement needed interface. Other things, like reactive-queries-plugin
(which gives reactivity for React or Vue) or migrations-plugin
, are optional to install and use.
Kikko | |
---|---|
⚖️ Tiny size | < 15kb size in gzip |
📱 Wide platforms support | Web, mobile(react-native, expo, cordova, ionic), desktop(electron, tauri). |
🧰 Lib-agnostic | Use with React, Vue, Svelte (WIP), Angular (WIP) or any other lib/framework you want. |
🐛 Easy to debug | Kikko colorize queries, so, for example, you can easily understand to which transaction query belongs. He also meausures preparation, transfer and execution time. |
🔐 Secured by default | With template literals, all vars that are used will be automatically marked as prepared statement variable that reduce chances of SQL injections a lot. |
🛠 Plugin system | Allows you to integrate your own code on query/transaction run. |
🥹 Full typescript support | Yes! |
import {
makeId,
sql,
useDbQuery,
useFirstRowDbQuery,
useRunDbQuery,
} from "@kikko-land/react";
type Note = { id: string; title: string };
const notesTable = sql.table`notes`;
export const Notes = () => {
const notes = useDbQuery<Note>(sql`SELECT * FROM ${notesTable}`);
const notesCount = useFirstRowDbQuery<{ count: number }>(
sql`SELECT COUNT(*) FROM ${notesTable}`
);
const [addNote, addNoteState] = useRunDbQuery((db) => async () => {
const id = makeId();
await db.runQuery(
sql`INSERT INTO ${notesTable}(id, title) VALUES(${id}, ${`Note#${id}`})`
);
});
return (
<>
<button
onClick={addNote}
disabled={
addNoteState.type === "running" || addNoteState.type === "waitingDb"
}
>
Add note
</button>
<div>Add note result: {JSON.stringify(addNoteState)}</div>
<div>Query result (total notes count: {notesCount.data?.count})</div>
<pre>{JSON.stringify(notes)}</pre>
</>
);
};
Platform | Uses | Package | Example | Doc |
---|---|---|---|---|
Vite + React | @kikko-land/better-absurd-sql | @kikko-land/absurd-web-backend |
Link | Link |
Tauri + Vite + Vue | tauri-plugin-sqlite | @kikko-land/tauri-backend |
Link | Link |
Create-react-app | @kikko-land/better-absurd-sql | @kikko-land/absurd-web-backend |
Link | Link |
Expo | @kikko-land/better-absurd-sql for web, expo SQLite for native | @kikko-land/absurd-web-backend @kikko-land/native-expo-backend |
Link | Link |
Electron | better-sqlite3 | @kikko-land/electron-better-sqlite3-backend |
Link | Link |
Ionic | @awesome-cordova-plugins/sqlite | @kikko-land/absurd-web-backend @kikko-land/native-ionic-backend |
Link | Link |
React Native | react-native-sqlite-storage | @kikko-land/react-native-backend |
Link | Link |
Cloudflare D1 | Cloudflare D1 | @kikko-land/d1-backend |
Link | Link |