Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(store)!: more reworks #1860

Merged
merged 79 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from 73 commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
9811756
refactor(store): more reworks
Legend-Master Oct 2, 2024
35b439f
Enable auto save by default
Legend-Master Oct 2, 2024
ea9c101
Store to resource table by default
Legend-Master Oct 3, 2024
98d4fc4
Remove share store
Legend-Master Oct 3, 2024
8975d10
Clean up
Legend-Master Oct 3, 2024
e0bbc6d
Merge remote-tracking branch 'upstream/v2' into store-rework-2
Legend-Master Oct 3, 2024
4cb9d8d
Add close store
Legend-Master Oct 3, 2024
6cdaa31
Add store function
Legend-Master Oct 3, 2024
79bc8d0
Add lazy store
Legend-Master Oct 3, 2024
bbd34b1
Add init to lazy store
Legend-Master Oct 3, 2024
17d910b
refresh cache in example
Legend-Master Oct 3, 2024
7ffd769
Add get-or-create-store
Legend-Master Oct 3, 2024
3acf66e
Revert "Add get-or-create-store"
Legend-Master Oct 3, 2024
42c5a1c
try get first
Legend-Master Oct 3, 2024
4f17adc
Merge branch 'v2' into store-rework-2
Legend-Master Oct 3, 2024
45b2af4
Docs
Legend-Master Oct 3, 2024
d22de02
Use absolute path for store
Legend-Master Oct 3, 2024
a3bef84
more docs
Legend-Master Oct 3, 2024
718f5dc
Allow js to use pre-stored (de)serialize functions
Legend-Master Oct 3, 2024
4f13a03
Fix js get and close store
Legend-Master Oct 3, 2024
73f365d
Show case how to use pretty json
Legend-Master Oct 3, 2024
2718722
Update readme
Legend-Master Oct 3, 2024
f6a72ee
Merge branch 'v2' into store-rework-2
Legend-Master Oct 3, 2024
7723f48
Use store instead of `store_builder` in example
Legend-Master Oct 3, 2024
120f39f
Build
Legend-Master Oct 3, 2024
bfe2b38
Merge branch 'v2' into store-rework-2
Legend-Master Oct 3, 2024
50ab4c1
Fix example
Legend-Master Oct 3, 2024
fc51b3d
More docs for StoreBuilder::build
Legend-Master Oct 3, 2024
4037589
Add default (de)serialize fn
Legend-Master Oct 4, 2024
1ef9f6a
Use pretty json by default
Legend-Master Oct 4, 2024
831105d
Use `undefined` for empty value in get
Legend-Master Oct 4, 2024
25d677d
Change files
Legend-Master Oct 4, 2024
7faf8c3
Differentiate json null from no value for events
Legend-Master Oct 4, 2024
dc5be00
Add create or existing
Legend-Master Oct 5, 2024
c7f2cfc
Merge branch 'v2' into store-rework-2
Legend-Master Oct 5, 2024
d3d9cfe
Merge branch 'v2' into store-rework-2
Legend-Master Oct 8, 2024
92196ee
Build
Legend-Master Oct 8, 2024
a00cb15
Rename inner store's inset method to set
Legend-Master Oct 8, 2024
c709447
Update readme
Legend-Master Oct 8, 2024
230e6bb
Apply suggestions from code review
Legend-Master Oct 10, 2024
3413d2a
Use close instead
Legend-Master Oct 10, 2024
7c24d4a
Merge remote-tracking branch 'upstream/v2' into store-rework-2
Legend-Master Oct 10, 2024
c3748b3
Update breaking changes
Legend-Master Oct 10, 2024
d88fcb5
Return result in resolve_store_path
Legend-Master Oct 10, 2024
39dec5d
Change to close_resource and take &self
Legend-Master Oct 10, 2024
3f470a7
Clean up
Legend-Master Oct 10, 2024
5296ffa
Apply suggestions from code review
Legend-Master Oct 11, 2024
a020ae3
Remove unused pub(crate)
Legend-Master Oct 11, 2024
7e33a5e
Update change file
Legend-Master Oct 11, 2024
1498eb5
Expose resolve_store_path
Legend-Master Oct 14, 2024
02d077e
Remove with_store
Legend-Master Oct 14, 2024
99321dd
Remove StoreInner from pub and expose is_empty
Legend-Master Oct 14, 2024
1c401f7
Fix wrong jsdoc param
Legend-Master Oct 14, 2024
3127ce5
Merge remote-tracking branch 'upstream/v2' into store-rework-2
Legend-Master Oct 15, 2024
7aca255
Update readme
Legend-Master Oct 15, 2024
083c165
rename createOrExistingStore to createOrLoad
lucasfernog Oct 15, 2024
ff9bddd
make api consistent with the JS implementation, add examples
lucasfernog Oct 15, 2024
afbb5aa
fmt
lucasfernog Oct 15, 2024
028d666
reintroduce "get existing store" behavior for create_or_load
lucasfernog Oct 15, 2024
8a8bdca
rename createOrLoad to newOrExisting
lucasfernog Oct 15, 2024
a7af661
keep store lock throughout whole new_or_existing_inner
lucasfernog Oct 15, 2024
fbc7149
Remove load
Legend-Master Oct 15, 2024
5f2de5e
Missed if load
Legend-Master Oct 15, 2024
985059a
Don't make StoreState public
Legend-Master Oct 15, 2024
44016a4
Remove R: Runtime from Builder
Legend-Master Oct 15, 2024
983bd82
rename newOrExisting to load, load to reload
lucasfernog Oct 16, 2024
d7bff64
update docs
lucasfernog Oct 16, 2024
ac91270
rename missing reload fn
lucasfernog Oct 16, 2024
150e030
rename builder fn to build()
lucasfernog Oct 16, 2024
3288e4b
fix default permission
lucasfernog Oct 16, 2024
99cafa6
Fix description and create_new logic
Legend-Master Oct 17, 2024
0d1b78a
Merge branch 'v2' into store-rework-2
Legend-Master Oct 17, 2024
bf5a191
Clippy
Legend-Master Oct 17, 2024
9751296
Update docs
Legend-Master Oct 17, 2024
5181d2b
Update docs
Legend-Master Oct 17, 2024
09cce55
remove create_store command
lucasfernog Oct 17, 2024
4a29fc8
remove close_store command since we extend from Resource
lucasfernog Oct 17, 2024
70a1830
Revert "remove close_store command since we extend from Resource"
lucasfernog Oct 17, 2024
8e71393
Reapply "remove close_store command since we extend from Resource"
lucasfernog Oct 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changes/store-plugin-rework-js-feat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"store-js": minor:feat
---

