Index āŗ 5. Persistence
Learn how to persist information using Kittenās built-in JavaScript Database (JSDB)
Topics covered
- Persistence.
- JavaScript Database (JSDB).
- The Kitten CLIās
db
command. - Your projectās entrypoint (the main.script.js file).
- Database app modules.
Persistence (is not) futile!
So counting kittens is great fun but what happens if you restart the server?
All your kittens are lost! (This is a tragedy.)
So letās fix that.
(Brace yourself, youāre about to use ā drumroll ā a SCARY database! Oooh!)
š» Using JavaScript Database (JSDB) ā a (not so) scary database
š” Kitten has recently been upgraded to use the latest JSDB 5.1.0 with JSDF 3 (JavaScript Data Format version 3). If you were storing custom objects or objects with properties that begin with an underscore (_), you should check out the JSDB 4 to 5 (JSDF 2 to 3) migration guide.
Update your code to match this:
if (kitten.db.kittens === undefined) kitten.db.kittens = { count: 1 }
export default () => kitten.html`
<h1>Kitten count<h1>
<p>${'š±ļø'.repeat(kitten.db.kittens.count++)}</p>
`
Your page should automatically reload in the browser with the new count.
Now refresh the page a few times, manually stop the server, restart it, and load the page againā¦
Wait, what?
Thatās it?
Seriously?
Yep, thatās the magic of the integrated JavaScript Database (JSDB) in Kitten.
If you donāt believe me, restart the server and note that all your kittens are still there.
If you still donāt believe me (wow, what a cynic), look in the following folder:
~/.local/share/small-tech.org/kitten/data
You should see another folder in it that mirrors the path of your project along with the domain and port you ran it at.
For example, if your project is in:
/var/home/aral/kitten-playground
And you ran it locally at the default domain and port (which is localhost
and 443
), then the folder will be named:
var.home.aral.kitten-playground.localhost.443
Inside this folder (your projectās database folder), you should see a kittens.js file.
Open it up in a text editor and take a look at it.
It should look something like this:
export const _ = { 'count': 40 };
_['count'] = 41;
_['count'] = 42;
Thatās what a table looks like in JavaScript Database (JSDB), the database thatās integrated into Kitten and available from all your routes via the global db
reference.
Kitten db command
Kitten provides you with a simple way to get information about and see a live view of your tables.
To get general information about the database, including where the database is located and which tables it has, use the db
command from your projectās folder:
kitten db
If you want to see a live view of the contents of a table, add its name to the db
command.
So for the Persisted Kitten Count example, if you wanted to see the kittens table, you would enter:
kitten db kittens
š” You are not limited to storing plain objects in your database. You can also store custom objects (instances of custom classes) and get them back with the correct type when you read them. Thatās a more advanced feature, however, and you will need to implement a database app module to do it.
Check out the database app module in the Domain project to see an example of advanced database use in a larger real-world app.
š” Thereās so much more to JSDB and you can learn all about in the JSDB documentation.
Initialising things
If initialising your database table in your route feels a little yucky, thatās because it is. What if more than one route needed to use that table? If we werenāt absolutely certain that the routes would be called in a given order, weād have to repeat the conditional initialisation in every route just to be safe.
You can see how this could become a maintenance nightmare.
Fear not, Kitten to the rescue!
If you create a special script called main.script.js in the root of your project folder and export a default function from it, Kitten will import that function and run it at start up.
This is a great place to carry out global initialisation for your app. This function also gets passed a parameter object with a property called app
thatās a reference to the Polka app instance so you can perform advanced tasks like adding custom middleware, etc., if you need to.
For our purposes, we could move the conditional initialisation of our database table to main.script.js like this:
export default function () {
if (kitten.db.kittens === undefined) kitten.db.kittens = { count: 1 }
}
Which would leave our route looking rather pristine:
export default () => kitten.html`
<h1>Kitten count</h1>
<p>${'š±ļø'.repeat(kitten.db.kittens.count++)}</p>
`
š” There is another way to achieve this thatās specifically designed for the purpose of initialising databases (and adding strong typing to them) using a special App Module. You havenāt seen App Modules yet but, to get a feel for it, take a look at how itās used in Domain: https://codeberg.org/domain/app/src/branch/main/app_modules/database
Right, so now that we know that persisting things isnāt scary in Kitten, letās take another aside and look at one of Kittenās nifty features: its interactive shell (REPL). And, in the process, weāll also learn more about Kittenās JSDB database and take a first look at how components and fragments work in Kitten.
Next tutorial: Kittenās interactive shell (REPL)