Video #329: Point-Free Live: A Vision for Modern Persistence
Episode: Video #329 Date: Jun 30, 2025 Access: Members Only 🔒 URL: https://www.pointfree.co/episodes/ep329-point-free-live-a-vision-for-modern-persistence

Description
We go live with our viewers to unveil our vision for modern persistence. We show just how easy it is to seamlessly synchronize your app’s data across many devices, including sharing data with other iCloud users, and we answer your questions.
Video
Cloudflare Stream video ID: 25def18e949b4e3783dde92472711dff Local file: video_329_point-free-live-a-vision-for-modern-persistence.mp4 *(download with --video 329)*
Transcript
— 0:00
Okay, we are live and we are on YouTube. Hey everybody. Hello. So, alright, we’ve got a big live stream planned, and we have switched off of Vimeo for streaming and we recently even switched off of Vimeo for our video hosting. so, so we’ve got CloudFlare in our videos and we’re using YouTube for our streaming. Brandon
— 0:33
And of course this is a new channel we’ve got even on, YouTube. So if people wanna subscribe to it, we, we have hopes to, to put stuff on this YouTube channel, but, you know, who knows, who knows who’s got time for that. so this live stream is all about, cloud kit synchronization and modern persistence. Brandon
— 0:55
We just finished our big modern persistence series and we. Are really excited to show what the next step for our modern persistence is. And for us, what that is is completely seamless cloud kit synchronization. The, the idea that you could have your entire app built on SQLite and it could use your SQLite database exactly how you would want to typically, but secretly behind the scenes it is synchronizing everything to cloud kit. Brandon
— 1:25
And, and then on top of that, the idea that you could take a record in that database and share it with another user so that they can make edits to it. And everything is synchronized between all these services and it’s just, it just all kind of happens magically and, and Apple’s taking care of all the server. Brandon
— 1:41
You know, storage of the data and we’re taking care of all the different events that can be coming back and forth between devices. And so we wanna demonstrate that we haven’t released any of these tools yet. It’s all built into our SharingGRDB library. We’re gonna give a little preview of it and then we will give some, news about how we plan on actually releasing this stuff. Brandon
— 2:02
And so we’ve got two demos lined up. I’m gonna do one and then Stephen, you’ll do the other. And, I’ll do the first demo. And it, what it’ll show is a completely local app with no. Cloud synchronization whatsoever, and we’ll show what it takes to add synchronization to it. And Stephen will monitor the chat during that time and we will answer lots of questions. Brandon
— 2:23
And then Stephen’s gonna take a fully built app with synchronization and everything and show how you can just layer on like more and more advanced features on top of it. and, and yeah, along the way we’ve got tons of Q&A that were submitted to our Vimeo, livestream. that was before we knew we were gonna switch over to YouTube. Brandon
— 2:41
So we’ve got screenshots of all those questions and we’ll, we’ll show them and, and answer them. And of course people can, we’ve got a Q&A open up in YouTube right now. You can of course use that, to ask questions and then we’ll be monitor monitoring the chat the best we can. So I think I wanna get into it, so yeah. Brandon
— 3:00
You ready, Stephen? Stephen
— 3:02
Yeah, let’s do it. CloudKit sync/sharing from scratch Brandon
— 3:03
Okay. So, all right, here we go. All. I’m gonna go to sharing my screen. And there we got it. And I’ve got the SharingGRDB library, which is our library for using the, the wonderful GRDB SQLite, database library. And we, we take that foundation and we add on a bunch of tools for integrating with SwiftUI. Brandon
— 3:31
And with even UI kit, and there’s just a lot of really nice tools in there. and there’s a lot of demos in this, in this repo. We’ve got a whole bunch of demos here for like this sync up app, which is a scrum dinger, port that, apple made that that really wonderful, example app in WWC a couple years ago. Brandon
— 3:48
And we kind of, we’ve repeatedly created it in various ways over the years. We’ve got a really fun reminders app. That’s what Steve will be looking at a little while and just kind of general case studies, but there’s a new demo here called Cloud Kit Demo. All right. And right now it is a very simple app and there is no actual cloud kit synchronization here. Brandon
— 4:07
We’re gonna add that together as a, as a live stream. All right. But I’ll start by running it in the simulator just so we can see what it does. And it’s, it’s not gonna be anything too impressive, but we need something really simple to start with so that we can really hone in on the ideas of synchronization. Brandon
— 4:23
And it allows us to create counters. And then we can count up and we can count down and we’ve just got, you know, as many counters as we want. And then we can, you know, swipe to delete them and get rid of ’em. All right. And all of this is stored. So if I, if I were to do this and, and reload it, it all, the data is stored in a SQLite database. Brandon
— 4:43
So with that, when I relaunch the counter is back, and then I can delete it if I want. so let’s just look at what it took to make this It does, it’s not a lot. It’s, it’s not the most impressive thing. I’ll start with, Stephen
— 4:54
oh, you, your simulator. Brandon
— 4:55
Oh. Oh. Was I just doing that whole thing without simulator? All right. Brandon
— 4:59
so let’s, that’s funny. I’ll, I’ll do it again. We got a ten second delay. Yeah, we got a little bit I can see on YouTube. all right, here we go. Now I think my simulator is showing. And all right, so I’m gonna add some counters, and we can individually increment and decrement them and then we can swipe away to delete. Brandon
— 5:28
And all this data is stored in SQLite, so I can relaunch the simulator and it should launch with that one counter sitting there all, and there it is. And then we can delete. So, so of course not the most impressive app, but you know, we gotta start somewhere. And so, let’s start looking at the code of what it took to take this, to, to build this. Brandon
— 5:46
We’ve got a SQLite table that represents a counter. It’s got an ID. It’s a UUID and that’s because in the cloud kit world and really in any kind of distributed schema system, auto incrementing, integers just don’t play nicely. with, with distributed schemas, you do need the ability for there to be globally unique IDs being generated across all these devices. Brandon
— 6:10
So, so this counter does need to be, have an idea of a U id. and it’s got its count of course. And then we do the standard thing of forming a connection to this database. We, we find a place on disk, we wanna put it, we, have a configuration. We prepare the database by printing out all the queries, going through it. Brandon
— 6:29
It’s really nice for debugging, create our connection to the database pool, and then we migrate it in order to create the SQLite table that powers this data type. All right. And then we migrate, Stephen
— 6:41
we’re getting some comments that your audio’s a little low and mine might be a little high. Brandon
— 6:45
Oh, okay. All right. Brandon
— 6:46
I’ll move closer to the microphone. And I can turn up a little bit and see what, we’ll see in 10 seconds if this is any better. okay, so, so, and I can also just give her the same letter here. All right, so here’s our, our SQLite table. it gets migrated and everything. And then let’s look at what the SwiftUI view looks like. Brandon
— 7:09
we’ve got this counters list view. We fetch all of the counters. This right here is, is the tool from our sharing JDV library. It fetches all the counters in the database. And then we show a, a section with all those counters, and there’s a row for each counter. When you do the swipe to delete, we can open up a database, right? Brandon
— 7:27
Transaction, go through all the indices, find that counter, and then delete it. we can have an ADD button that when tapped, opens up another right transaction and inserts a new counter into the database. And here we don’t have to specify an ID because this is just a draft. an ID will be. Created for us. Brandon
— 7:47
And when the row is inserted into the database and then each row holds onto one of these counters, and when you tap a minus button, we just do another right transaction where we find that counter in the database and we update it by decrementing. Its, its count by one. And then the same with adding, we started a right transaction. Brandon
— 8:07
Find the counter and update it by incrementing by one. Alright, so I hope everyone is, is with me now because what we’re gonna do is we’re gonna take this app and we’re gonna add synchronization to it. All right? And what happens as you go to the entry point of the app where you prepare your database, and I’ve already got an app delegate and seen delegate in place here because this is what we’re gonna need eventually for some of the sharing stuff. Brandon
— 8:32
And I didn’t wanna write all that from scratch. So. This is just your most basic little app delegate. And here’s where we override our dependencies to install the default database. And we put in that app database, which was this thing I just walked through a moment ago. And in here what you do is you provide another database and it’s called the default sink engine. Brandon
— 8:55
All right? And so this default sink engine is something we can construct and it takes some arguments and you do have to try the whole thing. And so you start with the CKContainer . And if you’re not familiar with cloud kit, the CKContainer ‘s kinda like a namespace for your database, essentially. I mean, it kind of is a database I don’t really know. Brandon
— 9:19
If there’s a, a strong distinction between these things. But this thing holds a CK database and in fact it holds a couple of CK databases ‘cause there’s private, shared and public databases. But this is our kind of view into the cloud kit servers and, and their databases. We need to identify and there is a little bit of setup you have to do in your EXCO project to get all this going. Brandon
— 9:38
And we, I’ve already pre-done that. I don’t think it’s very interesting or fun to do a live, so I’ve got some entitlements already set up. You, you would have to do that in your project. And I’ve already got a container identifier, which is this right here. Alright, so then the next argument is the database that you want to synchronize and that is this default database right here. Brandon
— 9:59
So this is what we, we wanna listen for changes in this database and play them back and forth to cloud kit, essentially. All right. And then the next one is a logger. We can leave that off for right now. And then the tables that you wanna synchronize, ‘cause there may be tables that you don’t wanna synchronize. Brandon
— 10:16
And so that will be counter self. And then there’s the concept of private tables, which we don’t have to worry about right now, but if there were tables that you didn’t want to allow sharing, then this would be, a place where you could, describe that. And that right there I think compiles and it should work exactly as it did before in the simulator. Brandon
— 10:37
I’ll get the simulator up. Alright, so I, I can still, oh, well, alright, so I got a bunch of counters coming in because this is from when, Steve and I were demoing it, yesterday. So, all right. Pretend you didn’t see that. Oops, I just moved that accent. I’m gonna delete these counters. I mean, that shows, you know, something’s working. Brandon
— 11:02
So the magic. Yeah. Yeah, that’s the magic. So, so if you hadn’t seen that, everything would work exactly as it did before, where I can add counters still and I can increment decrement. Everything is being saved to the SQLite database and is all available locally. But the fun thing is also behind the, behind the scenes, it is synchronizing this to cloud kit in order to demonstrate that. Brandon
— 11:24
Let’s, all right, so I’m gonna count this one up to 10. That’s negative two and two. So to demonstrate this, I’m gonna do something that I don’t think is a very smart idea, but I’m gonna do it anyway, which is, I’m gonna show my phone on a live stream. All right? There it is. And I’m gonna run this app on my phone. Brandon
— 11:48
All right. So let’s let that build and install. Brandon
— 11:53
All right. There it is. So if I, wait a moment, we got the counters streaming in and so we can even see it right on the screen. In fact, here I can even put this, this little simulator or drag it over here. So we see it lot like the, the ordering of the counters is not correct, but that’s ‘cause we’re not ordering. Brandon
— 12:13
So it’s, it’s a non-deterministic. It’s not determined by anything. But the, the numbers are the same. We got a negative 2, 2 10 on both sides. And if I were to say, count this one up to 15, and I wait a moment, so I count it on the simulator. I wait a moment, it should come. There it is. So now it is 15 on my, phone right now. Brandon
— 12:37
Now you would also like that, so on the phone I might count up that negative too. I’ll count it up to five. And you would like that, that would immediately synchronize to the iPhone. But unfortunately iPhones, they don’t get the push notifications required from cloud kit to have that actually sync automatically. Brandon
— 12:51
So the only thing I can do, Stephen
— 12:53
the, the simulator, Brandon
— 12:55
sorry, the simulator. The simulator does not get the, the push notifications to synchronize. And so it still says two and negative two here. Even though on my phone it’s got a five, but if I just relaunch it, then it will download everything. So let’s do that real quick, or that just relaunched my phone. Brandon
— 13:12
Let’s relaunch the simulator. Brandon
— 13:20
All right. it just popped in, so now we’ve got 15, two, and five on both devices. Alright, so, and then let’s just do, also I’ll delete, I’m gonna delete the 15. We wait a moment for it to synchronize and then a moment later it should show up on my phone. Boom. Two and five are now left. All right, so that is how it goes. Brandon
— 13:40
And, just to also, I’ll add a row. So I just added a zero. We wait a moment and on my phone it’ll show up. All right. There it is. All right. So that is the basics of how it works. And so it really was technically just adding this one line. Now, now there is a lot. That has to be done to get a database in shape to actually synchronize, depending on how your database is designed. Brandon
— 14:06
But it can technically be just this one line. And certainly if you start with a completely fresh project, then it is truly this one line because, ‘cause then you’ll just design your database schema to be mindful of these things. And we’ve got a lot of documentation about that. And, and in fact, we’ve gotten a lot of questions about it too. Brandon
— 14:21
I guess I could maybe even answer a couple of questions, either right now or, or a little bit later about this kind of stuff. But, but yeah. Well, I’m sure we’ll get to that, throughout the, the live stream. So. So now the next, I mean, one of the Stephen
— 14:36
questions is just. Migrating an existing app. Brandon
— 14:41
okay. So yeah, let’s, let’s get into it. Brandon
— 14:44
Yeah. I mean, Stephen
— 14:44
specifically John d asked, what’s the best way to migrate an existing app in production using SwiftData with cloud kit Sync to using, SharingGRDB Oh boy without risking potential loss of existing user data? Brandon
— 14:55
Yeah. Okay. Well, that, that one is, we don’t have a great answer for that is the, the most difficult situation to, to deal with. Brandon
— 15:03
and I dunno, maybe Stephen, you, Stephen, you’ve got some ideas, but the only thing that comes to mind for me is you are gonna have to have at some point, a hard cutoff in your app where you just have to tell people they have to update the app and forget the path. And you don’t allow people to use the old version of the app. Brandon
— 15:22
I, I don’t, I don’t know if it’s gonna be easy to be able to. Incrementally add a SQLite database that is kept in sync with a SwiftData database and have those live in for a while, and then some day just drop the SwiftData database. I’m, I’m just not sure about that. I think instead what you need is an app that copies over all the data from SwiftData into SQLite, and then that version of the app is the only version of the app that people are allowed to use, and you’ll have to have a kill switch on all older versions of your app to tell them, this app doesn’t work anymore unless you update. Brandon
— 15:53
That’s the only thing that comes to mind for me. Stephen
— 15:55
Yeah, I think as soon as a user is migrated, you need to flip a switch in cloud kit or, or somewhere else that gets synchronized so that if they try to access like the old version again, it just won’t let them. Brandon
— 16:08
Yeah. however, so you might even have to roll out an Stephen
— 16:11
old version just to have that kill switch before Yeah. Stephen
— 16:14
Introducing another version. Brandon
— 16:16
Yeah. You might need to release a, a kill, like a version of your app with a secret kill switch that you let be out there for a couple of months so that you can get as many people as possible and then activate the kill switch. But, but say you’ve got a SQLite, app out there that has, that’s local only, that one will be far easier to get into shape. Brandon
— 16:35
And for the most part it means converting any auto incrementing IDs to UUIDs. And we hope to have some tools in place that will automate that migration. ’cause it really should be. As easy as just literally just going through your tables, finding any ant ID columns and turning them into UUIDs. And you can even turn like the ID 42 into the UUID with all zeros and then 42. Brandon
— 16:57
So there should be a way forward there that should be a lot easier. Alright, so we’ve got synchronization that already is fun and you know, really powerful and nice, but then I’m gonna make it so that I can take one of my counters and share it with you, Stephen, and allow you to make edits and I can make edits and we can all have like the same counter. Brandon
— 17:22
Alright? And so to do that, yeah, so to do that we need to add some ui and so what I’m gonna do is go down to the counter row and at the end of this H stack, which has the plus minus and count, I’m gonna throw in. Let’s see. Did I get lost here? I think here I’m gonna add it. Well add, I might wanna hide Stephen
— 17:43
your simulator. Stephen
— 17:44
Oh, and yeah, Brandon
— 17:45
your phone. Alright. Yeah, thanks. So let’s get rid of simulator. Let’s get rid of phone. There we are. So I got, I’ll put a spacer to push this button away from the plus and minus and then I’m gonna put in a button with a label and I always forget. Let’s see, I want to image system name. So I think it’s a square and arrow up icon. Brandon
— 18:12
And then here we, so this will be a little share icon. And when you tap it, what we wanna do is interact with cloud kit saying we wanna share this record and then further display a UI to the user to allow them to share it. They can either text a link to a friend or they can just. Produce a, a like a global, like a public link that then allows anybody to join in on this. Brandon
— 18:37
And so to we, we have the functionality that kind of hides some of that away. And to get access to it, we need to get access to the default sink engine. So we’ve got a sink engine right here. This will be the one that we set up over in the app entry point. And we will, it’s got a method called share. And we can share a record. Brandon
— 18:57
It has to be a primary key table. And we’ve got that record. It is just the counter, so a throwing counter. Then it takes a trail enclosure that allows you to configure the share. And this is the CKShare that has just been constructed. And CKShare s. Get some system fields, like a title, and we can say, join my counter exclamation point. Brandon
— 19:19
And then this returns what is known. Oops. Let’s see. it’s a shared record and this holds some information that we need in order to then display a ui. So what we can do is hold onto the shared record as some at state, and this shared record is even identifiable, so we can use it in a sheet. So then I hop back down at the bottom of the view, I do a sheet item with a shared record. Brandon
— 19:49
Now we have a shared record. And then on top of that, our library comes with a cloud share view there, cloud sharing view that takes a shared record and that will, if we go into this, all this does is wrap the UI kit. UI cloud sharing controller and a representative. So nothing special here. but that will present the shared and or the sharing sheet and allow them to choose who they wanna share. Brandon
— 20:16
Alright? That is all that is required in order to share the record, just those few lines. But now we have to allow someone to accept the record. So someone like you in a moment will be running a version of the app that wants to be able to tap on the, those links in like your, in your text messages, and then open up the app and accept the share. Brandon
— 20:35
And that is why I have the scene delegate down here because in the scene delegate, there is an accept share, delegate method. And this gets called when someone launches the app to accept a share. And we gotta relay that back to our sink engine. So we do, we get access to the default sink engine again, and now we can say, accept share. Brandon
— 21:02
And then we pass along the metadata and it takes care of the rest. Now this is, oh, you know what? That’s funny. I, I haven’t built anything yet, so this is technically async and throwing. And so I’m gonna wrap this into a task. And then also, this is async and throwing, and so I’ll wrap this at a task and you should probably do some air handling here, but we won’t worry about that. Brandon
— 21:27
Now let’s build and see if I did everything right. All right, I did. So let’s give it a shot. I’m gonna load this up on, I’ll just do it in a simulator or, now I’ll do it on the phone. Alright, I’m gonna launch on the phone. I’m gonna show it in OBS. All right. And so what I think can happen, so we got these share icons, so I’m gonna take the five. Brandon
— 21:58
And so I tapped it, and now this is the default share sheet that shows up. And I can either add Stephen directly, like if I tapped this button, or I can just generate a public link and then I can just copy that link. oops. I think sometimes the, yeah, I saw copy the link. And now I’m gonna go over, I’m not gonna do this on my phone. Brandon
— 22:20
I’m gonna go over to my, my text messages on my computer. And Stephen, I’m gonna send you that link. And then I’m also gonna push this code and you’re gonna pull it and you’re gonna run it. Stephen
— 22:32
Yeah. Let me know. Brandon
— 22:33
All right. So I’ve pushed the code, I’ve sent you the link. So now you will pull the code, run the app, you’re gonna accept it, and then you’re gonna be able to make changes to this counter. Brandon
— 22:48
And while you do that, I’ll take a look at it building now. Okay. I. Stephen
— 22:55
And we could also answer some Q&A. Brandon
— 22:58
Yeah. About, yeah. I’ll, I’ll go through some Q&A. Alright. So, so one question back from the Vimeo, Q&A was regarding cloud kit sharing. as far as I know, there are two main paradigms. There’s hierarchical and record zone sharing. Which one does this library support? Brandon
— 23:26
And this is an example of the hierarchical sharing. So I, I have one record and I shared it with you. And then that would also share any associations with you. Here. We don’t have any associations, but it would, and so then there’s something called record or or zone sharing where you, you, you share an entire zone of records and I. Brandon
— 23:48
And you can still do that if you want, but there’s nothing in our library that supports that because that doesn’t seem to be actually very, rel or relevant to what we’re doing. As far as we know, we’re also not pros in cloud kit. And so, you know, we’re gonna expect the community to really kind of talk to us and let us know what, what they need out of these tools. Stephen
— 24:08
I did join your counter. It’s up to five. Brandon
— 24:11
Okay. it, yep. So you count to just something. Don’t tell me what it is and then we’ll all see it live. What it, what it goes up to Brandon
— 24:22
all I see. 10. Did you count it to 10? That’s Stephen
— 24:24
what I counted up to, yeah. All right. Brandon
— 24:26
So I, I hope this is coming through on the live stream. I’m, I’m not, I got my phone here. He’s got his phone here. you, you, you count up again. I’m not, I’m not touching the counter. I don’t know how to show this. I got, I got no fingers on the screen, but he counted up to 19 23, 24. Brandon
— 24:41
So all of his edits are, are coming through and synced to my device. And then of course, if, if I were to come in and I count it up to our favorite number 42, in a moment, he’s gonna get Yes. Yeah, he’s gonna get that 42. All right, so that is sharing. it only took a couple of lines and All right, so we, we answered that one question about the hierarchical sharing. Brandon
— 25:11
mm-hmm. And then I’ll, I’ll just go through a few others and if you see anything in the chat, feel free to interrupt. But there was another question about. Apple states that NS persistent Cloud kit container doesn’t support cross share relationships. is the library able to overcome this limitation? Brandon
— 25:29
we, we aren’t using NS persistent cloud kit container at all, that that’s a CoreData thing. and so that doesn’t factor into this whatsoever. This is all built on top of CK Sync Engine, which is completely agnostic of the actual underlying database, which is nice. I mean, it does know about the CK database that Cloud has, but the local way in which you arrange your data, none of that matters as far as CK Sync engine cares. Brandon
— 25:56
and let’s see. There was a couple of other fun ones in here. okay. So yeah, I think I’ll just go through some of these. I think we actually have already, addressed, but here’s a question from Kaya. Will the SDK manage the callbacks for when a user accepts a shared record? and so that we, we just showed, it’s what’s on screen right now is the scene delegate. Brandon
— 26:19
This is how you tap in and allow your users to accept shares. And then will there be a way for us to manage participants and manually remove from a share? well, that is gonna dovetail with exactly what I wanna show next, which is not only did it only take a couple lines to get all this going, but we don’t hide all of the underlying cloud kit information from you. Brandon
— 26:40
There is a world of CK records and CKShare s running all over the place, and we want all the information to be available to you. And so what I’m gonna do next is I’m gonna show how in this little shared list I’ve got on my phone, I wanna split these counters into two sections that my local counters and then my shared ones. Brandon
— 26:59
And that’s gonna help show that all of this, this, the CK record data is available to us. And then because it’s available to us, that is what you can use to then make modifications. If you wanna reach into a record, grab its ck, share and play around with the participants, you’re completely free to do that. Brandon
— 27:18
All right? And so to show that I’m gonna hop over. To the counter list. And so we’ve got this right here, fetches all counters. I want to be able to separate this into two layers of, we got local counters. I’m not gonna rename it right now ’cause that just calls a big mess down below. But those will be the local counters. Brandon
— 27:37
And then here we’ll have the shared counters. And, and thanks to like how fetch all and our tools are designed, we can actually perform these queries right in line right here. And so we wanna fetch all the counters that are not shared and then fetch all the counters that are shared. And the way we do this is there is a special table that is made accessible to us called Sync metadata. Brandon
— 28:02
All right? And if I go to it, what we’ll find is it is a SQLite table that exists in a database separate from your database. It has record type, which is the name of the table. It’s got record name, which is an amalgamation of the UUID and the table kind of built in. But this is the CK record name. It’s got information about the parent records. Brandon
— 28:26
It’s got information about the share, and it’s got information about the last known server record. Alright, so this has got everything sitting here and we publicly expose this for everyone to be able to grab. But because it’s a SQLite database or and a table on its own, you can join your tables. To this table and get everything all in one single query. Brandon
— 28:47
So I can actually take our counter table. Do you wanna Stephen
— 28:50
hide the The phone? Oh yeah, yeah. From OBS. I think it’s crowding the code just a little bit. Brandon
— 28:54
Yeah. Yeah. So we can take our counter table and we can join it to the sync metadata table. All right. So we can cross reference our records with the records that are in cloud kit databases. Brandon
— 29:09
And the way we join this is that we’ve got an ID column that’s our UUID, and we can check that that is equal to the Sync metadata’s record primary key, which represents the UUID of that record. so this will now give us access to our counter, along with any of its sync metadata. Alright? And then what we can do is, we can do aware where we say that we want that sync metadata to not be shared. Brandon
— 29:40
And so we can check is the shared nil. So that will filter out all, it’ll just filter to only take just the non-shared counters. And then ultimately we wanna get a counter out of this. And so we could just select and grab just the counter columns from this joined table. All right, so that right there is only the shared or the non-shared. Brandon
— 30:05
And so I’ll copy and paste this and just flip it to then say, is not nil, meaning all the counters that have some sync metadata or the share is not nil. That will be our shared counters. Alright? And so I’m just gonna copy and paste this. To say that this is our shared counters. So shared counters. Shared counters, shared counters, and then I think that’s it, if I’m remembering correctly. Brandon
— 30:37
Did you Stephen
— 30:37
attached the MET database? I might have been. Brandon
— 30:39
I did not. But let’s, let’s show that, because then they’ll show that, one extra step we gotta do. So here we are. I gotta show my iPhone. There’s no counters listed, and we’ve got, that we would’ve a Stephen
— 30:59
And you’re not sharing the, the phone. Brandon
— 31:02
Oh, I, I did. Brandon
— 31:03
You may, there may be a still a delay. let’s see. Brandon
— 31:12
Okay, so I saw, I saw the, something come up here. I. So this should be a purple runtime morning. I don’t know if maybe I’m too constricted here that it’s not showing the, where do those things usually show over here? I don’t know. It’s not showing. I saw Stephen
— 31:31
with your previous spell. Oh, it, it’s, ‘cause it’s on my Brandon
— 31:33
phone. Brandon
— 31:33
It’s not the simulator. So on the simulator it would show correctly. so maybe I’ll just switch back to phone because I don’t think I really even need to do this anymore. So let’s go back to simulator. Bring it over here. now? Hmm. Still okay. Oh wait, I’ve got this filtered. Brandon
— 31:57
Hmm. Brandon
— 31:59
All right. I’m not sure what I mean. Brandon
— 32:00
We’ll, we’ll look into these things, who knows? But, but the thing is, is we, we get this warning saying no such table SQLite data, iCloud metadata. This is that secret table that we have in a database that has all the CK record information. And so you have to take one extra step in order to get your database to be able to talk to our database. Brandon
— 32:23
And that is you go over to the schema and when you prepare your database, there’s a DB attach met database, it’s throwing and we need that cloud kit identifier again. So put that in. Now let’s run. I wanna hide the Stephen
— 32:40
simulator one more time. I’ll just do this or, Brandon
— 32:42
yeah. Alright, there we go. So now we’ve got the counters separated, but let’s add some headers to these sections. Brandon
— 32:56
So this will be our local counters. This will be our shared counters. Brandon
— 33:10
All right. So there it is. So now we were just able to join our table to this extra database, hanging out with all the information and be able to figure out what is shared was not shared, but we can even do better. I’ll do one last thing and then I’ll, I’ll give the stage to Stephen. What if we wanted to, oops. Brandon
— 33:29
further show. The name of the participants in this row right here. Alright, so I want access to the actual shared data in that row. So let’s design a little data type that represents all the data the row wants. It wants a counter, and then it also wants a share if it’s a available. All right. And then further, we mark this as a selection. Brandon
— 33:54
This allows us to, make a query and then select into this custom data type. And the SL light, the way everything gets hooked up underneath the hood is SQLite will decode into this type, but of course, SQLite can’t decode into a CKShare . This is a data type that SQLite, knows nothing about. And so that’s why you then have to further annotate it with As, and we’ve got a CKShare , data representation. Brandon
— 34:19
That we can use. And now SQLite will under, or our library will understand how to decode the raw SQLite binary data into this CKShare . And so now what we can do is we can just select into this row, we construct the row columns with the counter, which is dollar sign zero, and the share, which is dollar sign one share. Brandon
— 34:44
And we use that in both places. Oops. We use that in both places. And now we can even drop this type in. Actually, we could have dropped this before we dropped this type. It can infer it from all this information. And so now we’ve got our local counters, our shared counters, and there is this little bit of optional shared state hanging out. Brandon
— 35:03
And so let’s just update. So now this is a row and the row has a counter. this is a row that has a counter. All right, let’s see. This is a row that has a counter. Then this is a row that has a counter. Oops. And I believe that should hopefully compile. It doesn’t because, oh yeah. It’s not identifiable. We can make it identifiable easily, but also there’s a counter sitting inside the counter is identifiable. Brandon
— 35:35
So let’s just slap that on. Alright. It compiles. But all we’ve done is just shuffle data around. What we really wanna do is pass along the row, inside this counter row, because then we could use the share. So do that. Now we’ve got a row here, and this is the counters. counter list, view row. All right. I think I do a bunch more. Brandon
— 36:05
Row dot counter. Row counter. Alright. Bear with me a little bit longer. It’ll be worth it, I promise. Row do counter. All right. Let’s see. Does that compile? And now we’re finally in a position to show the participants. So I’ve got a V stack, I, I did this with a little bit of forethought to put it, wrap the whole thing in a VS stack because then underneath the H stack we can unwrap the share in the row and then we can show a text view where we’ve got that, share the shares, get participants. Brandon
— 36:38
The participants, we can map over them because participants have what is called, user identity in that is name components. And then we can format it. It is optional. So I guess maybe we should compact map it and then we join the whole thing with a comma. And I hope that that is it. I think that’s it. Brandon
— 37:02
So let’s run in the simulator and I would hope that it shows all the participants. There it is. So Michael Williams. Yeah. People may not know Michael’s my first name, but Michael Williams, Stephen sells are the collaborators on this. And of course there’s extra information available to us where we could, see who the owner of the share is, so that you could say shared from or shared with. Brandon
— 37:27
And then you can also remove yourself from the array of participants. ‘cause of course, you’re a participant, you’re seeing it here, like all the data is available to you. And I just think it’s pretty amazing. So, I hope people are excited about this ‘cause it really is amazing. I guess we’ll find out in 10 seconds what, what the chat thinks, but I’ll, I think I’ll flip back to our, that that’s the, my demo. Brandon
— 37:52
And so I’ll flip back to our talking heads and we can take a couple of questions. and so, so I’ve got. So I’ll, I’ll throw up some questions right now actually. Brandon
— 38:11
So here’s one. Brandon
— 38:17
From Kaya, this was from our Vimeo. we’ll, we’ll take YouTube chats and everything, but we had a bunch of Vimeo ones. So if I have a root table that has multiple leaf tables, is it possible to share the root table and selectively choose the leaf tables that are shared? And that is possible. And it’s what? Brandon
— 38:34
There was an extra argument in the sink engine, that I briefly mentioned called private tables, and that allows you to describe what tables should not be shared, when you’re sharing all the other tables. And here’s an example of that and was the, the main reason why we wanted this feature is, in a reminders app, which Stephen’s about to look at next. Brandon
— 38:55
In a Reminders app, you could share a reminders list with someone, but then also in the Reminders app, you’re allowed to drag and drop and reorder your reminders list. That’s data you, that you would not want synchronized to who you’re sharing the reminders list with that would allow you to change the order of their reminders from your device. Brandon
— 39:13
And so you can squirrel away that private data into a separate table and you’ll have to join them together whenever you need access to it. But that allows you to carve out a little area that of data that just does not get shared. It’s still synchronized amongst your devices. But it’s not shared and that’s, that’s important. Brandon
— 39:31
alright, so that was, that’s good. Worth Stephen
— 39:33
talking a bit about the limitations of schema design with shared records as well, since it’s gonna be slightly different than just synchronization. Synchronization has basically just the limitation view, UUID primary keys. Mm-hmm. But sharing has a, a few more. Brandon
— 39:50
Yeah. Brandon
— 39:51
Actually that kinda dovetails with, this question here. which there’s one additional, constraint on syncing, not related sharing, just syncing, which is you ha you have to turn off foreign key relationships, because it’s just not guaranteed that you’re gonna get a reminders list and then all of its reminders immediately after you may get all of the reminders and then suddenly a reminders list. Brandon
— 40:18
So it’s kind of a bummer that you have to disable form key relationships, but we have taken the extra step to look at your foreign key relationships and recreate the on delete and the on update action. So you can still say that one table references another table with on delete cascade, and we just do that for you rather than letting SQLite do it. Brandon
— 40:42
so that’s, that’s one good thing. And then going back to. When you get to sharing, there’s additional restrictions you have. You can’t just share any record no matter what. So, first of all, the, the only record you can share directly with someone is a root record, which means it’s got no form key relationships whatsoever. Brandon
— 40:59
You, you can’t, like, you can’t share say a reminder on its own because then that allows you to get into a very weird situation of, I send a reminder to you, Stephen, and then you move it to a different list that I don’t have. Should I suddenly get your list? Because you just moved it to a list. So it doesn’t make sense to share a reminder in the abstract, but it does make sense to share a reminder list because it has no other foreign key relationships pointing to a parent record. Brandon
— 41:27
So that’s one restriction. and then, and then further, and this kind of dovetails with, let’s see, another question, which is. And, Stephen
— 41:39
and just to kind of tie that one question up mm-hmm. With the, the foreign keys one, problem with it is the kind of enforcement of it, like turning it on. And did you cover that? Brandon
— 41:51
I, I did. Yeah, I think I did. But you say it again because I I was, you’re probably have better words than I I was monitoring Chad. So Yeah. I would say, yeah. Say it again because it’s, it’s good to know. Stephen
— 42:01
just the fact that the, the triggers that we introduced this week, are gonna enforce them a little more weekly. Brandon
— 42:08
Yeah. Yes. You Stephen
— 42:09
don’t Brandon
— 42:09
have Stephen
— 42:09
to worry about that. Brandon
— 42:10
Yeah. alright. So I, I’m having trouble finding, but, but essentially, there’s the added restriction on shared records that, we, we do share the association. So when you share a reminders list, we’ll share all the reminders along with it. But then the question gets a little bit more complicated when you think about what about tags that can be many to many associated from reminder to tag. Brandon
— 42:36
We can’t. Further go and share all those tags with the user. And in fact, even the Reminders app on Mac Os iPhone that Apple makes, it doesn’t even do that. You, you’ll find that if you create a reminders list, share it, create a reminder associated a bunch of tags, those do not sync to whoever you shared with. Brandon
— 42:55
And so the reason you can’t do that. Is because it’s kinda similar to the other thing I, I mentioned a moment ago with the root record. What are you supposed to do if someone comes and deletes those tags or assigns tags that you don’t know about? Like, are you really supposed to be getting access to that data from them when there’s not clearly this very clear parent child relationship? Brandon
— 43:15
It’s a mini to mini relationship. And so, and so our, our library analyzes all these relationships. It figures out what you’re allowed to share, what you’re not allowed to share that’ll prevent you from doing something nonsensical. And we’re gonna have a ton of documentation that describes how you can design your schema to make it more shareable. Brandon
— 43:33
Like if you do want tags to be shareable, you have to unfortunately turn that many to many relationship into a one, to many. And then you just have to deal with the fact that you may have multiple tags out there with the same name and you’ll have to coalesce and do extra work querying to, to deal with that. Brandon
— 43:49
But that is the only way to allow something like that. Okay, here’s a good one. And this actually came up in two or three, questions, which was, someone asking if we’ve ever heard of Fort by, drew McCormack and, and you know, how does it fit into all this? And, and so this goes into something I guess we haven’t talked about, and this is probably the majority of questions we have, is just how do we deal with conflict resolution? Brandon
— 44:23
And we at this moment are doing the most basic last edited record wins. That’s just, that is the simplest way to do things. And that’s what we’re starting with. We, we do think it’ll only require a little bit more work to at least do it on a per column basis. And so, you know, we’re open to doing that and we hope to do that. Brandon
— 44:43
Well, it’ll be last edited column wins. And that way you could, if 1% edits one column, another percent adds another column. Those were merged just fine. When it gets beyond that, when you’re, when you talk about the idea of like what this library here does, forked of like forking records, making edits in parallel and then merging them together, we are not currently thinking about handling that. Brandon
— 45:08
we are, it, it is just that is a, a bigger, a bigger thing to consider. And so we don’t wanna hold up all of these tools as we try to find the perfect solution to that. And so what we would hope, ideally is that we could allow people to tap into our conflict resolution mechanism and do whatever they want. Brandon
— 45:27
If they want to go wild with all that, you know, so be it. But we think the vast majority of people will probably not notice a per column conflict resolution. And so I think we’re just gonna stick with that. Stephen
— 45:39
Yep. Yeah, I think for individual use and synchronization, even the, you know, per row version that we have right now is gonna suffice for most folks. Stephen
— 45:50
‘cause you’re not gonna be editing on multiple devices at the same time. Yep. I think with sharing we do want the, the column based solution though. Brandon
— 45:57
Yep. Justine, if there’s one more, I think there’s a lot of duplicates in these questions, so, so I think we’ve kind of gotten pretty broad coverage so far. Brandon
— 46:12
So we could take a look at the reminders app that you’re gonna demo. yeah, Advanced CloudKit queries Stephen
— 46:20
yeah. I’m ready to take over. Yeah, you’re in. Okay. All right. So this reminders demo is something that we shipped, I think in the very first version of SharingGRDB. if, if not, it was not too far along, but we have updated it and outfit it with cloud kit sync and sharing, and it didn’t take that much work to do. Stephen
— 46:45
we pre-ID a, a lot of the work like moving to UUIDs already on the main branch. So if you take a look at the repo right now, you’ll see basically this code, but with, a few changes. first off, we have configured the default sync engine, inside of the app entry point. And if you take a look on the, the phone that I’m sharing here, you can see that there’s two lists. Stephen
— 47:14
One, which is my personal list, and then there’s a point free list. one other change that we’ve made is that. if I drill in, we have added like a cover image to the top of the reminders list to make it have a little more flare. and one of the reasons that motivated this is because a feature of cloud kit is you can store large blobs of data in CK assets. Stephen
— 47:40
And we wanted to make that as easy to do and as transparent as possible. And what’s pretty amazing is we can take a look at the schema where we’ve introduced a, a new table for reminders list asset. And notably, there’s no CK asset mentioned at all here. what happens is our sync engine, whenever it encounters a data blob for a row, it, it automatically takes that columns data and just sends it into a CK asset. Stephen
— 48:12
And that cks is what gets synced across devices and across shares. And so we just wanted to make that as transparent as possible. And so that doesn’t mean CA assets will be used for anything, even small data blobs. you could work around that with maybe a custom representation, but, we figure making it as easy as possible to take advantage of cloud kits features was the way to go. Brandon
— 48:36
Yeah. And we had gotten multiple questions about that. so yeah, so just, yeah, it, it’s not really something we planned on adding, we kinda added last minute, but it was extremely easy. So it’s good to have, in fact, I’m gonna get it running on my device right now and I’m gonna, ‘cause you’re in, you’re in the shared list with us. Stephen
— 48:55
yeah, so I think if you, you wanna load it up and maybe we can see some of the synchronization and sharing in action. Brandon
— 49:04
Yeah. So, I’m gonna, I’m gonna change the poster image. I, let’s see. Brandon
— 49:18
So, Stephen
— 49:23
oh. Nope. Brandon
— 49:25
This is a little bit nerve wracking to do this live. Yeah. Stephen
— 49:28
Be careful with image. Shoulda Brandon
— 49:30
had. Yeah, I know. I should have, should have had an image ready to go. But yeah. I’m gonna throw on this, this image with our hair was a little bit longer. Oh boy. That’s, that’s a good one. All right. So, and then I’m also, yeah. Brandon
— 49:46
So I’m gonna hit save and that image will upload and a couple of moments later it will. I’ll update if you’ve seen it yet. Stephen
— 49:56
Yep. There it is. Brandon
— 49:58
Okay. And then I’ll add a reminder to say, edit. Well, I won’t tell you what it is, and I’ll, All right, so in a moment you should get something. Lemme know what it is. Stephen
— 50:16
I think you put to edit the episode video and it’s flagged. Brandon
— 50:20
Yep, yep. And let’s see. Some of the Chad’s asking, we shared the reminders list between us two, and That’s correct. What, we’ve got one reminders list that is shared between me and Stephen right now. So I’m making edits and it’s showing up on his phone. Stephen
— 50:32
You can see we have the participant listed right by the list. Brandon
— 50:36
Yeah. if you wanna come through Stephen
— 50:39
something and Brandon
— 50:41
yeah. So I’ll, yeah, I, I did finish editing the episode, so I’ll complete that. Stephen
— 50:48
All right. And made it nicely down. And yeah, I mean, it all works pretty quickly and it, it all is pretty magical and there’s really not that much that has changed in this app. Stephen
— 51:00
There’s just kinda a new share button, which you can see at the top, and that just uses the same infrastructure that Brandon just demoed with the cloud kit demo. yeah, let’s add a new feature. ‘cause I think that’d be fun, because this is a more, oh, wait, wait. Brandon
— 51:17
We’re we’re, this is actually kind of funny. Brandon
— 51:19
We’re, we’re getting, we’re getting dared to do something where we both delete the same one at the same time, and I think that’ll work just fine. So, but let’s do it. Let’s both delete, send weekly emails at the same time when you are on the count of three. 1, 2, 3. Stephen
— 51:42
Nothing’s coming back. Nothing’s changing, so, okay. Brandon
— 51:45
Yep. On mine it’s still gone, so we’re looking good. Stephen
— 51:49
All right. So yeah, let’s add in a new feature. It’s gonna overlap a little bit with what you were doing. Because I wanna get access to that shared data and kind of render a bit more on this screen. Stephen
— 52:03
‘cause at the top here we have all these cards for today scheduled, all flagged and completed. And I think it’d be nice to have just a centralized location to see all of my shared reminders. And so the way that we can do that is we have this detailed type in num that lists all of the kind of drill down categories that we have in the app. Stephen
— 52:23
And so I’m just gonna add in a new case for shared and I’m gonna build it so we can find all of our switches that need to be updated. All right. First we have the reminders, query that kind of powers, each detailed view. And I’m gonna start by just adding in a shared case and I’m gonna stub it out to true just to get things building. Stephen
— 52:47
Then for the id, I’m just going to follow suit with what’s there. Same for the navigation title. Stephen
— 53:00
And then for the color, Brandon
— 53:03
I Stephen
— 53:03
think pink would look nice. Stephen
— 53:12
I think we will be in building order, but of course there’s no changes. So let’s update the ui. I’m gonna go to the reminders list because that is where we are showing all these grid cells for today, it’s et cetera. And I’m gonna add right next to completed, shared, and we will do the, what was it, box or square and arrow up and let’s fill this one in. Stephen
— 53:46
And let’s just build things and see if things are looking good. Stephen
— 54:00
Alright, there it is. there’s no count and we need to do a bit more work to get the count in there, but I think the first thing I wanna do is update it. So when I drill down into the shared, it only shows shared things. Right now it’s reusing the completed actually. And so let’s update this to be shared and shared. Stephen
— 54:22
Just had that true back in the query right here. And so we want to start filling in more information here. Because this app already is showing the participants, that means that we have already attached to the MET database. So that means I already have access to querying against the sync metadata. And so what we can do is we could create a subquery to it and kind of figure out whether or not this reminder, or rather its reminder list is in, thes metadata with the share not being nil. Stephen
— 55:08
And so we can just say sync metadata where its record primary key is equal to the reminders ID and the share is not nil. And then we can use the exists keyword, to check that subquery. And let’s see. Stephen
— 55:44
All right, it is building, so let’s run it and see what happens. All right. no count yet, but if I drill down into shared, we are seeing nothing. And why would that be Stephen
— 56:05
the record? Primary key. Oh, okay. I think we also need to check the record type, right? Yeah. In fact, this is wrong. This should be the reminders reminder list. Id, in fact. Yeah. And this is a gotcha with the, the current, Implementation that we have where shares in cloud kit and in the sync metadata are associated with that root record type. Stephen
— 56:37
And so a little bit more work needs to be done, to find the share at the moment. But we, we do wanna make writing queries, a bit easier and with fewer gotchas. But I think because this is gonna be unique, we don’t even need to check the, the list as the record type. Stephen
— 57:02
Oh, and this is reminders list id. Brandon
— 57:05
Yeah. So while you, while you deal with complicated query. Yeah. I’ll just, I’ll just say that we, we understand this is complicated and kind of hard to wrap, you know, the mind around, we’ll have a lot of documentation to describe how one queries the sync metadata and stuff like that. Brandon
— 57:22
And we hope to have more and more helpers. I. showing, you know, making this like, hopefully like a one-liner or something, but at least it’s all possible. Stephen
— 57:30
Yeah. But with the gotcha side, it is now implemented and we can see that it’s the same that you’ve shared with me down here. And if I were to take a look at the completed it brings, it completed in and notably it’s filtered out the get groceries personal reminder that I have. Stephen
— 57:48
And so no worry, about that kinda leaking in. and I think it was pretty easy to do. We could just reach out to this table at any time and write queries against it. We, you just need to know exactly how the metadata is formatted and, and we’ll make it a bit easier as well. And, and we’re gonna have lots of documentation, all of this. Stephen
— 58:10
but let’s get the, the count in there and the count is gonna show the complication that we just experienced a bit more. because I wanna count all the reminders that appear in shared lists. And so let’s go up to the reminders list view. ‘cause we have these stats that we’re selecting with all the counts. Stephen
— 58:33
And I’m gonna update it with a shared count Stephen
— 58:43
that will require me to update this with a new shared count query. Alright? And the way that I am going to do this is I am going to, again, reach directly out to the sync metadata. I think it’s gonna be a bit gnarly, but it’ll be easier to go through this and do a count rather than try to join on, the reminders table or the reminders list table to, to make this query. Stephen
— 59:15
Okay. And so we want to do a count where the record type it is equal to, and the record type is just gonna be the table name. And so we can reach out to the reminder and grab its table name. And then further we need to check the parent record type. And all of the foreign key relationships that kind of form that tree are, are captured in the sync metadata so you can query right against them. Stephen
— 59:50
And so if there’s a parent record, we do that linking as well. And this is optional, which means we are going to need to, unwrap it in order to work with it in a type safe way. And there is a map operation that we added, like an optional map. that works with query expressions. And so if we open this up, dollar zero is now a non-optional parent record type, and we can just check is that parent record type or parent record name, Stephen
— 1:00:24
which is gonna be the id. And so is that in? And then we’re gonna do one more nested subquery just to, to get this all working, where we will take the sync metadata and we will filter it where the record type is equal to the reminders. List table name. And then further, Stephen
— 1:00:53
we will check to see that the share is not nil. And some of this we could even maybe write helpers forward. I’m, I’m seeing some repetition from earlier queries. And then we are checking an in, so we want to check the ID and so we can do a select on the record name. And I believe that will do. And finally, this is an optional map, so this is going to return an optional bullion. Stephen
— 1:01:23
And so we are going to want to coalesce to false if there is no parent record name. Brandon
— 1:01:30
And so, and of course this is a, a, a wild query. Yeah. But you know, it’s possible. We, we, we hope to come up with the tools that would make this nice and concise. But I mean, also, even if we don’t, it, it is possible. The point is that we’re giving all the tools available to people to query the cloud kit sync metadata whenever they need. Stephen
— 1:01:50
This is also just if you want to stay in the most type safe like swifty way possible, you could always write even just parts of these subqueries using the SQL macro and that will allow you to just spell it out as a string with some extra bells and whistles. But we did want to show kind of the power that you have at your fingertips, even though it does seem like a lot, but I believe we are in building orders. Stephen
— 1:02:16
So let’s hook this shared count up to the view. Stephen
— 1:02:24
And we have our model, I believe. Yep. It has its stats and that includes the shared count. So let’s kick off a build Stephen
— 1:02:39
and hope that I wrote that query correctly. Yeah. Got a lot of faith in you. Stephen
— 1:02:47
All right. three. And that is true. If we want, we could further filter out the completed. I think that would probably be a good idea. ‘cause I think we filter out the completed with all the others. And so, oops, let’s go back to that query. Stephen
— 1:03:07
And we would need to do a join to do that. Should we risk it? Or maybe just let things go and capture it as a to do? Brandon
— 1:03:17
Let’s let, let’s let things go. Yeah. Yeah. Let’s capture that as a to-do. and so, but let’s go back to the home screen ‘cause I’m gonna create a reminder for us. All right. And so what I would hope is, let’s see, what, what number is it for you right now? Brandon
— 1:03:33
It’s currently Stephen
— 1:03:34
three. Brandon
— 1:03:35
Okay. And then I’m gonna further flag it and I’m gonna give it a due date. So when this one reminder synchronizes to your device, because we’ve got the shared reminders list, you should see your scheduled count go up by one, your flag count go up by one, and the shared count go up by one. Brandon
— 1:03:51
All right. So I’m gonna hit save a moment later. Stephen
— 1:03:57
Yep. 2 0 3 1 to 3 1 4. We have a new for today and for all. Brandon
— 1:04:02
Yeah. Yeah. All right. So it, it just shows like you, these queries are always observing the database and they’re always updating live. And you, you don’t, you just really don’t have to think anymore about setting up observations, getting things wrong. Brandon
— 1:04:18
It just all just is kinda working. Even when it comes to sharing and all that, we can even do something really fun. Go, go into your search and search for episode and I’m gonna create one. All right, you in there? Stephen
— 1:04:34
I am. Yep. Brandon
— 1:04:36
All right. So I’m gonna make this a high priority. I’m gonna hit save, and even your search right now is listening for our shared reminders list. And so once that synchronizes, it should show up and. Stephen
— 1:04:52
Yep. Brandon
— 1:04:52
Yeah. And a high priority. Stephen
— 1:04:55
It is very high priority. Yeah. Brandon
— 1:04:57
Yeah. So everything is just all connected and everything. Brandon
— 1:05:00
It’s, it’s all listening, all the shares, all the SQLite database and, and then also, an important, I, I feel like we’re showing some really amazing things, but we’re maybe not. Describing it, it’s still even more amazing than I think we’re making it seem right now, because the thing is, is we did not change any of our app code. Brandon
— 1:05:16
We’re still using a regular SQLite, database connection. We’re writing to it, we’re reading from it, we’re setting up observations. It’s all just working. We don’t have to bend ourselves and weird contortions in order to write in a specific way or set up all these things. We set up the syn engine and it just rolls with it. Brandon
— 1:05:35
and then we’ve also gotten a lot of chat about the relationships and the limitations of sharing and stuff like that. And I, I think maybe we didn’t fully describe the situation, so let’s try to do it from scratch real quick so that we can really make it clear. Alright. So first, before talking about sharing, when it comes to synchronization. Brandon
— 1:05:54
Everything just syncs. It doesn’t matter if you’ve got many to many relationships, one to minis, all those should sync just fine. The only limitations are that we need UUID primary keys, and then also you have to turn off foreign key constraints in your SQLite database connection. That doesn’t mean you don’t use foreign keys. Brandon
— 1:06:14
In fact, we, if you go actually go to the schema real quick and show that we’re still using foreign keys all over the place. the only thing we have to do is turn off the constraint aspect because foreign keys, there’s two aspects to it. There is the constraint aspect where SQLite will just not allow you to point a record to a, a non-existent record. Brandon
— 1:06:34
so that we cannot allow. But then there’s all this other stuff about foreign keys that we can allow, like the on lead cascade, we do want that. And then further, we want the ability to just have tables reference each other because our library analyzes your schema to figure out how to set up those relationships. Brandon
— 1:06:53
So we are using foreign keys. We’re just not using foreign key constraints. All right? And our library will look at all of these foreign keys and it will. Implement the on delete cascades and on update cascades itself. Because sql, because we had to tell SQLite, Hey, don’t do the constraints. It also doesn’t do the cascading. Brandon
— 1:07:15
And so we gotta go in and do that ourselves and we do do it. Alright. So, so that’s one aspect that’s just synchronization. Then comes the sharing and sharing, works by, you can only share root records. And then if you’ve got other records that refer to that root record, as long as it’s got only one single foreign key, it will also be shared. Brandon
— 1:07:40
So a reminders list, having reminders that gets shared. the cover image actually, can you go to the cover image, or the reminders asset table? and the schema because, so the, the schema and the schema, the type or, we could do either whichever one. And so because the reminders asset only has one single foreign key pointing to a reminders list, it gets shared. Brandon
— 1:08:04
The only thing in this app that doesn’t get shared are the reminder tags. And the tags, because that’s a many, many relationship that that does not work. A reminder tag has two parents. It’s got a reminder parent and a tag parent. And so that can’t be shared. And that’s also just how even Apple handles things. Brandon
— 1:08:23
so, so yeah, we’ll have documentation about all this, but we, we wanna kind of show that, you know, this, there are limitations, but they’re actually reasonable limitations. They are things that you just would not want. You know, we shouldn’t even be trying to make it so that we could do this because it, it would just lead to nonsensical things. Stephen
— 1:08:41
And, and Sean, Robert, thought that we said that many, many relationships are supportive, but they, they’re not by default. you could emulate them in, in certain ways by kind of de normalizing, as Brandon mentioned earlier. But yeah, out of the box, that’s gonna kind of cut things off and, and that can be a good thing if you don’t want tags to be a shared thing. Stephen
— 1:09:05
that’s just an automatic way that you get that behavior and that is what the reminders app has, Brandon
— 1:09:10
officially. Yeah. And it, and it gets a little confusing. ‘cause many to many is supported for synchronizing when you’re just talking about one user’s devices. Right, right. But then when it comes to sharing that, the mini to many does not work, and you would have no choice but to de normalize a mini to mini table. Brandon
— 1:09:25
And that is a totally valid way to go about things too, if you want. Stephen
— 1:09:29
Right. So I guess a good thing to highlight and the amazingness that, that you want to kind of emphasize, emphasizes that if, if you don’t need sharing, you just want cloud kit sync, there’s really not much work you have to do other than get you your IDs in, into your database and also turn off foreign keys and let our library do things like the cascading. Stephen
— 1:09:49
It’s really just like you add one line of code and you do migration. If you weren’t already doing your primary keys as UUID. Brandon
— 1:09:57
Yep. Stephen
— 1:09:58
And then Brandon
— 1:09:59
sharing Stephen
— 1:09:59
it becomes just a little more complicated. But even that is not that complicated. It just makes you think a bit more as you design your database to make sure that the foreign key relationships form a tree that gets shared. Stephen
— 1:10:12
And then anytime you go into a many to many territory, well that will get synchronized just fine for your user. if you want it to be shared, you need to do some extra work. Brandon
— 1:10:21
Yep. here’s a good one from the chat about, I’m still worried how to manage potentially many users with different versions of the app schema, trying to share different records with different people. Brandon
— 1:10:32
And we’re gonna have a lot of documentation about this. And essentially the overall. Strategy here is your, schema. Migrations have to just be the most basic forward moving backwards compatible migrations possible. You cannot drop columns, you can’t rename columns, you can’t rename tables. Like all that stuff is even just, you know, it’s, it’s nice to, clean up the schema. Brandon
— 1:11:01
You know, every once in a while you may think as a developer, but as soon as you’ve taken that schema and distributed on thousands of devices where each one can have a different version of the schema, you’re just no longer allowed to do those developer experience, experie dev developer experience improvements anymore. Brandon
— 1:11:17
so, so yeah, we’ll have documentation on this, but as long as you, you do design your sche in this way, it is actually completely possible for, like, I could be running a new version of the reminders list where our, our, our reminders app or our reminders list has a. Like all types of new fields and Stephen’s running on an old one, and I can make edits to those fields, send those records to him, and his device will just ignore them. Brandon
— 1:11:39
He’ll edit all the other fields. Those records will come back to me with all of my new fields still intact. And so as long as you do approach your schema as just only incrementally adding to it continually, it’ll all just work. it does mean adding Stephen
— 1:11:57
optionality that you would prefer not to have, but that just kind of comes with the territory. Stephen
— 1:12:02
but the very first like create table statement, you are allowed to do not all and have defaults that are expressions that evaluate kind of as each row gets inserted. Brandon
— 1:12:15
Yep. You know, how about I’ll, I’ll start, streaming again and we’ll, we’ll go to the talking heads and we’ll do Q&A to, to kind of finish out the live stream. Q&A Brandon
— 1:12:24
I. Yep. And then, yeah, so there’s, so someone asking, so the new stuff just doesn’t show up. Yeah, exactly. If, if I’m running a new version of the app and I’ve got all these new features and I tweak them, Stephen just isn’t gonna get seeing of that data until he updates. But all the data is still there. alright. Brandon
— 1:12:44
And then let, let’s see. We got, let’s throw in some questions. I think, Stephen, you, I, I’ll throw some at you. and Stephen
— 1:12:55
Noma in chat says, force update will always save you. And I think that’s a good point. the earlier you introduced the force update kind of flag to your application, the more flexibility you’ll have in the future, when you release new versions. Stephen
— 1:13:10
Mm-hmm. Brandon
— 1:13:14
let’s see. So I think, so just for people who may be, Came in late. There’s some of these that we’ve already answered, but I’ll just throw ‘em up really quickly. Stephen was able to show that, you know, sometimes you need to sync files on disc, like images and things like that. I. what’s your take here? Brandon
— 1:13:33
As we showed, if you add a data blob to a column, we automatically package it up into CK Asset and send it off so you can you get it? Yeah. It’s all Stephen
— 1:13:43
transparent. You don’t have to worry about the URLs or anything. it’s just going to take any data blob column put into a CK asset, and then when that gets synchronized to another device, it plops it into the data blob column. Brandon
— 1:13:56
Yeah. So, yeah. So if anyone out there wanted to take these tools for a spin and kinda explore it, imagine making a Voice Memos app where you attach the actual recording of the audio to your table as a data blob. That would be instantly synced to every device. You don’t even have to think about it. now we will have documentation to describe some of the caveats. Brandon
— 1:14:17
it is not, probably not a good idea to take. A core important large, table with lots of user data fields and slap in a large data blob into it that will slow down querying you the all the rules of SQLite still apply here. We’re not doing any kind of magic to work around the rules of SQLite. Brandon
— 1:14:34
That is our, kind of our fundamental limits of physics here. We got SQLite at the very top end. And so what you do is you make a separate table and put your data blob in that, and that way you can choose not to join against that table and not incur the cost of trying to scan that table. So that’s one thing to do. Brandon
— 1:14:54
okay, let’s go, let’s get another one up. Stephen
— 1:14:59
I think the main issue with that is you’re gonna be querying models directly a lot of the time and you would need to select to omit that data way more places. And so having it in a separate table just avoids that extra work caveat. Brandon
— 1:15:11
Yep. here’s one from the Vimeo. Brandon
— 1:15:15
I assume you’ll elaborate on the OR so, is. Is, is it a one-time copy or will then any changes they make also sync with your copy? Ideally, I’d like both possibilities. and I think, I mean, as we’ve shown, it’s, it’s the latter. Any changes made with the shared reminder or played back to us. But Cloud Kit does have the option to share something with someone in a read only state and, and then of course that that is enforced by Cloud kit and we will expose those options. Brandon
— 1:15:47
Like you can always grab the CKShare and see, do I have right access and if I don’t, don’t even allow the person to, to make edits. So, so we feel like both of those are essentially already supported. Stephen
— 1:16:01
Yeah. Brandon
— 1:16:03
all right. There was a good, we may even be able Stephen
— 1:16:05
to. Kind of error out if you attempt to make those rights. Stephen
— 1:16:09
I, I don’t think we’ve gone that far yet, but it is something that we’d like to do. Brandon
— 1:16:13
Yeah. Yeah. We’ve got, we’ve got a, a to-do list, the length of my arm of things that we need to look into, and that’s, that’s one of ‘em. here’s one. Will it be possible to use these sinking features with other SQLite libraries? Brandon
— 1:16:29
so right now it is built into our, sharing JRDB library specifically, and we kind of have hopes that we could make it a little bit more general purpose, but I dunno, we’re already dealing with a lot of complex things right now, so it’s, it’s not exactly top of our priority to make this a fully general SQLite synchronization system. Brandon
— 1:16:52
So, we’ll, we’ll see where that goes. Stephen
— 1:16:58
let’s Brandon
— 1:16:58
see. And. Stephen
— 1:17:01
We could do another question in chat. There’s a question about can the syn engine start later? like if somebody enables sync as a toggle on the setting screen, and we, we haven’t explored that ourselves. Even apple’s code samples do their best to start their syn engines as early as possible in the lifecycle of the application. Stephen
— 1:17:21
that said, you can invoke that, you know, sync engine, initializer wherever you want. And so, you could give it a try and let us know. Brandon
— 1:17:30
Yeah, I I wouldn’t say we’ve built it with that use case in mind, so, you know, be aware. Brandon
— 1:17:39
so then here, oh, I had one. Let’s see. let’s see. We’ve, I, yeah, Brandon
— 1:17:49
we’ve really answered a lot of these. Brandon
— 1:17:57
so I guess one thing. We could do. So just, I’ll throw in a couple that might be just really easy to answer because it’s just, there’s, it’s a lot of nos to these, but what’s the best practice to use SQL Cipher? Unfortunately, we, we just don’t have any recommendation there, I think. Yeah. sorry about that. Brandon
— 1:18:21
here’s another one of, whether we are, have plans to look into RDTs, like kinda as we mentioned before, we don’t, we plan on approaching conflict resolution in the simplest way possible. Most people would probably be fine with row based, newest value wins, but we will try to get column based newest value wins and anything beyond that, we would rather. Brandon
— 1:18:50
Open up the APIs to allow people to do whatever they want rather than us specifically do that. Stephen
— 1:18:57
yeah. And with the SQL Cipher, that is something that exists outside of us, and it’s A-G-R-D-B kind of extension. so if you can get it to work with GRDB, you should be able to get it to work, but we don’t think it’ll have any impact on, on our tools. Brandon
— 1:19:12
Mm-hmm. Brandon
— 1:19:16
let’s see. So here’s a question about, oh, yeah, go ahead. Stephen
— 1:19:21
I was just gonna say, we could also look at the YouTube ’cause Brandon
— 1:19:26
there as well. Oh, I completely lost track of that. Oh boy. Oh man. Completely. Stephen
— 1:19:33
yeah, there’s a, there’s a, a wall of them. Brandon
— 1:19:35
Yeah. so Oh, oh, okay. Stephen
— 1:19:41
Could take it from the top. Brandon
— 1:19:42
Yeah, let’s do it. Stephen
— 1:19:44
Do you want me to add one? Brandon
— 1:19:46
Yeah, go for it. Yeah. Stephen
— 1:19:52
All right. Yeah. Art asked, what’s the best practice to use SharingGRDB with TCA And will there be examples or case studies? sharing and SharingGRDB kind of work, you know, equally well in TCA and vanilla, you kind of just would use it however you use your existing shared property wrappers, so you can drop a fetch, one fetch all directly inside of a reducer and get access to it. Stephen
— 1:20:20
you can do it from an effect and, and so on. I think we would like to expand some of these demos. we do have like a sync up TCA that we should probably update to use, SharingGRDB. I think even Apple recently updated their scrum dinger to use SwiftData, so people wanna check that out. I. but yeah, we’ll get more demos and examples out for sure. Brandon
— 1:20:44
Yep. I’m just kinda scanning through for some, some quick easy wins here. so let’s see if I select this question. So how would you approach syncing the order of the counters and cloud kit demo? And this kind of dovetails with some of the stuff we said with reminders. So, the, I mean, the easiest way would to be add a position field to the counter and then sort by the position and allow drag and drop to update all the positions. Brandon
— 1:21:13
And that would sync across all your devices just fine. Everything’s get more complicated when you allow yourself to then share those counters. ‘cause you wouldn’t want the ordering of counters on your device to somehow affect the counters you shared with other people. And so then you might extract out that little position into a private table that is synchronized but not shared. Brandon
— 1:21:33
And our tools support all of that. Brandon
— 1:21:46
let’s see. Stephen
— 1:21:47
Okay, what else do we got? Brandon
— 1:21:54
So, Brandon
— 1:21:58
all right, so there, there were a couple of questions in the chat and then I see one, let’s see. So I’ll, I’ll just throw this one up. And there, there was some questions in chat about this just in general of kind of, some people asked about just sharing the entire database and that doesn’t really fit into this, into this model that we’re describing of just truly sharing every single record. Brandon
— 1:22:24
cloud kit does support something called a, a public database, but, our tools are only using the private database and the shared database, so I. There are even limitations. I believe Syn Stephen
— 1:22:36
Engine doesn’t even support public databases. Yeah. Sync Engine doesn’t Brandon
— 1:22:40
support public databases. And so, and so the one, if you truly had this use case of needing to share absolutely everything, the only thing that comes to mind for me is that you would create a single 10 record, and have all of your root tables have a foreign key pointing to that. Brandon
— 1:23:00
And that means if you ever sh share that root record with someone, it would share all of the root tables along with it. I just, I, I think, you know, what we’re looking for is maybe some discussions about the really concrete examples of how people expect to use this so that we could fully understand, what people want out of these tools. Brandon
— 1:23:21
but that is kind of the first go at, at that. Yep. Stephen
— 1:23:33
Some of these questions we’ve already answered. Stephen
— 1:23:41
and some of them we would have to do research to to answer. does any stand out that is worth bringing up? Or Brandon
— 1:23:55
one thing we could do is talk about our release plan. I’m sure people wanna know about that. Stephen
— 1:24:01
Oh yeah. Yeah. I suppose they do. Yeah, they brought it up in chat earlier. Brandon
— 1:24:05
Yeah. So let’s talk about the release plan. So we, we, we’re gonna do things a little bit differently this time. Brandon
— 1:24:14
we are gonna release a private alpha of these tools because we do not think they’re ready to be used in production right now. We really don’t want people to, ‘cause we, I. We wanna get more feedback and kind of work on the tools a little bit more. So we’re gonna do a private alpha and we hope to release it to tomorrow or Friday. Brandon
— 1:24:32
And the private aspect of this is we are only going to allow people who are subscribers to point free to get access. So y’all can email us and we will have a blog post and open up, like kind of an email line, or, and so you’ll email us, give us your GitHub, and we’ve got a private SharingGRDB. Brandon
— 1:24:51
iCloud repo we’re running off of. And so what we would like is then if y’all took this library and gave us feedback on its current state made toy apps, please do not release an app or anything using these tools. That would be a very bad idea. But make little toy apps or, or explore our case studies. Brandon
— 1:25:10
Maybe someone can make that voice, memo app or something. And so, and then start discussions with a lot of these things that are being brought up in the Q&A and let’s just talk about it. And then in a week or two, we’ll make a public beta and then that will be at the point where I. You know, everyone can start using it. Brandon
— 1:25:29
Not necessarily in production. It still will be beta, but I mean, if you wanna go for it, you know, be my guest. But, but that is the plan. We, we want a small group of people, people that we have already a direct line of communication with in our community. we’ll have the Slack open for discussions. Brandon
— 1:25:47
The GitHub discussions will be open, and so that will be the plan. Stephen
— 1:25:53
Yep. And I think people can throw it at more real world apps that they have, but just with that caveat that do not release that app. You probably even want to carve out a kind of. CKContainer just for testing. And you shouldn’t expect to be able to use that same container for the the released app. Brandon
— 1:26:12
Yes. Stephen
— 1:26:13
Once these tools are, are more polished, Brandon
— 1:26:15
yeah. We’ve had to delete container, recreate container a few times ‘cause of bad data getting into them while testing stuff. So you should expect to have to do the same. So I, I would definitely create a temporary container. and then there’s a question here in the chat about, I haven’t worked with CoreData, but is there anything that CoreData still has over what we’re showing here that would be preferred in new project? Brandon
— 1:26:39
I mean, of course I’m biased, but the, the main thing I think CoreData has that we don’t provide tools for, but it doesn’t mean these tools cannot be built and maintained is CoreData has this concept of a model context, this idea, it’s like. A little area of scratch objects that you’re allowed to make edits to and do things. Brandon
— 1:27:00
And nothing is being saved to the database until it either auto saves at some non-deterministic moment later or until you know, you hit save on the context that takes all the objects that have, that have changes and saves them. all of that is 100% possible with SQLite. They even have a dedicated article about an und undo redo manager that would show you the beginnings of how to even get into those ideas. Brandon
— 1:27:24
But that is one thing that I think a lot of people maybe like with CoreData, whereas, you know, with a more standard SQLite setup, you just read from the database right from to the database and boom, it’s done. So that’s one. yeah. Stephen
— 1:27:41
I think it’s just different tools and different comfort levels. you know, some people are gonna be more comfortable just editing an object graph and the changes kind of magically applying. Stephen
— 1:27:52
I think you and I prefer just the precision and power and guardrails that SQL provides. Brandon
— 1:27:59
Mm-hmm. Brandon
— 1:28:04
Okay. Stephen
— 1:28:09
Anything else to mention? Yeah, I’m gonna throw about that. Brandon
— 1:28:13
There’s a question here, and this also even kind of dovetailed with a previous question. Does this break corely if someone logs into different iCloud identity? So there are events that the sync engine gets when it detects a iCloud user, logs out, logs in or is temporarily logged out. Brandon
— 1:28:30
And so we. Hopefully are listening to those events correctly and then do the right thing. And so when we detect a log out, what that should do is delete all the local data potentially, or, or maybe this is a, a configurable thing. or, and then when someone like logs in, like, we probably shouldn’t keep that data around. Brandon
— 1:28:50
So there’s, there’s things we’ll be doing for it, but this would be, I’m not sure we even have all the logic implemented yet, but this would be something that’d be useful for, for people to test out. Stephen
— 1:29:00
Yeah, I believe we do the default behavior that Apple kind of advises or, or shows in its own sample code, which is to delete that data. Stephen
— 1:29:11
but yeah, I think if people have other use cases, they should reach out and talk to us. Brandon
— 1:29:16
here’s a good one. how about recreating something like CoreData’s faulting with sharing g shared db? So, so this is. An example of something that I, I feel like SQLite actually already does in a way by default. Brandon
— 1:29:29
And so in SQLite, it is just incredibly easy to select only the little bits of data you need, including associations and everything. And so, and then only when you need the full data do you need to actually fetch that data. So, so while it may not work as magically as getting a model where secretly behind the scenes, some of the fields have been populated and others have not, and then you touch a field that was faulted and it magically makes a database request and loads up all the data and you don’t even know that’s happening behind the scenes. Brandon
— 1:30:03
While it doesn’t work like that, and I feel like that’s actually not a great way to, to have these things work, it, it is still possible to get the essence of faulting, which is load the minimal data and then load the rest of the data later. That actually is quite easy and, and pretty straightforward with our tools. Brandon
— 1:30:21
So, so we feel Okay. Yeah. Stephen
— 1:30:24
There’s a, a chat in, from Vitali asking, is it possible to fetch data then perform some business logic and then show it on the ui? And Absolutely. Most of what we’ve shown is using property wrappers that just kind of magically show the most recent data, but you still have full access to the database and you can perform queries however, and whenever you want. Stephen
— 1:31:05
I’m not sure if you’re putting something else up now. Brandon
— 1:31:07
I was just scanning through to see if there’s anything that pops out. I mean, I think we’re getting, we’re winding down, but Yeah, people should ask. Any last minute questions? Stephen
— 1:31:22
there’s a question about SQLite plugins like SQLite vec, and that’s also kind of a more vanilla, concern because you can’t just install plugins into the SQLite that ships with iOS, et cetera. Stephen
— 1:31:36
And so I believe you would need to build your own SQL item, somehow embed it in your application for those kinds of things. Mm-hmm. It’s possible to write queries against those kinds of logic because we have the SQL macro and we have like a pretty flexible, query expression builder. Brandon
— 1:31:53
Mm-hmm. And then here’s a question which I’m not entirely, Certain for the answer, but just under the impression that observation is, oops. Less efficient when not using auto incrementing IDs. I, I’m not sure that’s true. I think where observation can be very, very efficient is by row IDs and row IDs can still be made available because that’s just a local concern. Brandon
— 1:32:21
And so then the question would be just the trade off in general of integer, primary key versus UUID. you know, I’m sure UUIDs are obviously more storage. and I’m sure they are slightly slower, although when they’re indexed, maybe not substantially slower. I think probably storage is the, the biggest difference. Brandon
— 1:32:41
But I also just think we don’t really have a choice. It’s, you know, we need a globally unique UUID. And so if you want these things distributed, you just gotta use a UUID. Yeah. So there’s a question here about, media asset syncing seems common besides data of labs. Any suggestions? and I, so this, this goes kind of more towards maybe a more general syncing framework that we’re, we’re not trying to say we’re providing, we, we really are focused on just a SQLite database syncing. Brandon
— 1:33:23
And that’s why we say if you throw a data blob in it, it’ll be synced. But if you’re wanting more just like files on disc to be synced and stuff like that, I think our tools are not necessarily gonna help with that unless you’re willing to bring those files into the SQLite database. So if you’re not willing to do that, then I think you would need to look for other tools. Brandon
— 1:33:52
so, okay, so this is a good one. can you elaborate on how s sync between devices with different local database schema version works? You mentioned even unrecognizable data, from Cloud Kitt is synced. Where does it get stored? Alright, so yeah, we could just talk a little bit how the sync engine works. Brandon
— 1:34:11
when we get a CK record from Cloud Kitt, we go through all, or we load up the corresponding row in our database, if it exists and we, or all right, let me back up. We get a CK record from Cloud Kit and we do an upsert on the database from that CK record. So if it is a reminders list with, you know, five fields, we will try to do an upsert. Brandon
— 1:34:39
Using the schema information we know locally to get data from those five fields. And if we’ve only got three fields, we only take three of the fields. and so that leaves the CK record fully intact. As far as Apple knows, you know, it’s a, it’s a record with five fields, even though one of the clients, one of the devices only knows about three fields. Brandon
— 1:35:00
And so then later when the app updates and knows about all five fields, it will fetch that data again. It’ll see all five fields and it’ll get the full set of data. And so it all should just work perfectly fine. As long as your schema migrations are very strict and do not do destructive things. You really, it all has to be forward movement of just adding things. Brandon
— 1:35:34
Okay. I mean, all right, so there’s one thing here about, UUIDv7 helps with indexing and it, that’s interesting because right now we are building these tools fully pinned to just UUID Foundation, UUID type. And so I don’t know if we’re gonna possibly reconsider that at some point or, or, you know, have it be a bring your own UUID, but you know, you know, it’s also gotta be a type of UUID that the database can also generate, although you, you can’t install a database function to do whatever you want. Brandon
— 1:36:08
But yeah, right now, UUI Ds or, kind of baked in to these tools, so this would be a good place for people to provide feedback if they don’t think that’s the right choice. Stephen
— 1:36:20
I do believe there are libraries out there or just code that you drop into your app that extends Foundation, UUID with additional initializers for different versions. Stephen
— 1:36:30
And so that would all work just fine. And I don’t even think we’re, we’re not. Ever responsible for doing the UUID generation ourselves in the library? That’s all coming from your own tables, Brandon
— 1:36:42
right? Yeah. So your, your default when you create your table, you’d wanna make sure to call out to some database function with UUIDv7. Brandon
— 1:36:51
Yep. all right. Let’s see. All right, so this one I’m not sure I understand. Is it possible to use your library property wrappers in managers, not in observable models, but managers located in models and how, how does observe work? I’m, I’m not sure I understand this, but nothing about our property wrappers needs to be installed in an observable model because it takes care of observation on its own, on the inside. Brandon
— 1:37:21
So, so you can. Put those property wrappers elsewhere and the mere act of accessing fields from it will cause the view to then observe those changes. I’m not sure if that’s that’s what’s asking, but that, that is how it works. let’s see. We’ve got something about the next big focus for the library. Brandon
— 1:37:46
you got, this Stephen
— 1:37:47
is the big focus at the moment. Yeah. We’re always open to discussion ideas on GitHub and, we’ve gotten some great ideas from the, the community already since the launch of the library and so keep ’em coming. But yeah, I think we got, you know, as Brandon said, a big old laundry list of things to complete. Stephen
— 1:38:07
And I’m sure that this is only gonna grow once we start this off alpha. Brandon
— 1:38:11
Yep. and I guess not related to the library, but our next series of episodes will be starting next week. And it’s not about synchronization, but it is about, triggers, which is some, a tool, a something we release to support triggers, earlier this week, and triggers form the foundation of how all these synchronization tools that we demoed work. Brandon
— 1:38:35
And so we’re gonna do a fun little side quest on just triggers in general because we think they’re amazing and we think they’re underused, in our community. there’s also a good question here of have you found any way to write tests that simulate different iCloud user sharing data? And we actually have made a lot of strides in this field. Brandon
— 1:38:53
We do have actually a decent amount of test coverage, even though CK engine is a, a black box. And of course we can’t test it directly. We are able to wiggle ourselves in to all the little areas of our, of our library code to see what happens when records are coming in, merging with existing records, or what happens when there’s nothing in the sync metadata table. Brandon
— 1:39:12
But we get a new record in all, all these different combinations and it’s given us a lot of confidence, in our code and, and our ability to just change code massively and hope that things just work correctly. So, so once you get access to the library, you’ll be able to see how we wrote all those tests and, and it’s using a lot of inline snapshot testing and it’s, fun stuff. Brandon
— 1:39:36
Okay. Stephen
— 1:39:40
There, there’s a question about people with multiple iCloud accounts, like work and personal and. We just have the, the same limitation that any application has, which is when you’re logged into cloud kit at the system settings level, it is, that is gonna be what’s accessed by cloud kit’s, APIs. Brandon
— 1:40:00
Yep. Brandon
— 1:40:01
Here’s a question, Brandon
— 1:40:04
about how, let’s see, how to describe a model of Shang R DB table using protocols. I think this is, I I can’t give concrete answer to this. I think we would need more details and maybe start a discussion about it. We personally don’t think there’s really much use in putting a protocol in front of just your table model. Brandon
— 1:40:22
It’s just a lightweight strut. I think kind, hopefully you could just let it be, but if there’s something more concrete, I think open up a discussion and, and we can all chat about it. Stephen
— 1:40:32
The table macro does apply the table protocol to destruct and so that might give you what you need already. But yeah, if you have a more concrete problem, please start a discussion. Brandon
— 1:40:50
Okay. I don’t know unless something comes in. I think we, I mean, we didn’t get to everything, but I think we answered things that kind of covered a lot. I, Brandon
— 1:41:07
let’s see. Brandon
— 1:41:15
there’s a question from Vimeo about, using a sqli database in app groups. That way you can share a database with, I guess this would be with things like widgets or something. I haven’t done a lot of widget stuff, but, there is a very popular blog post out there warning to never ever do this, that it is a, a recipe for disaster for doing deadlocks and, and a lot more stuff. Brandon
— 1:41:38
So, so I only wanna just, yeah. Make sure people know of the, the troubles of doing that. I don’t have a great solution for it. It’s not anything we’ve ever looked into ourselves. I think people just say, you just gotta cook up notification mechanisms to kind of communicate between these things. But yeah, I got, yeah, I got nothing concrete other than just probably do not do it and look up that blog post. Brandon
— 1:42:06
Oh, hey, here’s one. What do you think, Stephen? what was the most unexpected thing you’ve learned about cloud kit? Stephen
— 1:42:15
You want me to take this one? Brandon
— 1:42:16
yeah, you take it while I think about it. yeah, let’s see. I mean, oh, I feel like there’s been so much, but honestly we, we’ve really been in the trenches for so long. Brandon
— 1:42:32
It all feels like just normal stuff now. Stephen
— 1:42:36
yeah, I mean, it’s unexpected. Maybe kind of how many layers and versions of APIs are out there in the wild and kind of sifting through them to make sure that we’re implementing kind of the latest and greatest. Brandon
— 1:42:53
yeah, a lot of outdated docs, missing docs, but you know, I think we’re all used to that with Apple libraries. Brandon
— 1:42:59
There’s also. there’s a shadow world of async throwing versions of these CK operations, but it’s very hard to find them. So you’ll find docs that mention, gotta create a ck modify operation, configured a whole bunch of lines fired up with a callback closure, all these things. And then lo and behold, there’s a little async throwing function that does most of it, doesn’t always do all of it, but, you know, gives you like most of it, very difficult to find that kind of stuff. Brandon
— 1:43:27
And then in the next, I guess one of the surprising Stephen
— 1:43:29
things that we encountered with those operations is sometimes you can add the operation to the container. Sometimes you can add it to an operation queue, and sometimes if you add it to the wrong thing, it’ll throw a runtime warning Yep. Or an Brandon
— 1:43:42
error or crash and you just never really know. Brandon
— 1:43:44
Yep. Yeah. Lots of weird errors popping up. yeah, it’s a, it’s a tough one. We’ve been working on this now for probably a over, well over a month. and, and this is our first alpha preview of it, so, Brandon
— 1:43:59
yeah. Stephen
— 1:44:08
a question about any problems using it alongside non-shared GRDB at the same time. And I, I don’t believe there’s any issue with that. you showed that there’s kinda the private table stuff, which will exclude tables from sharing, and then also if you, if you mean sharing JRDB, you can use all the querying tools without the property wrappers throughout your application. Brandon
— 1:44:31
Yeah, yeah. You can use everything from JRDB, everything from sharing JRDB, yeah, it’s all, it’s all just there. oh, and that, I think I accidentally answered Jeff’s question about how long have we’ve been working on, I think it’s been about a month and a half, and then I Stephen
— 1:44:47
thought you got that shot. Brandon
— 1:44:48
Yeah, no, I, I, I was just saw it and then, vision OS support. Brandon
— 1:44:53
I mean, I think all these, I mean, it’s as supported as just. CK syn engine. And as long as CK syn engine is available, then all, all this is available. There’s nothing vision specific. and let’s see. Brandon
— 1:45:13
So there’s a question here. Let’s see. It’s, I can pin it. I have a TCA that uses client to abstract network or SQL access. Can I use the share macro and my sql, version of my clients and return the same domain models and points? you wouldn’t really use the property wrappers, like fetch all like in and inside just to return data. Brandon
— 1:45:36
You might as well just do a database, read, grab the data. but, but really I think. What we’ve shown in a lot of our demos is that there’s really no need to sep separate the idea of like an endpoint that fetches just this little piece of data endpoint that fetches this piece of data. It seems like a more universal way of approaching this is just allow executing queries and that gives you the full, that even allows you to do full test coverage, end to end of the user did something Aquarius constructed, sent to the database data decoded comes back and put in the ui. Brandon
— 1:46:10
You get everything. And so we would actually just recommend opening it up to allow your TCA app just to run the queries and then you can use fetch all and fetch and fetch one inside your observable state. and, and because SQL has such good support for in-memory databases, it makes it super easy to test. Brandon
— 1:46:27
Yeah. We think that’s the way to go. Stephen
— 1:46:30
Yeah. And we, we learned that lesson 0.3 still drives its database with an abstraction over sql and we, we can’t wait to swap that out for, you know, having direct SQL access. Brandon
— 1:46:42
Mm-hmm. Brandon
— 1:46:44
and so there’s a question about will this be a trait in SPM to not block other block other platforms? Brandon
— 1:46:49
everything is wrapped in a if can import cloud kit with availability version. So you should be able to drop this in an app. If you still support iOS 13, you won’t be able to use the sync engine. But sharing JRUB as a package, we’ll continue supporting all the platform. It’s always supported. Brandon
— 1:47:06
Yep. Till next time Brandon
— 1:47:12
Okay. All right. That was a, a solid what? Oh, almost two hours. Oh, boy. Okay. all, I guess that’s, Stephen
— 1:47:21
I think that was, Brandon
— 1:47:22
yeah. all right. Well, so look out for blog post and social media posts, announcing the private alpha to our subscribers. You will, we will be able to chat in Slack and on GitHub discussions, get, get some information about how things are going, and then a public beta in some number of weeks in the future, and then a official public release. Brandon
— 1:47:50
I, I can’t say I am exactly looking forward to fielding bug reports from people having to do with cloud kit syncing, but, you know, that’s the name of the game. also, this is new for us, the, the whole YouTube channel. Feel free to like, subscribe to that. I don’t know what we’re gonna post to it, but maybe we’ll find some fun things. Brandon
— 1:48:10
and yeah. oh. All right. Wait, now, now more questions coming in. Did y’all answer the question about, other s supporting other sink engines like super base? yeah. We didn’t answer, we didn’t talk about that, but we, there are no plans right now. There is maybe a slight glimmer of hope that we could, make, like extract out the CK sync engine, allow you to do other things, but that really is just not a focus right now. Brandon
— 1:48:39
It really is just let’s get cloud kit working. ’cause that is honestly complex enough. absolutely. And then are you gonna release a recording advice room? Yeah. So we will release, recording, probably next week. All right. Should we call it? Great. Stephen
— 1:48:57
Yeah. Thanks everyone for joining. Brandon
— 1:48:59
Okay. All right. We are out. Stephen
— 1:49:02
All right. Till next time. Brandon
— 1:49:04
Till next time. Downloads Sample code 0329-pflive-modern-persistence Point-Free A hub for advanced Swift programming. Brought to you by Brandon Williams and Stephen Celis . Content Become a member The Point-Free Way Beta previews Gifts Videos Collections Free clips Blog More About Us Community Slack Mastodon Twitter BlueSky GitHub Contact Us Privacy Policy © 2026 Point-Free, Inc. All rights are reserved for the videos and transcripts on this site. All other content is licensed under CC BY-NC-SA 4.0 , and the underlying source code to run this site is licensed under the MIT License .