- Add `getStore`
- Add an option to use pre-stored (de)serialize functions (registered on rust)
- Add `LazyStore`
23 changes: 23 additions & 0 deletions .changes/store-plugin-rework.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
"store": minor:breaking
---

### Breaking changes:

- Renamed `StoreCollection` to `StoreState`
- `StoreBuilder::build` now returns a `Result`
- `StoreExt::store` now returns `Result<Arc<Store>>`

### Enhancements:

- Save and cancel pending auto save on drop
- Use absolute path as store's key, fix #984
- Share store to resource table by default
- Enable auto save with 100ms debounce time by default
- Use pretty json by default, close #1690

### New features:

- Add `get_store` to get shared stores across js and rust side
- Add default (de)serialize functions settings `default_serialize_fn` and `default_deserialize_fn`
- Allow js to use pre-stored (de)serialize functions registered by `register_serialize_fn` and `register_deserialize_fn`
6 changes: 1 addition & 5 deletions examples/api/src-tauri/capabilities/base.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,6 @@
],
"deny": ["$APPDATA/db/*.stronghold"]
},
"store:allow-entries",
"store:allow-get",
"store:allow-set",
"store:allow-save",
"store:allow-load"
"store:default"
]
}
3 changes: 2 additions & 1 deletion examples/api/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ pub fn run() {
.user_agent(&format!("Tauri API - {}", std::env::consts::OS))
.title("Tauri API Validation")
.inner_size(1000., 800.)
.min_inner_size(600., 400.);
.min_inner_size(600., 400.)
.visible(false);
}

#[cfg(target_os = "windows")]
Expand Down
78 changes: 60 additions & 18 deletions examples/api/src/views/Store.svelte
Original file line number Diff line number Diff line change
@@ -1,34 +1,71 @@
<script>
import { Store } from "@tauri-apps/plugin-store";
import { LazyStore } from "@tauri-apps/plugin-store";
import { onMount } from "svelte";

export let onMessage;

let key;
let value;

const store = new Store("cache.json");
let store = new LazyStore("cache.json");
let cache = {};

