sindresorhus / electron-store

Simple data persistence for your Electron app or module - Save and load user preferences, app state, cache, etc
MIT License
4.61k stars 150 forks source link

Add update method [Feature Request] #240

Open ramtinsoltani opened 1 year ago

ramtinsoltani commented 1 year ago

Currently the only available setter Store.set() either sets a single item or takes an object to set multiple values. Providing an object would overwrite the whole value, which is a normal/expected behavior. Though, this leaves out use cases where we want to update multiple fields at a path in one go.

Example:

const store = new Store();

store.store = {
  users: {
    p9dsbfo0b0sbd: {
      name: 'John Smith',
      email: 'john.smith@gmail.com',
      age: 52,
      occupation: {
        title: 'Web Developer',
        remote: false
      }
    }
  }
};

// Updating multiple values (we'll either lose 'email' and 'occupation.title' fields or a schema validation error is thrown)
store.set('users.p9dsbfo0b0sbd', {
  name: 'John M. Smith',
  age: 53,
  occupation: {
    remote: true
  }
});

// Must do
store.set('users.p9dsbfo0b0sbd.name', 'John M. Smith');
store.set('users.p9dsbfo0b0sbd.age', 53);
store.set('users.p9dsbfo0b0sbd.occupation.remote', true);

// Better be able to do (object should be merged deeply)
store.update('users.p9dsbfo0b0sbd', {
  name: 'John M. Smith',
  age: 53,
  occupation: {
    remote: true
  }
});
sindresorhus commented 1 year ago

Seems useful to me.

Is it expected to a user that it does deep merging though?

ramtinsoltani commented 1 year ago

@sindresorhus I think deep merging is more practical, but users might expect a shallow merge based on other database operators such as MongoDB. We can however provide both methods through either:

// Additional argument
update(key: string, object: any, deepMerge: boolean = false)

// Example
store.update('users.p9dsbfo0b0sbd', {
  name: 'John M. Smith',
  age: 53,
  occupation: {
    remote: true
  }
}, true);

or a different method altogether:

// Shallow merge
update(key: string, object: any)
// Deep merge
merge(key: string, object: any)

Though I personally prefer the first approach.

If you find this useful, once we agree on an approach, I can create a dependency-free PR for conf.