From ca9646b4ae7e47bf51a7ce6efc5e7ac44a8b3422 Mon Sep 17 00:00:00 2001 From: javierbrea Date: Sat, 22 Feb 2020 19:10:31 +0100 Subject: [PATCH] feat(Memory): [BREAKING CHANGE] Update data-provider to v2 --- CHANGELOG.md | 11 ++ README.md | 133 --------------------- package-lock.json | 171 +++++++++++++-------------- package.json | 16 ++- rollup.config.js | 27 +++-- sonar-project.properties | 2 +- src/Memory.js | 124 ++++++++------------ src/index.js | 3 +- test/index.spec.js | 5 +- test/memory.spec.js | 244 ++++++++++++++++++--------------------- 10 files changed, 271 insertions(+), 465 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa0cd9b..c183aa3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - "queriesDefaultValue" option has to be removed. - Options should be accepted only as second argument. "uuid" should be defined only using the "uuid" option, not as second argument. +## [2.0.0.beta-1] + +> DISCLAIMER: This major release adapts this plugin to the @data-provider v2.x interface. Read @data-provider docs for further info. + +### Changed +- feat(Memory): [BREAKING CHANGE] - Use data-provider v2 standard arguments (id, options) +- feat(Memory): [BREAKING CHANGE] - Queries now has to be defined as an object: { prop: "foo-prop" } +- feat(Memory): [BREAKING CHANGE] - Remove defaultValue argument, now "initialState" option has to be used instead. +- feat(Memory): [BREAKING CHANGE] - Remove uuid option. Now id is required as first argument. +- feat(Memory): [BREAKING CHANGE] - Remove queriesDefaultValue option. Now this is the default behavior + ## [1.4.3] - 2020-01-26 ### Changed - Update dependencies diff --git a/README.md b/README.md index e14d8b8..38ebe93 100644 --- a/README.md +++ b/README.md @@ -4,139 +4,6 @@ [![NPM downloads][npm-downloads-image]][npm-downloads-url] [![License][license-image]][license-url] -## Overview - -This package provides a [Data Provider][data-provider-url] for handling memory objects. - -* __Data Provider queries__ based on object keys. -* __Reactivity__ to CRUD actions. When a "create", "update" or "delete" method is called over an instance, the cache clean events are dispatched. - -### Install - -```bash -npm i @data-provider/memory --save -``` - -## Api - -`new Memory(defaultValue[, options || uuid][, options])` -* Arguments - * defaultValue - _``_. Object to be stored. Default value is assigned too at the same time. - * options - `` containing properties: - * queriesDefaultValue - _``_ If `true`, the default value of queried instances will be the value of the "key" in the query. If not defined, the default value of queried instances will be the full `defaultValue` object. - * uuid - _``_ Unique id to assign to returned Data Provider instance. Useful when using [Data Provider `instances` handler][data-provider-instances-docs-url]. - * tags - _` or `_ Tags to assign to the instance. Useful when using [Data Provider `instances` handler][data-provider-instances-docs-url]. A "memory" tag will be always added to provided tags by default. - -## Methods - -### query - -`memory.query(key)` -* Arguments - * key - `` Key of the memory object to be read, updated, created or deleted. - -## Cache - -All cache will be cleaned when the `update`, `delete` or `create` methods are executed for any specific query. - -## Default value - -The default value of a "queried" instance will be the complete `defaultValue` object until the "queriesDefaultValue" option is set as `true`, in which case the default value will be the value of the key corresponding to the query: - -```js -import { Memory } from "@data-provider/memory"; - -const fooMemory = new Memory({ - foo: "foo-value", - var: "var-value" -}); - -console.log(fooMemory.query("foo").read.value); // {foo: "foo-value", var: "var-value"} - -const fooMemory2 = new Memory({ - foo: "foo-value", - var: "var-value" -}, { - queriesDefaultValue: true -}); - -console.log(fooMemory2.query("foo").read.value); // "foo" -``` - -## Examples - -Next example will be easier to understand if you are already familiarized with the [Data Provider][data-provider-url] syntax. - -```js -import { Memory } from "@data-provider/memory"; - -const sessionDetails = new Memory({ - userId: null, - isLogedIn: false -}); - -// Pass key to read method -sessionDetails.read("userId").then(userId => { - console.log(userId); -}); - -// Pass key as a query -sessionDetails - .query("userId") - .read() - .then(userId => { - console.log(userId); - }); - -sessionDetails.query("isLogedIn").update(true); -``` - -Use Data Provider Memory objects in combination with Axios Data Provider, and take advantage of the built-in reactivity. Use the memory objects to query the API providers, and, when you update the Memory Object, the API object caches will be cleaned as a consequence: - - -```js -import { Selector } from "@data-provider/core"; -import { Memory } from "@data-provider/memory"; -import { Api } from "@data-provider/axios"; - -const currentAuthor = new Memory({ - id: null -}); -const booksCollection = new Api("http://api.library.com/books"); - -const currentAuthorBooks = new Selector( - { - provider: currentAuthor, - query: () => "id" - }, - { - provider: booksCollection, - query: (query, previousResults) => { - if (!previousResults[0]) { - return; - } - return { - queryString: { - authorId: previousResults[0] - } - }; - } - }, - (currentAuthorId, booksResults) => booksResults -); - -// Api request to "http://api.library.com/books". Return all books -currentAuthorBooks.read(); - -// Api request is not repeated, as query has no changed. -currentAuthorBooks.read(); - -currentAuthor.query("id").update("foo-author-id"); - -// Api request now is sent to "http://api.library.com/books?authorId=foo-author-id". Return author books -currentAuthorBooks.read(); -``` - ## Contributing Contributors are welcome. diff --git a/package-lock.json b/package-lock.json index 2d7a0b8..d046caa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@data-provider/memory", - "version": "1.4.3", + "version": "2.0.0-beta.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -2628,13 +2628,12 @@ } }, "@data-provider/core": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@data-provider/core/-/core-1.8.0.tgz", - "integrity": "sha512-PUeLcCgVgFnI1JJFNW4Dxst/Y7b1Fe7rpKd+9KO3ufLNPhOJvFpUrbzAQJR6b923X4onG9wt4bQYpaet+fWvEA==", + "version": "2.0.0-beta.2", + "resolved": "https://registry.npmjs.org/@data-provider/core/-/core-2.0.0-beta.2.tgz", + "integrity": "sha512-KmbLSOqAjwVcGzumt/asF6HpP8Wbh9CScVJlOkI8I9WIHomGzIXVNXutTeQng/MJsjcm2WNPwEaZVOnivoG4Hg==", "dev": true, "requires": { - "is-promise": "2.1.0", - "lodash": "4.17.15" + "is-promise": "2.1.0" } }, "@jest/console": { @@ -2855,6 +2854,61 @@ "fastq": "^1.6.0" } }, + "@rollup/plugin-commonjs": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-11.0.2.tgz", + "integrity": "sha512-MPYGZr0qdbV5zZj8/2AuomVpnRVXRU5XKXb3HVniwRoRCreGlf5kOE081isNWeiLIi6IYkwTX9zE0/c7V8g81g==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.0.0", + "estree-walker": "^1.0.1", + "is-reference": "^1.1.2", + "magic-string": "^0.25.2", + "resolve": "^1.11.0" + } + }, + "@rollup/plugin-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.0.2.tgz", + "integrity": "sha512-t4zJMc98BdH42mBuzjhQA7dKh0t4vMJlUka6Fz0c+iO5IVnWaEMiYBy1uBj9ruHZzXBW23IPDGL9oCzBkQ9Udg==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.0.4" + } + }, + "@rollup/plugin-node-resolve": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.1.tgz", + "integrity": "sha512-14ddhD7TnemeHE97a4rLOhobfYvUVcaYuqTnL8Ti7Jxi9V9Jr5LY7Gko4HZ5k4h4vqQM0gBQt6tsp9xXW94WPA==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.0.6", + "@types/resolve": "0.0.8", + "builtin-modules": "^3.1.0", + "is-module": "^1.0.0", + "resolve": "^1.14.2" + }, + "dependencies": { + "resolve": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", + "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + } + } + }, + "@rollup/pluginutils": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.0.8.tgz", + "integrity": "sha512-rYGeAc4sxcZ+kPG/Tw4/fwJODC3IXHYDH4qusdN/b6aLw5LPUbzpecYbEJh4sVQGPFJxd2dBU4kc1H3oy9/bnw==", + "dev": true, + "requires": { + "estree-walker": "^1.0.1" + } + }, "@samverschueren/stream-to-observable": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz", @@ -4354,6 +4408,12 @@ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -7181,7 +7241,8 @@ "lodash": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true }, "lodash.get": { "version": "4.4.2", @@ -8100,6 +8161,16 @@ "util.promisify": "^1.0.0" } }, + "redux": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz", + "integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==", + "dev": true, + "requires": { + "loose-envify": "^1.4.0", + "symbol-observable": "^1.2.0" + } + }, "regenerate": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", @@ -8385,92 +8456,6 @@ } } }, - "rollup-plugin-commonjs": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz", - "integrity": "sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q==", - "dev": true, - "requires": { - "estree-walker": "^0.6.1", - "is-reference": "^1.1.2", - "magic-string": "^0.25.2", - "resolve": "^1.11.0", - "rollup-pluginutils": "^2.8.1" - }, - "dependencies": { - "estree-walker": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", - "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", - "dev": true - }, - "rollup-pluginutils": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", - "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", - "dev": true, - "requires": { - "estree-walker": "^0.6.1" - } - } - } - }, - "rollup-plugin-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-json/-/rollup-plugin-json-4.0.0.tgz", - "integrity": "sha512-hgb8N7Cgfw5SZAkb3jf0QXii6QX/FOkiIq2M7BAQIEydjHvTyxXHQiIzZaTFgx1GK0cRCHOCBHIyEkkLdWKxow==", - "dev": true, - "requires": { - "rollup-pluginutils": "^2.5.0" - }, - "dependencies": { - "estree-walker": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", - "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", - "dev": true - }, - "rollup-pluginutils": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", - "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", - "dev": true, - "requires": { - "estree-walker": "^0.6.1" - } - } - } - }, - "rollup-plugin-node-resolve": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz", - "integrity": "sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==", - "dev": true, - "requires": { - "@types/resolve": "0.0.8", - "builtin-modules": "^3.1.0", - "is-module": "^1.0.0", - "resolve": "^1.11.1", - "rollup-pluginutils": "^2.8.1" - }, - "dependencies": { - "estree-walker": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", - "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", - "dev": true - }, - "rollup-pluginutils": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", - "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", - "dev": true, - "requires": { - "estree-walker": "^0.6.1" - } - } - } - }, "rollup-plugin-uglify": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/rollup-plugin-uglify/-/rollup-plugin-uglify-6.0.4.tgz", diff --git a/package.json b/package.json index 2a52a79..e62b1d4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@data-provider/memory", - "version": "1.4.3", + "version": "2.0.0-beta.1", "description": "Memory Data Provider", "keywords": [ "data-provider", @@ -30,16 +30,16 @@ "coveralls": "cat ./coverage/lcov.info | coveralls" }, "peerDependencies": { - "@data-provider/core": "^1.7.0" - }, - "dependencies": { - "lodash": "4.17.15" + "@data-provider/core": "2.x" }, "devDependencies": { "@babel/core": "7.8.4", "@babel/preset-env": "7.8.4", "@babel/preset-react": "7.8.3", - "@data-provider/core": "1.8.0", + "@data-provider/core": "2.0.0-beta.2", + "@rollup/plugin-commonjs": "11.0.2", + "@rollup/plugin-json": "4.0.2", + "@rollup/plugin-node-resolve": "7.1.1", "babel-core": "7.0.0-bridge.0", "babel-jest": "24.9.0", "babel-polyfill": "6.26.0", @@ -51,11 +51,9 @@ "jest": "24.9.0", "lint-staged": "9.5.0", "prettier": "1.19.1", + "redux": "4.0.5", "rollup": "1.30.1", "rollup-plugin-babel": "4.3.3", - "rollup-plugin-commonjs": "10.1.0", - "rollup-plugin-json": "4.0.0", - "rollup-plugin-node-resolve": "5.2.0", "rollup-plugin-uglify": "6.0.4", "sinon": "8.1.1" }, diff --git a/rollup.config.js b/rollup.config.js index 27103ad..c405200 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -9,50 +9,49 @@ http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -const json = require("rollup-plugin-json"); -const commonjs = require("rollup-plugin-commonjs"); -const resolve = require("rollup-plugin-node-resolve"); +const json = require("@rollup/plugin-json"); +const commonjs = require("@rollup/plugin-commonjs"); +const resolve = require("@rollup/plugin-node-resolve"); const babel = require("rollup-plugin-babel"); const uglifier = require("rollup-plugin-uglify"); const BASE_PLUGINS = [ resolve({ - module: true, - main: true, - browser: true, - jsnext: true, + mainFields: ["module", "main"], preferBuiltins: true }), commonjs({ include: "node_modules/**" }), json(), - babel() + babel({ + babelrc: false, + presets: ["@babel/env"] + }) ]; const BASE_CONFIG = { input: "src/index.js", - external: ["@data-provider/core", "lodash"], + external: ["@data-provider/core"], plugins: [...BASE_PLUGINS, uglifier.uglify()] }; const GLOBALS = { - "@data-provider/core": "dataProvider", - lodash: "lodash" + "@data-provider/core": "dataProvider" }; module.exports = [ { ...BASE_CONFIG, output: { - file: "dist/data-provider-memory.cjs.js", + file: "dist/index.cjs.js", format: "cjs" } }, { ...BASE_CONFIG, output: { - file: "dist/data-provider-memory.umd.js", + file: "dist/index.umd.js", format: "umd", name: "dataProviderMemory", globals: GLOBALS @@ -61,7 +60,7 @@ module.exports = [ { ...BASE_CONFIG, output: { - file: "dist/data-provider-memory.esm.js", + file: "dist/index.esm.js", format: "esm", globals: GLOBALS }, diff --git a/sonar-project.properties b/sonar-project.properties index 5b52a73..dd606f4 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,6 +1,6 @@ sonar.organization=data-provider sonar.projectKey=data-provider-memory -sonar.projectVersion=1.4.3 +sonar.projectVersion=2.0.0-beta.1 sonar.sources=src,test sonar.exclusions=node_modules/** diff --git a/src/Memory.js b/src/Memory.js index 2802b05..fe632bd 100644 --- a/src/Memory.js +++ b/src/Memory.js @@ -10,107 +10,75 @@ Unless required by applicable law or agreed to in writing, software distributed */ import { Provider } from "@data-provider/core"; -import { cloneDeep } from "lodash"; const TAG = "memory"; -const ensureId = id => id || TAG; - -const warn = text => { - console.warn(`@data-provider/memory: ${text}`); -}; - -const deprecationWarn = text => { - warn(`Deprecation warning: ${text}`); -}; - -const traceLegacyOptions = () => { - deprecationWarn( - 'Defining "id" as second argument will be deprecated. Please provide an options object with "uuid" property' - ); -}; +class Memory extends Provider { + constructor(id, options = {}, query) { + const tags = options.tags || []; + tags.push(TAG); + super(id, { ...options, tags }, query); + this._data = this.initialState.data; + this.options._data = this._options._data || this._data; + } -const getOptions = (receivedId, receivedOptions) => { - if (receivedOptions) { - traceLegacyOptions(); - return { - ...receivedOptions, - uuid: receivedOptions.uuid || ensureId(receivedId) - }; - } else if (receivedId && typeof receivedId === "object") { - return { - ...receivedId, - uuid: receivedId.uuid || TAG - }; + get initialState() { + let initialState = this.initialStateFromOptions || {}; + if (!initialState.data) { + initialState.data = {}; + } + if (this._queriedProp) { + return { + ...initialState, + data: initialState.data[this._queriedProp] + }; + } + return initialState; } - if (receivedId) { - traceLegacyOptions(); + + get _queriedProp() { + return this.queryValue && this.queryValue.prop; } - return { - uuid: ensureId(receivedId) - }; -}; -export class Memory extends Provider { - constructor(value, receivedId, receivedOptions) { - const options = getOptions(receivedId, receivedOptions); - const tags = Array.isArray(options.tags) ? options.tags : [options.tags]; - tags.push(TAG); - const baseOptions = { - ...options, - tags - }; - if (!options.queriesDefaultValue) { - deprecationWarn( - 'Usage of "queriesDefaultValue" option is recommended to prepare your code for next major version' - ); + _cleanParentCache() { + if (this.parent) { + this.parent._cleanParentCache(); + } else { + this.cleanCache(); } - const getDefaultValue = function(query) { - const valueToReturn = value || {}; - if (query && options.queriesDefaultValue) { - return valueToReturn[query]; - } - return valueToReturn; - }; - super(null, getDefaultValue, baseOptions); - this._memory = cloneDeep(value || {}); - this.update(this._memory); } - _read(key) { - const cached = this._cache.get(key); - if (cached) { - return cached; + readMethod() { + if (this._queriedProp) { + return this._options._data[this._queriedProp]; } - const promise = Promise.resolve(key ? this._memory[key] : this._memory); - this._cache.set(key, promise); - return promise; + return this._options._data; } - _update(query, value) { - const data = cloneDeep(value); - if (query) { - this._memory[query] = data; + update(data) { + if (this._queriedProp) { + this._options._data[this._queriedProp] = data; } else { - this._memory = data; + this._options._data = data; } - this._clean(); + this._cleanParentCache(); return Promise.resolve(); } - _create(query, value) { - this._update(query, value); - this._clean(); + create(data) { + this.update(data); return Promise.resolve(); } - _delete(query) { - if (query) { - delete this._memory[query]; + delete() { + if (this._queriedProp) { + delete this._options._data[this._queriedProp]; } else { - this._memory = {}; + this._options._data = {}; } - this._clean(); + this._cleanParentCache(); return Promise.resolve(); } } + +export default Memory; diff --git a/src/index.js b/src/index.js index 57c4d98..dcf3da1 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,5 @@ /* +Copyright 2020 Javier Brea Copyright 2019 XbyOrange Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at @@ -8,4 +9,4 @@ http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -export { Memory } from "./Memory"; +export { default as Memory } from "./Memory"; diff --git a/test/index.spec.js b/test/index.spec.js index 50314cb..82fc3d2 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -1,4 +1,5 @@ /* +Copyright 2020 XbyOrange Copyright 2019 XbyOrange Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at @@ -8,10 +9,10 @@ http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -const index = require("../src/index"); +const { Memory } = require("../src/index"); describe("index", () => { it("should export the Memory constructor", () => { - expect(index.Memory).toBeDefined(); + expect(Memory).toBeDefined(); }); }); diff --git a/test/memory.spec.js b/test/memory.spec.js index bc4b3c8..64324de 100644 --- a/test/memory.spec.js +++ b/test/memory.spec.js @@ -9,12 +9,12 @@ http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -const { sources } = require("@data-provider/core"); +const { providers } = require("@data-provider/core"); const { Memory } = require("../src/index"); describe("Memory origin", () => { afterEach(() => { - sources.clear(); + providers.clear(); }); describe("Available methods", () => { @@ -37,39 +37,32 @@ describe("Memory origin", () => { it("should be true while resource is being loaded, false when finished", () => { expect.assertions(2); const promise = userData.read(); - expect(userData.read.loading).toEqual(true); + expect(userData.state.loading).toEqual(true); return promise.then(() => { - expect(userData.read.loading).toEqual(false); + expect(userData.state.loading).toEqual(false); }); }); it("should not be loading when request promise is cached", async () => { expect.assertions(3); await userData.read(); - expect(userData.read.loading).toEqual(false); + expect(userData.state.loading).toEqual(false); const secondRead = userData.read(); - expect(userData.read.loading).toEqual(false); + expect(userData.state.loading).toEqual(false); return secondRead.then(() => { - expect(userData.read.loading).toEqual(false); + expect(userData.state.loading).toEqual(false); }); }); it("should be loading again after cleaning cache", async () => { expect.assertions(3); await userData.read(); - expect(userData.read.loading).toEqual(false); - userData.clean(); + expect(userData.state.loading).toEqual(false); + userData.cleanCache(); const secondRead = userData.read(); - expect(userData.read.loading).toEqual(true); + expect(userData.state.loading).toEqual(true); return secondRead.then(() => { - expect(userData.read.loading).toEqual(false); - }); - }); - - it("should be accesible through getter", async () => { - expect.assertions(1); - return userData.read().then(() => { - expect(userData.read.getters.loading()).toEqual(false); + expect(userData.state.loading).toEqual(false); }); }); }); @@ -81,52 +74,54 @@ describe("Memory origin", () => { }; beforeEach(() => { - userData = new Memory(fooData); + userData = new Memory("foo-id", { + initialState: { + data: fooData + } + }); }); - describe("without query", () => { - it("should return default value while resource is being loaded", () => { + describe("without initialState", () => { + it("should return an empty object while resource is being loaded", () => { + userData = new Memory("foo-id-2"); expect.assertions(2); const promise = userData.read(); - expect(userData.read.value).toEqual(fooData); + expect(userData.state.data).toEqual({}); return promise.then(() => { - expect(userData.read.value).toEqual(fooData); + expect(userData.state.data).toEqual({}); }); }); - - it("should be accesible through getter", async () => { - expect.assertions(1); - await userData.read(); - expect(userData.read.getters.value()).toEqual(fooData); - }); }); - describe("when queried", () => { - it("should return default value correspondent to query while resource is being loaded if queriesDefaultValue option is set", () => { + describe("without query", () => { + it("should return default value while resource is being loaded", () => { expect.assertions(2); - userData = new Memory(fooData, "foo-id", { - queriesDefaultValue: true - }); - let queriedData = userData.query("foo"); - const promise = queriedData.read(); - expect(queriedData.read.value).toEqual(fooData.foo); + const promise = userData.read(); + expect(userData.state.data).toEqual(fooData); return promise.then(() => { - expect(queriedData.read.value).toEqual(fooData.foo); + expect(userData.state.data).toEqual(fooData); }); }); + }); - it("should return root default value if queriesDefaultValue option is not set", () => { + describe("when queried", () => { + it("should return default value correspondent to query while resource is being loaded", () => { expect.assertions(2); - let queriedData = userData.query("foo"); + userData = new Memory("foo-id-2", { + initialState: { + data: fooData + } + }); + let queriedData = userData.query({ prop: "foo" }); const promise = queriedData.read(); - expect(queriedData.read.value).toEqual(fooData); - return promise.then(() => { - expect(queriedData.read.value).toEqual(fooData.foo); + expect(queriedData.state.data).toEqual(fooData.foo); + return promise.then(value => { + expect(value).toEqual(fooData.foo); }); }); it("should return the property corresponding to applied query", async () => { - let queriedData = userData.query("foo"); + let queriedData = userData.query({ prop: "foo" }); const result = await queriedData.read(); expect(result).toEqual("foo-value"); }); @@ -140,20 +135,24 @@ describe("Memory origin", () => { }; beforeEach(() => { - userData = new Memory(fooData); + userData = new Memory("foo-id", { + initialState: { + data: fooData + } + }); }); describe("without query", () => { it("should clean the cache when finish successfully", async () => { expect.assertions(3); let promise = userData.read(); - expect(userData.read.loading).toEqual(true); + expect(userData.state.loading).toEqual(true); await promise; await userData.update(""); promise = userData.read(); - expect(userData.read.loading).toEqual(true); + expect(userData.state.loading).toEqual(true); return promise.then(() => { - expect(userData.read.loading).toEqual(false); + expect(userData.state.loading).toEqual(false); }); }); @@ -166,8 +165,8 @@ describe("Memory origin", () => { }); describe("when queried", () => { - it("should set the property corresponding to applied query", async () => { - let queriedData = userData.query("foo"); + it("should set the property corresponding to applied query in parent", async () => { + let queriedData = userData.query({ prop: "foo" }); await queriedData.update("foo-updated-value"); const value = await userData.read(); expect(value).toEqual({ @@ -175,16 +174,23 @@ describe("Memory origin", () => { }); }); + it("should set the property corresponding to applied query", async () => { + let queriedData = userData.query({ prop: "foo" }); + await queriedData.update("foo-updated-value"); + const value = await queriedData.read(); + expect(value).toEqual("foo-updated-value"); + }); + it("should clean the cache of root when finish successfully", async () => { expect.assertions(3); let promise = userData.read(); - expect(userData.read.loading).toEqual(true); + expect(userData.state.loading).toEqual(true); await promise; - await userData.query("foo").update(""); + await userData.query({ prop: "foo" }).update(""); promise = userData.read(); - expect(userData.read.loading).toEqual(true); + expect(userData.state.loading).toEqual(true); return promise.then(() => { - expect(userData.read.loading).toEqual(false); + expect(userData.state.loading).toEqual(false); }); }); }); @@ -198,28 +204,39 @@ describe("Memory origin", () => { }; beforeEach(() => { - userData = new Memory(fooData); + userData = new Memory("foo-id-2", { + initialState: { + data: fooData + } + }); }); - it("should delete the property corresponding to applied query", async () => { - let queriedData = userData.query("foo"); + it("should delete the property corresponding to applied query in parent", async () => { + let queriedData = userData.query({ prop: "foo" }); await queriedData.delete(); await userData.read(); - expect(userData.read.value).toEqual({ + expect(userData.state.data).toEqual({ foo2: "foo-value-2" }); }); + it("should delete the property corresponding to applied query", async () => { + let queriedData = userData.query({ prop: "foo" }); + await queriedData.delete(); + await queriedData.read(); + expect(queriedData.state.data).toEqual(undefined); + }); + it("should clean the cache when finish successfully", async () => { expect.assertions(3); let promise = userData.read(); - expect(userData.read.loading).toEqual(true); + expect(userData.state.loading).toEqual(true); await promise; await userData.delete(); promise = userData.read(); - expect(userData.read.loading).toEqual(true); + expect(userData.state.loading).toEqual(true); return promise.then(() => { - expect(userData.read.loading).toEqual(false); + expect(userData.state.loading).toEqual(false); }); }); }); @@ -231,131 +248,90 @@ describe("Memory origin", () => { }; beforeEach(() => { - userData = new Memory(fooData); + userData = new Memory("foo-memory-create", { + initialState: { + data: fooData + } + }); }); it("should clean the cache when finish successfully", async () => { expect.assertions(3); let promise = userData.read(); - expect(userData.read.loading).toEqual(true); + expect(userData.state.loading).toEqual(true); await promise; await userData.create("foo-new"); promise = userData.read(); - expect(userData.read.loading).toEqual(true); + expect(userData.state.loading).toEqual(true); return promise.then(() => { - expect(userData.read.loading).toEqual(false); + expect(userData.state.loading).toEqual(false); }); }); - it("should add the new key", async () => { - await userData.query("foo2").create("foo-new"); + it("should add the new prop in parent", async () => { + await userData.query({ prop: "foo2" }).create("foo-new"); const value = await userData.read(); expect(value).toEqual({ foo: "foo-value", foo2: "foo-new" }); }); - }); - - describe("Instance id", () => { - it("should be assigned based on second parameter", () => { - const FOO_ID = "foo-id"; - const fooData = new Memory(null, FOO_ID); - expect(sources.getById(FOO_ID).elements[0]).toEqual(fooData); - }); - it("should be assigned based on uuid option if provided", () => { - const FOO_ID = "foo-id"; - const fooData = new Memory(null, "foo-fake-id", { - uuid: FOO_ID - }); - expect(sources.getById(FOO_ID).elements[0]).toEqual(fooData); + it("should add the new prop", async () => { + await userData.query({ prop: "foo2" }).create("foo-new"); + const value = await userData.query({ prop: "foo2" }).read(); + expect(value).toEqual("foo-new"); }); + }); - it("should be assigned based on uuid option if provided as second argument", () => { + describe("Instance id", () => { + it("should be assigned based on first argument", () => { const FOO_ID = "foo-id"; - const fooData = new Memory(null, { - uuid: FOO_ID - }); - expect(sources.getById(FOO_ID).elements[0]).toEqual(fooData); + const fooData = new Memory(FOO_ID); + expect(providers.getById(FOO_ID).elements[0]).toEqual(fooData); }); }); describe("Instance tags", () => { describe("when no options are defined", () => { it("should contain the memory tag", () => { - const fooData = new Memory(null); - expect(sources.getByTag("memory").elements[0]).toEqual(fooData); + const fooData = new Memory("foo"); + expect(providers.getByTag("memory").elements[0]).toEqual(fooData); }); }); describe("when passing options as second argument", () => { it("should contain the memory tag even when a custom tag is received", () => { - const fooData = new Memory(null, { - tags: "foo-tag" - }); - expect(sources.getByTag("memory").elements[0]).toEqual(fooData); - }); - - it("should contain the memory tag even when an array of custom tags is received", () => { - const fooData = new Memory(null, { - tags: ["foo-tag", "foo-tag-2"] - }); - expect(sources.getByTag("memory").elements[0]).toEqual(fooData); - }); - - it("should contain defined custom tag if received", () => { - const FOO_TAG = "foo-tag"; - const fooData = new Memory(null, { - tags: FOO_TAG - }); - expect(sources.getByTag(FOO_TAG).elements[0]).toEqual(fooData); - }); - - it("should contain defined custom tags if received", () => { - expect.assertions(2); - const FOO_TAG = "foo-tag"; - const FOO_TAG_2 = "foo-tag-2"; - const fooData = new Memory(null, { - tags: [FOO_TAG, FOO_TAG_2] - }); - expect(sources.getByTag(FOO_TAG).elements[0]).toEqual(fooData); - expect(sources.getByTag(FOO_TAG_2).elements[0]).toEqual(fooData); - }); - }); - - describe("when passing options as third argument", () => { - it("should contain the memory tag even when a custom tag is received", () => { - const fooData = new Memory(null, "foo-fake-id", { - tags: "foo-tag" + const fooData = new Memory("foo", { + tags: ["foo-tag"] }); - expect(sources.getByTag("memory").elements[0]).toEqual(fooData); + expect(providers.getByTag("memory").elements[0]).toEqual(fooData); }); it("should contain the memory tag even when an array of custom tags is received", () => { - const fooData = new Memory(null, "foo-fake-id", { + const fooData = new Memory("foo", { tags: ["foo-tag", "foo-tag-2"] }); - expect(sources.getByTag("memory").elements[0]).toEqual(fooData); + expect(providers.getByTag("memory").elements[0]).toEqual(fooData); }); it("should contain defined custom tag if received", () => { const FOO_TAG = "foo-tag"; - const fooData = new Memory(null, "foo-fake-id", { - tags: FOO_TAG + const fooData = new Memory("foo", { + tags: [FOO_TAG] }); - expect(sources.getByTag(FOO_TAG).elements[0]).toEqual(fooData); + expect(providers.getByTag(FOO_TAG).elements[0]).toEqual(fooData); }); it("should contain defined custom tags if received", () => { expect.assertions(2); const FOO_TAG = "foo-tag"; const FOO_TAG_2 = "foo-tag-2"; - const fooData = new Memory(null, "foo-fake-id", { + const fooData = new Memory("foo", { tags: [FOO_TAG, FOO_TAG_2] }); - expect(sources.getByTag(FOO_TAG).elements[0]).toEqual(fooData); - expect(sources.getByTag(FOO_TAG_2).elements[0]).toEqual(fooData); + expect(providers.getByTag(FOO_TAG).elements[0]).toEqual(fooData); + expect(providers.getByTag(FOO_TAG_2).elements[0]).toEqual(fooData); }); }); });