onMount(async () => {
await store.load();
const values = await store.entries();
for (const [key, value] of values) {
cache[key] = value;
async function refreshEntries() {
try {
const values = await store.entries();
cache = {};
for (const [key, value] of values) {
cache[key] = value;
}
} catch (error) {
onMessage(error);
}
cache = cache;
}

onMount(async () => {
await refreshEntries();
});

function write(key, value) {
store
.set(key, value)
.then(() => store.get(key))
.then((v) => {
cache[key] = v;
async function write(key, value) {
try {
if (value) {
await store.set(key, value);
} else {
await store.delete(key);
}
const v = await store.get(key);
if (v === undefined) {
delete cache[key];
cache = cache;
})
.then(() => store.save())
.catch(onMessage);
} else {
cache[key] = v;
}
} catch (error) {
onMessage(error);
}
}

async function reset() {
try {
await store.reset();
} catch (error) {
onMessage(error);
}
await refreshEntries();
}

async function close() {
try {
await store.close();
onMessage("Store is now closed, any new operations will error out");
} catch (error) {
onMessage(error);
}
}

function reopen() {
store = new LazyStore("cache.json");
onMessage("We made a new `LazyStore` instance, operations will now work");
}
</script>

Expand All @@ -44,7 +81,12 @@
<input class="grow input" bind:value />
</div>

<button class="btn" on:click={() => write(key, value)}> Write </button>
<div>
<button class="btn" on:click={() => write(key, value)}>Write</button>
<button class="btn" on:click={() => reset()}>Reset</button>
<button class="btn" on:click={() => close()}>Close</button>
<button class="btn" on:click={() => reopen()}>Re-open</button>
</div>
</div>

<div>
Expand Down
61 changes: 18 additions & 43 deletions plugins/store/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ fn main() {
Afterwards all the plugin's APIs are available through the JavaScript guest bindings:

```typescript
import { Store } from '@tauri-apps/plugin-store'
import { createStore } from '@tauri-apps/plugin-store'
Legend-Master marked this conversation as resolved.
Show resolved Hide resolved

const store = new Store('.settings.dat')
const store = await createStore('settings.json')

await store.set('some-key', { value: 5 })

Expand All @@ -81,14 +81,11 @@ if (val) {
} else {
console.log('val is null')
}

// This manually saves the store.
await store.save()
```

### Persisting Values

As seen above, values added to the store are not persisted between application loads unless the application is closed gracefully.
Modifications made to the store are automatically saved by default

You can manually save a store with:

Expand All @@ -103,65 +100,43 @@ However, you can also load them manually later like so:
await store.load()
```

### LazyStore

There's also a high level API `LazyStore` which only loads the store on first access, note that the options will be ignored if a `Store` with that path has already been created

```typescript
import { LazyStore } from '@tauri-apps/plugin-store'

const store = new LazyStore('settings.json')
```

## Usage from Rust

You can also create `Store` instances directly in Rust:

```rust
use tauri_plugin_store::StoreBuilder;
use tauri_plugin_store::StoreExt;
use serde_json::json;

fn main() {
tauri::Builder::default()
.plugin(tauri_plugin_store::Builder::default().build())
.setup(|app| {
let mut store = StoreBuilder::new("app_data.bin").build(app.handle().clone());

// Attempt to load the store, if it's saved already.
store.load().expect("Failed to load store from disk");
// This loads the store from disk
let store = app.store("app_data.json")?;

// Note that values must be serde_json::Value instances,
// otherwise, they will not be compatible with the JavaScript bindings.
store.insert("a".to_string(), json!("b"));

// You can manually save the store after making changes.
// Otherwise, it will save upon graceful exit as described above.
store.save()
store.set("a".to_string(), json!("b"));
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
```

### Loading Gracefully

If you call `load` on a `Store` that hasn't yet been written to the disk, it will return an error. You must handle this error if you want to gracefully continue and use the default store until you save it to the disk. The example above shows how to do this.

For example, this would cause a panic if the store has not yet been created:

```rust
store.load().unwrap();
```

Rather than silently continuing like you may expect.

You should always handle the error appropriately rather than unwrapping, or you may experience unexpected app crashes:

```rust
store.load().expect("Failed to load store from disk");
```

### Frontend Interoperability

As you may have noticed, the `Store` crated above isn't accessible to the frontend. To interoperate with stores created by JavaScript use the exported `with_store` method:

```rust
use tauri::Wry;
use tauri_plugin_store::StoreExt;

let store = app.store_builder("app_data.bin").build();
store.insert("key", "value");
```
The store created from both Rust side and JavaScript side are stored in the app's resource table and can be accessed by both sides, you can access it by using the same path, with `getStore` and `LazyStore` in the JavaScript side and `get_store` and `store` in the Rust side
Legend-Master marked this conversation as resolved.
Show resolved Hide resolved

## Contributing

Expand Down
2 changes: 1 addition & 1 deletion plugins/store/api-iife.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions plugins/store/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

const COMMANDS: &[&str] = &[
"create_store",
"load",
"get_store",
"close_store",
"set",
"get",
"has",
Expand All @@ -12,9 +15,9 @@ const COMMANDS: &[&str] = &[
"reset",
"keys",
"values",
"length",
"entries",
"load",
"length",
"reload",
"save",
];

Expand Down
17 changes: 5 additions & 12 deletions plugins/store/examples/AppSettingsManager/src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

use std::time::Duration;

use serde_json::json;
use tauri::Listener;
use tauri_plugin_store::StoreExt;

mod app;
Expand All @@ -18,17 +17,11 @@ fn main() {
.plugin(tauri_plugin_store::Builder::new().build())
.setup(|app| {
// Init store and load it from disk
let store = app
.handle()
.store_builder("settings.json")
.auto_save(Duration::from_millis(100))
.build();

// If there are no saved settings yet, this will return an error so we ignore the return value.
let _ = store.load();

let store = app.store("settings.json")?;
app.listen("store://change", |event| {
dbg!(event);
});
let app_settings = AppSettings::load_from_store(&store);

match app_settings {
Ok(app_settings) => {
let theme = app_settings.theme;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "0.1.0",
"identifier": "com.tauri.app-settings-manager",
"build": {
"devUrl": "http://localhost:1420",
"frontendDist": "../dist"
},
"app": {
Expand Down
Loading
Loading