0:30:22 Yeah, certainly.
0:30:23 So in the very first instance, I
was just jSON serializing the content
0:30:29 of the store and writing it to local
storage, or to session storage, or to
0:30:34 file, because you can obviously run
TinyBase on a node server as well.
0:30:38 And, that's great, and in 2022 that
seemed like the Basically, you know,
0:30:45 when you're thinking about small stores
anyway that seems like a fine array of
0:30:49 ways to do it, but Obviously people start
to push the boundaries of what you can
0:30:53 store in those media and just serialize
JSON isn't necessarily the way to go
0:30:56 So I think IndexedDB was probably the
next one that I tackled was not as easy.
0:31:00 , just Just as a small side
note, IndexedDB is not the most
0:31:05 enjoyable API to work with.
0:31:08 Most notably, it lacks any form of
reactivity whatsoever that I know of.
0:31:12 I think there were some proposals
that never went anywhere.
0:31:15 But there's no observability.
0:31:17 So it's kind of Crappy to have
to poll for changes, but , yeah,
0:31:22 I do now have that as well.
0:31:24 So you can either save your in
memory store to IndexedDB or load
0:31:29 it or automatically save to it when
changes happen or automatically load
0:31:33 from it with a polling mechanism.
0:31:35 so that, that, that, that's there as
well and and then around the same
0:31:40 time, in fact, it was Matt Wonlow
that I know it was on your show a
0:31:43 little while back he was working on his
CR SQLite solution and I started to see
0:31:50 that SQLite was starting to emerge.
0:31:53 as as a browser opportunity.
0:31:57 And so I figured, well, you know, there'll
be people who want to store it in the
0:32:00 browser on, on a SQLite database as well.
0:32:03 So I went down the path
of supporting that.
0:32:06 So the tables that were in your
memory store in TinyBase can
0:32:10 now be literally written out
to tables in a SQLite instance.
0:32:14 Or read in, and again,
reactivity is not perfect.
0:32:19 , some APIs are better than others,
but you know, do what I can to, to
0:32:23 keep that as synchronized as possible.
0:32:26 And that then opened the door
to support things like PowerSync
0:32:31 and, uh Turso and ElectricSQL.
0:32:37 , I also did.
0:32:38 PartyKit along the way, which is
not a SQLite store, but it's a
0:32:42 kind of a WebSocket based way of
storing data up in a durable object,
0:32:46 and so it supported that also.
0:32:49 So yeah, there was a period, probably
over the last year or so, that the
0:32:52 version 4 series of TinyBase, if you like,
where each major release was me adding
0:32:56 support for one of these new storage
technologies or synchronization platforms.
0:33:02 The other two that are very worthy of
note are AutoMerge and YJS, so those
0:33:08 are more classic CRDT technologies,
but you can store TinyBase into a
0:33:13 Yjs document, or load it from a Yjs
document, or into an automerge document.
0:33:18 And then, of course, you've
got the benefit of those two
0:33:20 platforms synchronizing in
whatever way they want to.
0:33:23 So, yeah, I guess you could say
I, am providing a lot of options.
0:33:28 Maybe too many.
0:33:29 I, Suspect that when you go to
the website and you see all these
0:33:31 baffling options, you're like, Oh
yeah, but which do I actually choose?
0:33:34 so what I'm hoping to do actually fairly
soon is write a guide for, you know,
0:33:38 this is the kind of app I'm building.
0:33:39 This is the kind of platform I should
use, or this is how I should synchronize.
0:33:43 Do I do the synchronization myself or
do I rely on some third party to do it?
0:33:47 And at the same time, obviously we've
seen companies like PowerSync and
0:33:51 ElectricSQL, you know coming forward
with their, their solutions here.
0:33:54 And so, yeah, if people are using
TinyBase and they want to Provide
0:33:58 a a gateway to those systems,
then that's that option as well.
0:34:01 So yeah, I have tried to
be as flexible as possible.
0:34:04 One of the privileges, I guess, of
working on this as a hobby is that,
0:34:07 you know, I can be open to working with
as many of these partners as possible,
0:34:12 whether they're commercial startups
or just open source projects, right?
0:34:15 I'm not in competition with anybody.
0:34:18 And so if I'm providing a way for
developers to onboard onto these
0:34:21 different things, then that's great.
0:34:22 I definitely have a view that
the, the tide is rising up.
0:34:26 I'm saying that on a boat but the local
tide is rising, local-first tide is
0:34:30 rising, and I'm happy to see all boats
go with it even in the long term.
0:34:35 , even if in the long term TinyBase
becomes not needed because, you
0:34:40 know, all of these other platforms
have, have matured to the point where
0:34:43 they're offering what I already do.
0:34:44 But I think in the meantime, I'm hopefully
providing a nice, disambiguation
0:34:49 layer or you know, something like
that to help people decide what their
0:34:53 approach is going to be without having
to rewrite their app dramatically.
0:34:57 So yeah, today you could store
your TinyBase data to local
0:35:00 storage and tomorrow you could
then sync it to ElectricSQL.
0:35:03 Why not, right?
0:35:04 So in terms of the data that is persisted,
let's say to IndexedDB or OPFS, SQLite,
0:35:11 or synced to one of the syncing providers,
how do you bring the data into memory?
0:35:18 And do you typically, let's say
I have a, let's say I'm using
0:35:22 Turso and have my SQLite database
somewhere, Is TinyBase automatically,
0:35:27 hydrating all of that data from the
database into the in memory version?
0:35:32 Or is there some sort of scoped
version where maybe the database is two
0:35:36 gigabytes and you only can constrain
yourself to 200 megabytes in memory?
0:35:42 how are you handling that?
0:35:43 Right.
0:35:44 So for all of the database based
persisters, I call them, there's a
0:35:48 configuration where you say which
tables you want and, you know,
0:35:52 whether you want to just load from
those tables or whether you also
0:35:55 want to be able to save back to them.
0:35:57 the worst thing I could think of would
be somebody with some large production
0:36:00 database and they connect TinyBase to
it and the next thing you know, it's
0:36:03 tried to load the entire database into
memory or it's tried to write No, back
0:36:08 to the whole database, and then, you
know, that's the end of the world.
0:36:10 So no, it's all very configurable
on a table by table basis.
0:36:15 And the one thing I have not done,
but I'm pretty sure I need to
0:36:18 do, is also provide some kind of
pagination or filtering on that view.
0:36:23 because if you've got a database that
has, let's say you, you, you shard
0:36:27 it on user or something, and you only
want to be able to see just the data
0:36:31 from that user, which, you know, it's
gonna be a pretty common use case,
0:36:34 then make sure that persistence is
not for the whole table, but just
0:36:38 for the relevant rows, of that table.
0:36:41 I think it's going to be
harder than I think it is.
0:36:43 I suspect there are lots
of gotchas to doing that.
0:36:46 , and so for now, there's my, my solution
or my suggestion will be that people
0:36:51 doing this should probably have a per
user database, which is kind of an
0:36:56 interesting approach that I know some
people have started taking anyway,
0:36:59 for, for edge based, databases.
0:37:02 Um, so that, you know, you're,
you're in no danger of, accidentally
0:37:06 loading data from a different
user into someone's browser.
0:37:09 But no, that's definitely
something I need to tackle.
0:37:12 So it's scoped, to answer your question,
it's scoped to individual tables as
0:37:16 to whether it's load or save or both.
0:37:18 But I think over time we
need to add more pagination.
0:37:21 So that you are just looking at,
you know, the top 10 records,
0:37:23 100 records, or what have you.
0:37:25 The reactivity gets really tricky
at that point because I'm sure you
0:37:29 know, you know, SQLite's reactivity
out of the box is pretty weak.
0:37:32 At best, you're going to
know that a table changed.
0:37:35 And what are you going to do?
0:37:36 Query the whole table to find out
which row it was that changed.
0:37:40 And so knowing that it was row 47 out of
2 billion that was the one that changed.
0:37:45 is not currently something that the
database platforms provide by default.
0:37:49 Um, So, that's one thing where I
am really having to work around
0:37:54 those limitations right now.
0:37:56 , and I'm hoping, if I can't make it
clearer to you, I'm hoping that people
0:37:59 working on SQLite are going to crack
this and provide, you know technologies
0:38:03 that make it easier to synchronize
at a much more granular level, or get
0:38:06 reactivity at a much more granular level,
so that TinyBase isn't having to poll
0:38:10 everything in a way that doesn't scale.
0:38:13 Yeah, I mean, I, I think, Ideally
for SQLite, the most principled and
0:38:21 foundational approach would be to
rebuild SQLite from the ground up to
0:38:27 be incremental and to be reactive.
0:38:29 And I think actually a former coworker
of yours, who is um, Julian, who
0:38:35 has also created, like HipHopVM
at, at Facebook and, and HackLang.
0:38:40 he's actually trying to, to do that with
a new startup called, Skip that is a
0:38:45 very ambitious, or even audacious goal to
build the whole new database from scratch
0:38:50 to be reactive, from the ground up.
0:38:53 Which I think is very, very interesting,
but short of that, I think you, you're
0:38:57 left by imposing, reactivity, primitives
on top of SQLite and the best you can
0:39:04 do there is to do the minimal amount
of work, you need at a given situation.
0:39:09 So instead of pulling the entire table
that, you know, okay, row 47 has changed.
0:39:16 And that requires quite a bit of like
a reactivity system on top of it.
0:39:20 And so luckily with, a signal like
system, that is a, it's a pretty
0:39:25 good, primitive to put on top of
it, to implement that reactivity.
0:39:30 But, yeah, it's not as efficient
as you, if you'd build it
0:39:33 from the, from the ground up.
0:39:35 That being said, SQLite is so fast that
you get a lot of performance benefits out
0:39:40 of the box and you can get away with it.
0:39:42 Yeah, that's true.
0:39:43 you know, certainly on the client.
0:39:44 Um, yeah, I, I, without, you know,
sharing too much, internal stuff,
0:39:49 there was a big push, at Facebook.
0:39:51 I'm thinking six, seven years ago, you
know, to think about reactivity for
0:39:56 the entire Facebook stack, because this
concept of, you know, taking the ideas
0:40:00 of React that were out on facebook.
0:40:02 com and bringing them all the way back
through the web servers, which are
0:40:06 HHVM, all the way through to the data
stores that were being used at the
0:40:10 company, you know, like it's a utopian
vision, but like, if you can make
0:40:14 that push based all the way through.
0:40:16 That's spectacular.
0:40:17 and you know, Julian and I were
probably in many of the same, uh
0:40:22 discussion groups and, you know,
internal Facebook groups where a lot of
0:40:25 these ideas were being bounced around.
0:40:27 And, and so yeah, when he left and
went off and did, Skip and you know,
0:40:31 I guess maybe some of this informed my
thinking about TinyBase too, you know,
0:40:36 that dream is still very much alive.
0:40:40 and yeah, it's coming from, ironically,
it's like it's coming from React.
0:40:44 That idea is coming from React.
0:40:45 It's just like, well, okay, can we bring
that idea a little bit further back,
0:40:48 and then a little bit further back,
and then a little bit further back?
0:40:51 Oh, like, and then we
end up on the database.
0:40:53 Like, why can't we get the database to be,
you know, telling us about these changes?
0:40:57 And, yeah, I guess that
would be the vision.
0:41:00 Unfortunately, I haven't checked in
recently, but I think SkipDB wasn't
0:41:04 Wasn't at a level where I could start
working with it, when I last looked.
0:41:08 Um, so yeah.
0:41:10 I think it's not yet fully production
ready, but as far as I know,
0:41:13 they're just still working on it.
0:41:15 So in terms of the query layer
for TinyBase, you have, not
0:41:21 implemented SQL as a query language
on top of your own data store.
0:41:25 Um, so yeah.
0:41:25 But you've provided, given that
JavaScript or TypeScript is the
0:41:29 primary way how you interact with
it, you've just embedded a DSL, as a
0:41:34 query language directly into TinyBase.
0:41:36 So would you mind briefly describing
that and, how that describes a user
0:41:40 experience or the developer experience?
0:41:42 Right, right.
0:41:43 So the, the journey here for me was
that first I knew there were going
0:41:47 to be some very simple query like
primitives that I wanted to have.
0:41:51 So one is, like a metric, which
is some kind of, you know, number
0:41:57 derived from the content in a table.
0:41:59 And I knew that that was going to be the
first thing I wanted to have if I was
0:42:02 building this hypothetical GitHub app.
0:42:04 I was going to want to have a number
in the top that said number of repos,
0:42:07 and I was going to want to have a
number that said number of commits.
0:42:10 And so I actually baked in.
0:42:12 a kind of a metrics oriented DSL where you
can define a metric which is, you know,
0:42:19 basic aggregates, counts, averages, sums,
those sorts of things, which by default
0:42:24 is normally just counting the rows in a
table, but that is then a reactive entity.
0:42:29 So again, you can say, I just want
this span in the top right hand
0:42:33 corner of the window to just always
show whatever that metric was,
0:42:36 and then you can forget about it.
0:42:38 And if that table is updated, You
know that number's going to change,
0:42:40 TinyBase will take care of it.
0:42:42 another thing that I knew I
was going to need to do was
0:42:44 relationships between tables.
0:42:45 So I built a very specific thing for
just one local table, one remote foreign
0:42:51 table, and then like keys between them.
0:42:53 So the value of one column in one table
is used as the identifier for another.
0:42:57 And so, yeah, you want to see the issues
just for this repo, or you want to see
0:43:01 the repos just for this user, then you'll
be able to do those kinds of things.
0:43:04 So those are, were actually baked in
pretty early to TinyBase, just because
0:43:07 they seemed Very important, but I, I
guess I knew eventually people were
0:43:13 going to want to push that on and start
doing things like arbitrary queries.
0:43:20 And I toyed with the idea of, you
know, supporting SQL in some form.
0:43:26 And I should say, I love SQL.
0:43:28 I have been writing SQL most of
my professional career, which
0:43:30 you know, goes back a fair way.
0:43:33 And my most recent role at Facebook
was, you know, the data analytics
0:43:37 team in the data infrastructure org.
0:43:40 So you know, we were working
with SQL all the time.
0:43:43 Perhaps despite that, or because of
that, I kind of got nervous about doing
0:43:47 an arbitrary SQL parser, evaluator,
executor, and then being able to make
0:43:53 the results reactive, which was like,
that's the, that's That's the non deniable
0:43:58 requirement, like, it has to be, reactive.
0:44:01 So, I didn't really have a lot of
choice, but, oh, and by the way, you
0:44:06 know, a full SQL parser with all the
dialects you'd want is, like, it's
0:44:09 gonna quadruple the size of TinyBase.
0:44:12 It's just, it's code based.
0:44:13 So, no longer tiny.
0:44:15 Yes.
0:44:15 So, I wanted to come at it from
a slightly different direction.
0:44:19 I know I'm not the only person to have
thought of doing more like a DSL approach
0:44:22 to this, but I, I wanted to see whether
I could capture as much of the, the
0:44:26 valuable parts of SQL without turning
it into a place where people could build
0:44:31 stupid cartesian joins and kill their app.
0:44:34 so I wanted to make it kind
of a little bit on rails.
0:44:37 And yeah, it was the idea of TinyQL was
born, which is kind of a stupid name.
0:44:41 But it's, as you said, a DSL
that allows you to, you know,
0:44:45 select, where, group, limit.
0:44:48 , actually, no, I don't
have a limit in there.
0:44:50 I limit a later part in the pipeline.
0:44:53 But, yeah, basically allows
you to join tables together.
0:44:56 and then where them, there's havings and
groups and those kinds of things too,
0:45:02 which like really is what 98 percent
of people want to do with SQL anyway.
0:45:07 And haven't really come across too
many queries that I can't express
0:45:11 with these five or six quote keywords.
0:45:14 Yeah, the cool thing about
SQL is you can do anything.
0:45:17 The awful thing about SQL
is you can do anything.
0:45:19 And, I have worked with enough people
who thought they knew what SQL did and
0:45:24 didn't quite know what it did to, you
know, see the trouble you can get into.
0:45:27 So I really, yeah, wanted to make it a
little bit more constrained than that.
0:45:31 And it's, it's been,
it was a real journey.
0:45:33 That was a very tricky, for me, anyway.
0:45:35 , that was a very tricky thing to
build, especially making sure
0:45:38 that all the results are reactive.
0:45:39 Because, by the way, you know,
any of those tables could change.
0:45:43 Any of the rows in those
tables could change.
0:45:44 In fact, you don't want to react
to the changes of the results if
0:45:47 some of the irrelevant rows change.
0:45:49 You only want to know if it was
the relevant rows that changed.
0:45:51 So you have to set up listeners on
all the things that were relevant and
0:45:54 not the things that were irrelevant.
0:45:56 so that ended up being a little
harder than I thought, but yeah,
0:45:59 pretty proud with how it turned out.
0:46:00 And as a result, and I would urge
people to go check this out, You can
0:46:04 build kind of interesting analytics
apps, right, with this, in the browser.
0:46:09 So if you go to the TinyBase.
0:46:11 org demos, you'll see there's a demo.
0:46:14 I think it's called car
analytics or something like that.
0:46:17 And it takes a data set of car
data, different models, different
0:46:20 makes, miles per gallon, years.
0:46:23 So there's a bunch of numerical measures
and there's a bunch of dimensions.
0:46:27 And in the browser, it loads
all the data in pretty quick.
0:46:30 It's not that much data, but you
know, loads it in pretty quickly.
0:46:32 And then you can do groups,
sorts, filters, across all
0:46:35 of this data in the browser.
0:46:37 And it's like, it's completely instant.
0:46:39 It's like, great, love it.
0:46:41 and look, this is not going to be
great for querying the Facebook data
0:46:44 warehouse, however many hundreds of
petabytes that is these days, but
0:46:49 it is going to be fine if you've got
10 or 100, 000 rows in your browser.
0:46:53 And Don't be scared, people.
0:46:55 Like, getting a hundred thousand rows
of data into a browser is not hard.
0:46:58 The browser is perfectly
capable of doing that.
0:47:00 You know, most even phones
are very happy to run that kind
0:47:04 of sized data in, in memory.
0:47:06 so yeah, for a lot of even analytics
use cases, you can do, you could, you
0:47:09 could build interactive dashboards
with this kind of technology and
0:47:13 have a sort of constrained set of
queries all running off TinyBase.
0:47:17 And it's super feasible, and it's been.
0:47:20 It's been fun to build that.
0:47:22 Whether or not people are using
it in the wild, I don't know.
0:47:24 I should say, I don't put any
instrumentation into this product.
0:47:27 So who knows what people are using
it for, or how they're using it.
0:47:31 But I hope that those people who use
it do, do find the value of being
0:47:34 able to run queries, without, shooting
themselves in the foot with SQL.
0:47:37 Did you follow any sort of prior
art in regards to how you built
0:47:41 that reactive query system?
0:47:43 So, as I was working on a similar
part as, the work on Rffle, there,
0:47:48 there was, some prior art in
regards to Adapton and mini Adapton.
0:47:53 And so this was, some inspiration,
that we followed for the reactivity
0:47:57 system and we've like over time learned
that, it's very similar to how now like
0:48:04 signals is all the rage these days.
0:48:06 It's like very similar
in terms of the ideas.
0:48:09 So did you follow some,
some similar paths?
0:48:12 No.
0:48:13 And I wish I had.
0:48:14 I think it's one of my weaknesses.
0:48:16 One of my weaknesses is
that I look at a problem.
0:48:18 You know, it's like the
famous Hacker News thing.
0:48:19 It's like, I could have
built that in a weekend.
0:48:22 I, I look at a reactive query system.
0:48:23 I think, yeah, I'm sure
I could build that.
0:48:25 And then like two months later, I
was like, I wish I'd read a bit more.
0:48:30 I am not good at prior art and
reading scientific papers or even
0:48:35 just, you know, looking at other
projects to see how they're done.
0:48:37 I think, you know, I know what
the result should be and I'm
0:48:39 going to try to build it myself.
0:48:40 And then I get into trouble.
0:48:42 Fortunately, I worked
my way out of trouble.
0:48:44 If it makes you feel any better,
even with knowledge of the prior art,
0:48:48 it still took easily more than two
months just to get anything working.
0:48:53 So,
0:48:55 Okay, that's just, that's just my,
my weakness that fortunately I
0:48:59 was able to work around this time.
0:49:00 But yeah, I think the other thing is
that I obviously knew in intense detail
0:49:06 how the reactivity of the underlying
tables, rows, and cells were right.
0:49:11 And so I knew how I was gonna have to
cascade the listener trees into all
0:49:16 the relevant parts of the database.
0:49:18 And, That was, yeah, that was just
something I had to figure out for myself.
0:49:23 The other thing I alluded to
earlier is that TinyBase is
0:49:27 just draped with test cases.
0:49:29 Like, I am exhaustive, overly exhaustive.
0:49:32 I'm completely OCD when
it comes to test cases.
0:49:35 It's not quite TDD.
0:49:37 I don't always do the tests first,
but, you know, I do eventually try
0:49:41 to make it look like I did TDD.
0:49:42 So I built every possible query I can
think of, and I build all these demo
0:49:46 apps, and I build all these sample,
you know, fragments of code, and
0:49:50 they all get tested exhaustively, and
so I figure out, well, once, once,
0:49:55 once those work, I'm probably there.
0:49:57 So that, that was my
benchmark, and I got there.
0:49:59 It's probably, I'm sure it's
still possible to break it,
0:50:02 but, you know, I think, I think
I'm about where it needs to be.