Releases: mergesort/Bodega
Ambiguity Shambiguity
Stay Safe Out There
In version 2.1.1 I had accidentally committed [.unsafeFlags(["-strict-concurrency=complete"])]
into Bodegal's Package.swift
. That prevented the library from compiling on production versions of Xcode, it is now removed, so finally we're all safe again.
The Right Key To Unlock Your Door
This release improves Bodega's API with fixes (#27) and improvements (#25) courtesy of @dannynorth, thank you!
The changes are:
- A new
keysExist
function that more efficiently searches for and filters existing keys in aStorageEngine
. - Fixes the
readDataAndKeys
function to always return the correct data and keys. Previously if thereadDataAndKeys
function was provided an invalid key in thekeys
array incorrect values would be returned after the invalid key index.
Hard To Pin Down
This release fixes incompatibilities with other libraries (#16) by removing the explicit dependency on Version 0.13.3 of SQLite.swift. Bodega is now pinned to any version of SQLite.swift greater than 0.13.2, that way conflicts are less likely to emerge.
Never Feel Empty Using Bodega Again
This release includes a small fix to the SQLiteStorageEngine
.
Previously this code would throw an error.
let noItems = [] // You can imagine some computation that ends up with an empty array rather than setting [] directly
storageEngine.write(noItems)
Now it will not throw an error, instead the write
function will return early and act as a no-op, more accurately matching a user's expectations.
Dependency Fix Release
Ugh you know how sometimes you accidentally mess up a tag and it's not easily fixable? This version fixes a dependency issue for Boutique, nothing more, nothing less.
Version 2.0: Bring Your Own Database
Welcome to the future!
Bodega v2 allows you to extend Bodega far and wide by giving you the power to bring your own database to Bodega in one easy step. Out of the box Bodega v2 is 5-10x faster because the default database is now powered by the blazing fast SQLiteStorageEngine
. But if SQLite or the DiskStorageEngine
aren't your jam, you can build your own StorageEngine
by conforming to a simple protocol. Using Bodega is still as simple as it ever was, requiring very little code, no special objects, with simple defaults out the box.
As a bonus if you do that it will automatically with any Boutique-powered app, providing you the same single source of truth, realtime updates, and a fully offline-capable app you've come to know and love, in only a couple of lines of code.
Warning
This version contains breaking changes
In the Version 1.x series of Bodega the DiskStorage
type was responsible for persisting data to disk. ObjectStorage
was a Codable
layer built on top of DiskStorage
, letting you work with Swift types rather than Data
. Like the name implies DiskStorage
was backed by the file system, but what if you don't want to save Data
to disk? Saving data to disk is a simple and effective starting point, but can get slow when working with large data sets. One of Bodega's goals is to work with every app without causing developers to make tradeoffs, so version 2.0 is focused on eliminating those tradeoffs without ruining the streamlined simplicity Bodega brings.
In the spirit of not making tradeoffs here's how Bodega works with any database you want, say hello to the new StorageEngine
protocol.
public protocol StorageEngine: Actor {
func write(_ data: Data, key: CacheKey) async throws
func write(_ dataAndKeys: [(key: CacheKey, data: Data)]) async throws
func read(key: CacheKey) async -> Data?
func read(keys: [CacheKey]) async -> [Data]
func readDataAndKeys(keys: [CacheKey]) async -> [(key: CacheKey, data: Data)]
func readAllData() async -> [Data]
func readAllDataAndKeys() async -> [(key: CacheKey, data: Data)]
func remove(key: CacheKey) async throws
func remove(keys: [CacheKey]) async throws
func removeAllData() async throws
func keyExists(_ key: CacheKey) async -> Bool
func keyCount() async -> Int
func allKeys() async -> [CacheKey]
func createdAt(key: CacheKey) async -> Date?
func updatedAt(key: CacheKey) async -> Date?
}
By providing your own write
, read
, remove
, key
, and timestamp
related functions, you can make any persistence layer compatible with ObjectStorage
. Whether your app is backed by Realm, Core Data, or even CloudKit, when you create a new StorageEngine
it automatically becomes usable by ObjectStorage
, with one drop dead simple API.
The first StorageEngine
to be implemented is an SQLiteStorageEngine
, bundled with Bodega. I'll explain all the possibilities below, but first let's take a second to see how much faster your apps using Bodega and Boutique will be.
If it's not obvious, a SQLite foundation for Bodega is incredibly faster than using the file system. The DiskStorageStorageEngine
is still available, but if you use the SQLiteStorageEngine
loading 10,000 objects into memory will be more than 400% faster, and writing 5,000 objects is more than 500% faster. With this release I feel confident that you should be able to use Bodega and Boutique in the largest of apps, while counterintuitively becoming a more flexible framework.
Breaking
There's only one change to your code, ObjectStorage
now has a type constraint. This isn't required for ObjectStorage
but was an oversight in the 1.x versions, and a big version bump felt like the right time to fix this mistake.
Before you would initialize a new ObjectStorage like this.
let storage = ObjectStorage(
directory: .documents(appendingPath: "Animals")
)
And now it looks like this, a small tweak!
// Change #1: Instead of a directory we now provide a StorageEngine
// Change #2: Add a type constraint of <Animal> to ObjectStorage
let storage = ObjectStorage<Animal>(
storage: SQLiteStorageEngine(directory: .documents(appendingPath: "Animals"))!
)
And of course the same thing is true if you use DiskStorage
or any StorageEngine
you may build.
You can find Bodega's documentation here, including a lot of updates for the v2 release.
P.S. If you build something useful to others, by all means file a pull request so I can add it to Bodega!
Version 2.0 RC 2: Bring Your Own Database
If you'd like to see all of the v2 changes please consult the v2 RC 1 release notes.
RC 2 Changes
-
Bodega is now fully documented, available at build.ms/bodega/docs
-
StorageEngine
functions have now been markedasync
. Method signatures of conforming types will have to be updated to addasync
, but there is be no change to functionality. TheStorageEngine
protocol has anactor
conformance so the functions would already runasync
, this change just enforces that in the function signature. -
SQLiteStorageEngine
provides two new ways of creating anSQLiteStorageEngine
, either by callingSQLiteStorageEngine.default
orSQLiteStorageEngine.default(appendingPath: "Red Panda Store")
. -
Adding retry logic to
SQLiteStorage
. This wouldn't be an issue in an app, but would crop up as an issue when running tests.
Version 2.0 RC 1: Bring Your Own Database
Welcome to the future! Bodega v2 allows you to extend Bodega far and wide by giving you the power to bring your own database to Bodega in one easy step. Out of the box Bodega v2 is 5-10x faster because the default database is now powered by the blazing fast SQLiteStorageEngine
. But if SQLite or the DiskStorageEngine
aren't your jam, you can build your own StorageEngine
by conforming to a simple protocol. Using Bodega is still as simple as it ever was, taking very little code, and no special objects, with simple defaults.
As a bonus if you do that it will automatically with any Boutique-powered app, providing you the same single source of truth, realtime updates, and a fully offline-capable app you've come to know and love, in only a couple of lines of code.
Warning
This version contains breaking changes
In the Version 1.x series of Bodega the DiskStorage
type was responsible for persisting data to disk. ObjectStorage
was a Codable
layer built on top of DiskStorage
, letting you work with Swift types rather than Data
. Like the name implies DiskStorage
was backed by the file system, but what if you don't want to save Data
to disk? Saving data to disk is a simple and effective starting point, but can get slow when working with large data sets. One of Bodega's goals is to work with every app without causing developers to make tradeoffs, so version 2.0 is focused on eliminating those tradeoffs without ruining the streamlined simplicity Bodega brings.
In the spirit of not making tradeoffs here's how Bodega works with any database you want, say hello to the new StorageEngine
protocol.
public protocol StorageEngine: Actor {
func write(_ data: Data, key: CacheKey) async throws
func write(_ dataAndKeys: [(key: CacheKey, data: Data)]) async throws
func read(key: CacheKey) async -> Data?
func read(keys: [CacheKey]) async -> [Data]
func readDataAndKeys(keys: [CacheKey]) async -> [(key: CacheKey, data: Data)]
func readAllData() async -> [Data]
func readAllDataAndKeys() async -> [(key: CacheKey, data: Data)]
func remove(key: CacheKey) async throws
func remove(keys: [CacheKey]) async throws
func removeAllData() async throws
func keyExists(_ key: CacheKey) async -> Bool
func keyCount() async -> Int
func allKeys() async -> [CacheKey]
func createdAt(key: CacheKey) async -> Date?
func updatedAt(key: CacheKey) async -> Date?
}
By providing your own write
, read
, remove
, key
, and timestamp
related functions, you can make any persistence layer compatible with ObjectStorage
. Whether your app is backed by Realm, Core Data, or even CloudKit, when you create a new StorageEngine
it automatically becomes usable by ObjectStorage
, with one drop dead simple API.
The first StorageEngine
to be implemented is an SQLiteStorageEngine
, bundled with Bodega. I'll explain all the possibilities below, but first let's take a second to see how much faster your apps using Bodega and Boutique will be.
If it's not obvious, a SQLite foundation for Bodega is incredibly faster than using the file system. The DiskStorageStorageEngine
is still available, but if you use the SQLiteStorageEngine
loading 10,000 objects into memory will be more than 400% faster, and writing 5,000 objects is more than 500% faster. With this release I feel confident that you should be able to use Bodega and Boutique in the largest of apps, while counterintuitively becoming a more flexible framework.
Breaking
There's only one change to your code, ObjectStorage
now has a type constraint. This isn't required for ObjectStorage
but was an oversight in the 1.x versions, and a big version bump felt like the right time to fix this mistake.
Before you would initialize a new ObjectStorage like this.
let storage = ObjectStorage(
storage: SQLiteStorageEngine(directory: .documents(appendingPath: "Animals"))!
)
And now it looks like this, one small tweak!
let storage = ObjectStorage<Animal>(
storage: SQLiteStorageEngine(directory: .documents(appendingPath: "Animals"))!
)
And of course the same thing is true if you use DiskStorage
or any StorageEngine
you may build.
P.S. If you build something useful to others, by all means file a pull request so I can add it to Bodega!
A Direct(ory) Improvement
Adding a public FileManager.Directory
initializer
In 1.1.0 I added a fancy new type, FileManager.Directory
.
public extension FileManager {
struct Directory {
public let url: URL
}
}
But I forgot to add a public initializer, so that’s what this release is for… whoops. 😅