* refactor(store): more reworks
* Enable auto save by default
* Store to resource table by default
* Remove share store
* Clean up
* Add close store
* Add store function
* Add lazy store
* Add init to lazy store
* refresh cache in example
* Add get-or-create-store
* Revert "Add get-or-create-store"
This reverts commit 7ffd769240.
* try get first
* Docs
* Use absolute path for store
* more docs
* Allow js to use pre-stored (de)serialize functions
* Fix js get and close store
* Show case how to use pretty json
* Update readme
* Use store instead of `store_builder` in example
* Build
* Fix example
* More docs for StoreBuilder::build
* Add default (de)serialize fn
* Use pretty json by default
* Use `undefined` for empty value in get
* Change files
* Differentiate json null from no value for events
* Add create or existing
* Build
* Rename inner store's inset method to set
* Update readme
* Apply suggestions from code review
* Use close instead
* Update breaking changes
* Return result in resolve_store_path
* Change to close_resource and take &self
* Clean up
* Apply suggestions from code review
Co-authored-by: Amr Bashir <amr.bashir2015@gmail.com>
* Remove unused pub(crate)
* Update change file
* Expose resolve_store_path
* Remove with_store
* Remove StoreInner from pub and expose is_empty
* Fix wrong jsdoc param
* Update readme
* rename createOrExistingStore to createOrLoad
* make api consistent with the JS implementation, add examples
* fmt
* reintroduce "get existing store" behavior for create_or_load
* rename createOrLoad to newOrExisting
* keep store lock throughout whole new_or_existing_inner
* Remove load
* Missed if load
* Don't make StoreState public
* Remove R: Runtime from Builder
* rename newOrExisting to load, load to reload
* update docs
* rename missing reload fn
* rename builder fn to build()
* fix default permission
* Fix description and create_new logic
* Clippy
* Update docs
* Update docs
* remove create_store command
* remove close_store command since we extend from Resource
* Revert "remove close_store command since we extend from Resource"
This reverts commit 4a29fc8990.
* Reapply "remove close_store command since we extend from Resource"
This reverts commit 70a1830e7d.
---------
Co-authored-by: Amr Bashir <amr.bashir2015@gmail.com>
Co-authored-by: Lucas Nogueira <lucas@tauri.app>
@ -70,7 +70,7 @@ Afterwards all the plugin's APIs are available through the JavaScript guest bind
```typescript
import { Store } from '@tauri-apps/plugin-store'
const store = new Store('.settings.dat')
const store = await Store.load('settings.json')
await store.set('some-key', { value: 5 })
@ -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:
@ -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:
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
if("__TAURI__"inwindow){var__TAURI_PLUGIN_STORE__=function(e){"use strict";vart,r;functiona(e,t=!1){returnwindow.__TAURI_INTERNALS__.transformCallback(e,t)}asyncfunctioni(e,t={},r){returnwindow.__TAURI_INTERNALS__.invoke(e,t,r)}"function"==typeofSuppressedError&&SuppressedError;classn{getrid(){returnfunction(e,t,r,a){if("a"===r&&!a)thrownewTypeError("Private accessor was defined without a getter");if("function"==typeoft?e!==t||!a:!t.has(e))thrownewTypeError("Cannot read private member from an object whose class did not declare it");return"m"===r?a:"a"===r?a.call(e):a?a.value:t.get(e)}(this,t,"f")}constructor(e){t.set(this,void0),function(e,t,r,a,i){if("function"==typeoft?e!==t||!i:!t.has(e))thrownewTypeError("Cannot write private member to an object whose class did not declare it");t.set(e,r)}(this,t,e)}asyncclose(){returni("plugin:resources|close",{rid:this.rid})}}asyncfunctions(e,t,r){constn={kind:"Any"};returni("plugin:event|listen",{event:e,target:n,handler:a(t)}).then((t=>async()=>asyncfunction(e,t){awaiti("plugin:event|unlisten",{event:e,eventId:t})}(e,t)))}t=newWeakMap,function(e){e.WINDOW_RESIZED="tauri://resize",e.WINDOW_MOVED="tauri://move",e.WINDOW_CLOSE_REQUESTED="tauri://close-requested",e.WINDOW_DESTROYED="tauri://destroyed",e.WINDOW_FOCUS="tauri://focus",e.WINDOW_BLUR="tauri://blur",e.WINDOW_SCALE_FACTOR_CHANGED="tauri://scale-change",e.WINDOW_THEME_CHANGED="tauri://theme-changed",e.WINDOW_CREATED="tauri://window-created",e.WEBVIEW_CREATED="tauri://webview-created",e.DRAG_ENTER="tauri://drag-enter",e.DRAG_OVER="tauri://drag-over",e.DRAG_DROP="tauri://drag-drop",e.DRAG_LEAVE="tauri://drag-leave"}(r||(r={}));classoextendsn{constructor(e,t){super(e),this.path=t}asyncset(e,t){awaiti("plugin:store|set",{rid:this.rid,key:e,value:t})}asyncget(e){returnawaiti("plugin:store|get",{rid:this.rid,key:e})}asynchas(e){returnawaiti("plugin:store|has",{rid:this.rid,key:e})}asyncdelete(e){returnawaiti("plugin:store|delete",{rid:this.rid,key:e})}asyncclear(){awaiti("plugin:store|clear",{rid:this.rid})}asyncreset(){awaiti("plugin:store|reset",{rid:this.rid})}asynckeys(){returnawaiti("plugin:store|keys",{rid:this.rid})}asyncvalues(){returnawaiti("plugin:store|values",{rid:this.rid})}asyncentries(){returnawaiti("plugin:store|entries",{rid:this.rid})}asynclength(){returnawaiti("plugin:store|length",{rid:this.rid})}async load(){awaiti("plugin:store|load",{rid:this.rid})}asyncsave(){awaiti("plugin:store|save",{rid:this.rid})}asynconKeyChange(e,t){returnawaits("store://change",(r=>{r.payload.path===this.path&&r.payload.key===e&&t(r.payload.value)}))}asynconChange(e){returnawaits("store://change",(t=>{t.payload.path===this.path&&e(t.payload.key,t.payload.value)}))}}returne.Store=o,e.createStore=asyncfunction(e,t){constr=awaiti("plugin:store|create_store",{path:e,...t});returnnewo(r,e)},e}({});Object.defineProperty(window.__TAURI__,"store",{value:__TAURI_PLUGIN_STORE__})}
if("__TAURI__"inwindow){var__TAURI_PLUGIN_STORE__=function(t){"use strict";vare,a;functionr(t,e=!1){returnwindow.__TAURI_INTERNALS__.transformCallback(t,e)}asyncfunctions(t,e={},a){returnwindow.__TAURI_INTERNALS__.invoke(t,e,a)}"function"==typeofSuppressedError&&SuppressedError;classi{getrid(){returnfunction(t,e,a,r){if("a"===a&&!r)thrownewTypeError("Private accessor was defined without a getter");if("function"==typeofe?t!==e||!r:!e.has(t))thrownewTypeError("Cannot read private member from an object whose class did not declare it");return"m"===a?r:"a"===a?r.call(t):r?r.value:e.get(t)}(this,e,"f")}constructor(t){e.set(this,void0),function(t,e,a,r,s){if("function"==typeofe?t!==e||!s:!e.has(t))thrownewTypeError("Cannot write private member to an object whose class did not declare it");e.set(t,a)}(this,e,t)}asyncclose(){returns("plugin:resources|close",{rid:this.rid})}}asyncfunctionn(t,e,a){consti={kind:"Any"};returns("plugin:event|listen",{event:t,target:i,handler:r(e)}).then((e=>async()=>asyncfunction(t,e){awaits("plugin:event|unlisten",{event:t,eventId:e})}(t,e)))}asyncfunctiono(t,e){returnawaitu.load(t,e)}e=newWeakMap,function(t){t.WINDOW_RESIZED="tauri://resize",t.WINDOW_MOVED="tauri://move",t.WINDOW_CLOSE_REQUESTED="tauri://close-requested",t.WINDOW_DESTROYED="tauri://destroyed",t.WINDOW_FOCUS="tauri://focus",t.WINDOW_BLUR="tauri://blur",t.WINDOW_SCALE_FACTOR_CHANGED="tauri://scale-change",t.WINDOW_THEME_CHANGED="tauri://theme-changed",t.WINDOW_CREATED="tauri://window-created",t.WEBVIEW_CREATED="tauri://webview-created",t.DRAG_ENTER="tauri://drag-enter",t.DRAG_OVER="tauri://drag-over",t.DRAG_DROP="tauri://drag-drop",t.DRAG_LEAVE="tauri://drag-leave"}(a||(a={}));classuextendsi{constructor(t){super(t)}staticasyncload(t,e){consta=awaits("plugin:store|load",{path:t,...e});returnnewu(a)}staticasyncget(t){returnawaits("plugin:store|get_store",{path:t}).then((t=>t?newu(t):null))}asyncset(t,e){awaits("plugin:store|set",{rid:this.rid,key:t,value:e})}asyncget(t){const[e,a]=awaits("plugin:store|get",{rid:this.rid,key:t});returna?e:void0}asynchas(t){returnawaits("plugin:store|has",{rid:this.rid,key:t})}asyncdelete(t){returnawaits("plugin:store|delete",{rid:this.rid,key:t})}asyncclear(){awaits("plugin:store|clear",{rid:this.rid})}asyncreset(){awaits("plugin:store|reset",{rid:this.rid})}asynckeys(){returnawaits("plugin:store|keys",{rid:this.rid})}asyncvalues(){returnawaits("plugin:store|values",{rid:this.rid})}asyncentries(){returnawaits("plugin:store|entries",{rid:this.rid})}asynclength(){returnawaits("plugin:store|length",{rid:this.rid})}asyncreload(){awaits("plugin:store|reload",{rid:this.rid})}asyncsave(){awaits("plugin:store|save",{rid:this.rid})}asynconKeyChange(t,e){returnawaitn("store://change",(a=>{a.payload.resourceId===this.rid&&a.payload.key===t&&e(a.payload.exists?a.payload.value:void0)}))}asynconChange(t){returnawaitn("store://change",(e=>{e.payload.resourceId===this.rid&&t(e.payload.key,e.payload.exists?e.payload.value:void0)}))}}returnt.LazyStore=class{getstore(){returnthis._store||(this._store=o(this.path,this.options)),this._store}constructor(t,e){this.path=t,this.options=e}asyncinit(){awaitthis.store}asyncset(t,e){return(awaitthis.store).set(t,e)}asyncget(t){return(awaitthis.store).get(t)}asynchas(t){return(awaitthis.store).has(t)}asyncdelete(t){return(awaitthis.store).delete(t)}asyncclear(){await(awaitthis.store).clear()}asyncreset(){await(awaitthis.store).reset()}asynckeys(){return(awaitthis.store).keys()}asyncvalues(){return(awaitthis.store).values()}asyncentries(){return(awaitthis.store).entries()}asynclength(){return(awaitthis.store).length()}asyncreload(){await(awaitthis.store).reload()}asyncsave(){await(awaitthis.store).save()}asynconKeyChange(t,e){return(awaitthis.store).onKeyChange(t,e)}asynconChange(t){return(awaitthis.store).onChange(t)}asyncclose(){this._store&&await(awaitthis._store).close()}},t.Store=u,t.getStore=asyncfunction(t){returnawaitu.get(t)},t.load=o,t}({});Object.defineProperty(window.__TAURI__,"store",{value:__TAURI_PLUGIN_STORE__})}