Skip to content

feat: engine and database info + opt-in for unwraped values in idb + new options system #107

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

Merged
merged 5 commits into from
May 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ It was time to do a full review and refactoring, which results in:
- `.has()`, `.keys()` and `.size` are deprecated in `LocalStorage`. They will be removed in v9. They moved to the new `StorageMap` service.
- `JSONSchemaNumeric` deprecated (will be removed in v9)
- `LSGetItemsOptions` deprecated (not necessary anymore, will be removed in v9)
- `LOCAL_STORAGE_PREFIX` and `prefix` option of `localStorageProviders()` deprecated (will be removed in v9))
- `LOCAL_STORAGE_PREFIX` and `localStorageProviders()` deprecated (will be removed in v9). Moved to `StorageModule.forRoot()`
- `setItemSubscribe()`, `removeItemSubscribe()` and `clearSubscribe()` deprecated (will be removed in v9)

### Reduced public API
Expand Down
26 changes: 24 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ Efficient client-side storage module for Angular apps and Progressive Wep Apps (
- **security**: validate data with a JSON Schema,
- **compatibility**: works around some browsers issues,
- **documentation**: API fully explained, and a changelog!
- **maintenance**: the lib follows Angular LTS and anticipates the next Angular version,
- **reference**: 1st Angular library for client-side storage according to [ngx.tools](https://ngx.tools/#/search?q=local%20storage).

## By the same author
Expand Down Expand Up @@ -52,6 +51,28 @@ npm install @ngx-pwa/local-storage@next
npm install @ngx-pwa/local-storage@6
```

*Since version 8*, this second step is:
- not required for the lib to work,
- **strongly recommended for all new applications**, as it allows interoperability
and is future-proof, as it should become the default in a future version,
- **prohibited in applications already using this lib and already deployed in production**,
as it would break with previously stored data.

```ts
import { StorageModule } from '@ngx-pwa/local-storage';

@NgModule({
imports: [
StorageModule.forRoot({
IDBNoWrap: true,
})
]
})
export class AppModule {}
```

**Must be done at initialization, ie. in `AppModule`, and must not be loaded again in another module.**

### Upgrading

If you still use the old `angular-async-local-storage` package, or to update to new versions,
Expand Down Expand Up @@ -105,7 +126,8 @@ export class YourService {
```

New *since version 8* of this lib, this service API follows the
[native `Map` API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map),
[native `Map` API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)
and the new upcoming standard [kv-storage API](https://github.com/WICG/kv-storage),
except it's asynchronous via [RxJS `Observable`s](http://reactivex.io/rxjs/).

It does the same thing as the `LocalStorage` service, but also allows more advanced operations.
Expand Down
6 changes: 3 additions & 3 deletions docs/COLLISION.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ but is not recommended as there was breaking changes in v8.
For example:

```typescript
import { localStorageProviders } from '@ngx-pwa/local-storage';
import { StorageModule } from '@ngx-pwa/local-storage';

@NgModule({
providers: [
localStorageProviders({
imports: [
StorageModule.forRoot({
IDBDBName: 'myAppStorage', // custom database name when in `indexedDB`
LSPrefix: 'myapp_', // prefix when in `localStorage` fallback
})
Expand Down
102 changes: 78 additions & 24 deletions docs/INTEROPERABILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,36 +19,42 @@ as there are important things to do and to be aware of to achieve interoperabili
Interoperability can be achieved:
- **since v8 of this lib**,
- **only for apps that haven't been deployed in production yet**,
as v8 changed the storage system to achieve interoperability:
- it won't work on data stored with this lib before v8, as it still uses the old storage system for backward compatibility,
- changing configuration on the fly would mean to **lose all previously stored data**.
as v8 uses the following opt-in option to allow interoperability:
changing configuration on the fly would mean to **lose all previously stored data**.

## Configuration
```ts
import { StorageModule } from '@ngx-pwa/local-storage';

@NgModule({
imports: [
StorageModule.forRoot({
IDBNoWrap: true,
})
]
})
export class AppModule {}
```

Note:
- it is an initialization step, so as mentioned in the examples below, **it must be done in `AppModule`**,
- **never change these options in an app already deployed in production, as all previously stored data would be lost**.

## Configuration

### `indexedDB` database and object store names

When storing in `indexedDB`, names are used for the database and the object store,
so you will need that all APIs use the same names.

Option 1: keep the config of this lib and change the names in the other APIs,
by using the default values exported by the lib:

```typescript
import { DEFAULT_IDB_DB_NAME, DEFAULT_IDB_STORE_NAME } from '@ngx-pwa/local-storage';
```

Option 2: change this lib config, according to your other APIs:
- Option 1 (recommended): change this lib config, according to your other APIs:

```typescript
import { localStorageProviders } from '@ngx-pwa/local-storage';
```ts
import { StorageModule } from '@ngx-pwa/local-storage';

@NgModule({
providers: [
localStorageProviders({
imports: [
StorageModule.forRoot({
IDBNoWrap: true,
IDBDBName: 'customDataBaseName',
IDBStoreName: 'customStoreName',
})
Expand All @@ -57,36 +63,62 @@ import { localStorageProviders } from '@ngx-pwa/local-storage';
export class AppModule {}
```

- Option 2: keep the config of this lib and change the options in the other APIs,
by using the values exported by the lib:

```ts
if (this.storageMap.backingEngine === 'indexedDB') {
const { database, store, version } = this.storageMap.backingStore;
}
```

This second option can be difficult to manage due to some browsers issues in some special contexts
(Firefox private mode and Safari cross-origin iframes),
as **the information may be wrong at initialization,**
as the storage could fallback from `indexedDB` to `localStorage`
only after a first read or write operation.

### `localStorage` prefix

In some cases (see the [browser support guide](./BROWSERS_SUPPORT)),
`indexedDB` is not available, and libs fallback to `localStorage`.
Some libs prefixes `localStorage` keys. This lib doesn't by default,
but you can add a prefix:
but you can add a prefix.

- Option 1 (recommended):

```typescript
import { localStorageProviders } from '@ngx-pwa/local-storage';
import { StorageModule } from '@ngx-pwa/local-storage';

@NgModule({
providers: [
localStorageProviders({
imports: [
StorageModule.forRoot({
LSPrefix: 'myapp_',
})
]
})
export class AppModule {}
```

- Option 2:

```ts
if (this.storageMap.backingEngine === 'localStorage') {
const { prefix } = this.storageMap.fallbackBackingStore;
}
```

### Example with `localforage`

Interoperability with `localforage` lib can be achieved with this config:

```typescript
import { localStorageProviders } from '@ngx-pwa/local-storage';
import { StorageModule } from '@ngx-pwa/local-storage';

@NgModule({
providers: [
localStorageProviders({
imports: [
StorageModule.forRoot({
IDBNoWrap: true,
LSPrefix: 'localforage/',
IDBDBName: 'localforage',
IDBStoreName: 'keyvaluepairs',
Expand All @@ -96,6 +128,28 @@ import { localStorageProviders } from '@ngx-pwa/local-storage';
export class AppModule {}
```

### Example with native `indexedDB`

Interoperability with native `indexedDB` can be achieved that way:

```ts
if (this.storageMap.backingEngine === 'indexedDB') {

const { database, store, version } = this.storageMap.backingStore;

const dbRequest = indexedDB.open(database, version);

dbRequest.addEventListener('success', () => {

const store = dbRequest.result.transaction([store], 'readonly').objectStore(store);

const request = store.get(index);

});

}
```

## Warnings

### `indexedDB` store
Expand All @@ -107,7 +161,7 @@ or when the version change (but this case doesn't happen in this lib).
**If this step is missing, then all `indexedDB` operations in the lib will fail as the store will be missing.**

Then, you need to ensure:
- you use the same database `version` as the lib (none or `1`),
- you use the same database `version` as the lib (default to `1`),
- the store is created:
- by letting this lib to be initialized first (beware of concurrency issues),
- or if another API is going first, it needs to take care of the creation of the store (with the same name).
Expand Down
19 changes: 3 additions & 16 deletions docs/MIGRATION_TO_V8.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,6 @@ npm install @ngx-pwa/local-storage@next
2. Start your project: problems will be seen at compilation.
Or you could search for `getItem` as most breaking changes are about its options.

## New `indexedDB` store

To allow interoperability, the internal `indexedDB` storing system has changed.
It is not a breaking change as the lib do it in a backward-compatible way:
- when `indexedDB` storage is empty (new app users or data swiped), the new storage is used,
- when `indexedDB` old storage is here, the lib stays on this one.

So it should not concern you, but as it is very sensitive change, we recommend
**to test previously stored data is not lost before deploying in production**.

It's internal stuff, but it also means there is a transition phase where some of the users of your app
will be on the new storage, and others will be on the old one.

## The bad part: breaking changes

**The following changes may require action from you**.
Expand Down Expand Up @@ -343,11 +330,11 @@ export class AppModule {}

Since v8:
```typescript
import { localStorageProviders } from '@ngx-pwa/local-storage';
import { StorageModule } from '@ngx-pwa/local-storage';

@NgModule({
providers: [
localStorageProviders({
imports: [
StorageModule.forRoot({
LSPrefix: 'myapp_', // Note the underscore
IDBDBName: 'myapp_ngStorage',
}),
Expand Down
11 changes: 6 additions & 5 deletions projects/demo/src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { StorageModule } from '@ngx-pwa/local-storage';

import { AppComponent } from './app.component';

@NgModule({
declarations: [
AppComponent
],
declarations: [AppComponent],
imports: [
BrowserModule
BrowserModule,
StorageModule.forRoot({
IDBNoWrap: true,
}),
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
5 changes: 2 additions & 3 deletions projects/ivy/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';

// TODO: reintroduce `StorageModule.forRoot()`
@NgModule({
declarations: [
AppComponent
],
declarations: [AppComponent],
imports: [
BrowserModule
],
Expand Down
9 changes: 4 additions & 5 deletions projects/localforage/src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { localStorageProviders } from '@ngx-pwa/local-storage';
import { StorageModule } from '@ngx-pwa/local-storage';

import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
Expand All @@ -14,13 +14,12 @@ import { HomeComponent } from './home/home.component';
imports: [
BrowserModule,
AppRoutingModule,
],
providers: [
localStorageProviders({
StorageModule.forRoot({
LSPrefix: 'localforage/',
IDBNoWrap: true,
IDBDBName: 'localforage',
IDBStoreName: 'keyvaluepairs'
})
}),
],
bootstrap: [AppComponent]
})
Expand Down
Loading