From 0182aad5c591f18ee96068878dc5cdf2277dfc9c Mon Sep 17 00:00:00 2001 From: Dan Knutsen Date: Sat, 6 Apr 2019 20:15:08 -0500 Subject: [PATCH 1/2] Add yuidoc annotations and options arguments - find-all and find-record helpers now can take an "options" hash - add yuidoc annotations to needs-async component and all helpers --- addon/components/needs-async.js | 24 ++++++++++ addon/helpers/async-all.js | 14 ++++++ addon/helpers/async-hash.js | 14 ++++++ addon/helpers/belongs-to.js | 12 +++++ addon/helpers/find-all.js | 20 ++++++-- addon/helpers/find-record.js | 21 +++++++-- addon/helpers/has-many.js | 12 +++++ addon/helpers/peek-all.js | 11 +++++ addon/helpers/peek-record.js | 12 +++++ addon/helpers/query.js | 12 +++++ package-lock.json | 47 +++++-------------- tests/integration/helpers/find-all-test.js | 22 +++++++++ tests/integration/helpers/find-record-test.js | 22 +++++++++ 13 files changed, 201 insertions(+), 42 deletions(-) diff --git a/addon/components/needs-async.js b/addon/components/needs-async.js index 7eb1d6e..8e6ad0d 100644 --- a/addon/components/needs-async.js +++ b/addon/components/needs-async.js @@ -1,6 +1,30 @@ import Component from '@ember/component'; import layout from '../templates/components/needs-async'; +/** + Usage: + + ```hbs + + + + + + + + + + + + ``` + + @class NeedsAsync + @yield {Hash} States + @yield {TaskInstance} States.taskInstance an Ember Concurrency TaskInstance + @yield {Component} States.loading a component that renders its block if the task instance is still loading + @yield {Component} States.loaded a component that renders its block and yields the task value once the task is done loading + @yield {Component} States.error a component that renders its block and yields an error if the tak encountered an error +*/ export default Component.extend({ layout, tagName: '', diff --git a/addon/helpers/async-all.js b/addon/helpers/async-all.js index 1eda651..5cba544 100644 --- a/addon/helpers/async-all.js +++ b/addon/helpers/async-all.js @@ -1,6 +1,20 @@ import Helper from '@ember/component/helper'; import { all, task } from 'ember-concurrency'; +/** + Usage: + + ```hbs + {{async-all (array + (find-record "user" "1") + (find-record "user" "2") + )}} + ``` + + @function async-all + @param {array} taskInstances an array of Ember Concurrency task instances + @return {TaskInstance} a TaskInstance that resolves to an array of TaskInstance results +*/ export default Helper.extend({ asyncAllTask: task(function * (tasks) { return yield all(tasks); diff --git a/addon/helpers/async-hash.js b/addon/helpers/async-hash.js index 967ec0e..58d630a 100644 --- a/addon/helpers/async-hash.js +++ b/addon/helpers/async-hash.js @@ -1,6 +1,20 @@ import Helper from '@ember/component/helper'; import { hash, task } from 'ember-concurrency'; +/** + Usage: + + ```hbs + {{async-hash (hash + foo=(find-record "user" "1") + bar=(find-record "user" "2") + )}} + ``` + + @function async-hash + @param {array} taskInstances an array of Ember Concurrency task instances + @return {TaskInstance} a TaskInstance that resolves to a hash of TaskInstance results +*/ export default Helper.extend({ asyncHashTask: task(function * (tasks) { return yield hash(tasks); diff --git a/addon/helpers/belongs-to.js b/addon/helpers/belongs-to.js index 582e8b0..fb0464f 100644 --- a/addon/helpers/belongs-to.js +++ b/addon/helpers/belongs-to.js @@ -1,6 +1,18 @@ import Helper from '@ember/component/helper'; import { task } from 'ember-concurrency'; +/** + Usage: + + ```hbs + {{belongs-to user "company"}} + ``` + + @function belongs-to + @param {DS.Model} model the model to fetch the belongs-to relationship from + @param {string} relationship the name of the relationship to fetch + @return {TaskInstance} a TaskInstance that resolves to a DS.Model +*/ export default Helper.extend({ belongsToTask: task(function * (model, relationship) { return yield model.belongsTo(relationship).load(); diff --git a/addon/helpers/find-all.js b/addon/helpers/find-all.js index 6318cfb..2eab262 100644 --- a/addon/helpers/find-all.js +++ b/addon/helpers/find-all.js @@ -2,12 +2,24 @@ import Helper from '@ember/component/helper'; import { inject as service } from '@ember/service'; import { task } from 'ember-concurrency'; +/** + Usage: + + ```hbs + {{find-all "user" (hash include="company")}} + ``` + + @function find-all + @param {string} modelType the model type to request + @param {object} options (optional) options to pass to the store.findAll method + @return {TaskInstance} a TaskInstance that resolves to a DS.RecordArray +*/ export default Helper.extend({ store: service(), - findAllTask: task(function * (modelType) { - return yield this.store.findAll(modelType); + findAllTask: task(function * (modelType, options) { + return yield this.store.findAll(modelType, options); }), - compute([modelType/*, ...rest*/]/*, hash*/) { - return this.findAllTask.perform(modelType); + compute([modelType, options/*, ...rest*/]/*, hash*/) { + return this.findAllTask.perform(modelType, options); } }); diff --git a/addon/helpers/find-record.js b/addon/helpers/find-record.js index eacd10b..9ead9d9 100644 --- a/addon/helpers/find-record.js +++ b/addon/helpers/find-record.js @@ -2,13 +2,26 @@ import Helper from '@ember/component/helper'; import { inject as service } from '@ember/service'; import { task } from 'ember-concurrency'; +/** + Usage: + + ```hbs + {{find-record "user" "1" (hash include="company")}} + ``` + + @function find-all + @param {string} modelType the model type to request + @param {string} id the id of the model to request + @param {object} options (optional) options to pass to the store.findRecord method + @return {Promise} a promise that resolves to a DS.Model +*/ export default Helper.extend({ store: service(), - findRecordTask: task(function * (modelType, id) { - return yield this.store.findRecord(modelType, id); + findRecordTask: task(function * (modelType, id, options) { + return yield this.store.findRecord(modelType, id, options); }), - compute([modelType, id/*, ...rest*/]/*, hash*/) { + compute([modelType, id, options/*, ...rest*/]/*, hash*/) { if(!id) return null; - return this.findRecordTask.perform(modelType, id); + return this.findRecordTask.perform(modelType, id, options); } }); diff --git a/addon/helpers/has-many.js b/addon/helpers/has-many.js index b1d2c96..4088b6f 100644 --- a/addon/helpers/has-many.js +++ b/addon/helpers/has-many.js @@ -1,6 +1,18 @@ import Helper from '@ember/component/helper'; import { task } from 'ember-concurrency'; +/** + Usage: + + ```hbs + {{has-many company "employees"}} + ``` + + @function has-many + @param {DS.Model} model the model to fetch the has-many relationship from + @param {string} relationship the name of the relationship to fetch + @return {TaskInstance} a TaskInstance that resolves to a DS.RecordArray +*/ export default Helper.extend({ hasManyTask: task(function * (model, relationship) { return yield model.hasMany(relationship).load(); diff --git a/addon/helpers/peek-all.js b/addon/helpers/peek-all.js index 897cedd..34c1708 100644 --- a/addon/helpers/peek-all.js +++ b/addon/helpers/peek-all.js @@ -2,6 +2,17 @@ import Helper from '@ember/component/helper'; import { inject as service } from '@ember/service'; import { task } from 'ember-concurrency'; +/** + Usage: + + ```hbs + {{peek-all "user"}} + ``` + + @function peek-all + @param {string} modelType the model type to request + @return {TaskInstance} a TaskInstance that resolves immediately to a DS.RecordArray +*/ export default Helper.extend({ store: service(), peekAllTask: task(function * (modelType) { diff --git a/addon/helpers/peek-record.js b/addon/helpers/peek-record.js index b94292b..7350af9 100644 --- a/addon/helpers/peek-record.js +++ b/addon/helpers/peek-record.js @@ -2,6 +2,18 @@ import Helper from '@ember/component/helper'; import { inject as service } from '@ember/service'; import { task } from 'ember-concurrency'; +/** + Usage: + + ```hbs + {{peek-record "user" "1"}} + ``` + + @function peek-record + @param {string} modelType the model type to request + @param {string} id the id of the model to fetch from the store + @return {TaskInstance} a TaskInstance that resolves immediately to a DS.Model +*/ export default Helper.extend({ store: service(), peekRecordTask: task(function * (modelType, id) { diff --git a/addon/helpers/query.js b/addon/helpers/query.js index 7d690d2..45f117e 100644 --- a/addon/helpers/query.js +++ b/addon/helpers/query.js @@ -2,6 +2,18 @@ import Helper from '@ember/component/helper'; import { inject as service } from '@ember/service'; import { task } from 'ember-concurrency'; +/** + Usage: + + ```hbs + {{query "user" (hash lastName="smith" page=2)}} + ``` + + @function query + @param {string} modelType the model type to request + @param {object} query the hash that includes all params for the query + @return {TaskInstance} a TaskInstance that resolves to a DS.RecordArray +*/ export default Helper.extend({ store: service(), queryTask: task(function * (modelType, hash) { diff --git a/package-lock.json b/package-lock.json index 3c15e5e..8c1035e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "ember-needs-async", - "version": "0.2.1", + "version": "0.2.2", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -3115,7 +3115,6 @@ "resolved": "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz", "integrity": "sha1-emNune1O/O+xnO9JR6PGffrukRs=", "dev": true, - "optional": true, "requires": { "hoek": "0.9.x" }, @@ -3124,8 +3123,7 @@ "version": "0.9.1", "resolved": "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz", "integrity": "sha1-PTIkYrrfB3Fup+uFuviAec3c5QU=", - "dev": true, - "optional": true + "dev": true } } }, @@ -13349,8 +13347,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -13374,15 +13371,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -13399,22 +13394,19 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -13545,8 +13537,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -13560,7 +13551,6 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -13577,7 +13567,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -13586,15 +13575,13 @@ "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -13615,7 +13602,6 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -13704,8 +13690,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -13719,7 +13704,6 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -13815,8 +13799,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -13858,7 +13841,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -13880,7 +13862,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -13929,15 +13910,13 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", - "dev": true, - "optional": true + "dev": true } } }, diff --git a/tests/integration/helpers/find-all-test.js b/tests/integration/helpers/find-all-test.js index d765e81..e6c39f8 100644 --- a/tests/integration/helpers/find-all-test.js +++ b/tests/integration/helpers/find-all-test.js @@ -36,6 +36,28 @@ module('Integration | Helper | find-all', function(hooks) { assert.equal(this.element.textContent.trim(), users.map(u => u.firstName).join(''), 'it exposes the model as the value when loaded'); }); + test('it correctly passes findAll options to the backend', async function(assert) { + assert.expect(1); + + server.timing = 100; + server.get('/users', (schema, request) => { + assert.equal(request.queryParams.include, 'company', 'the include paramter is passed to the backend'); + return schema.users.all(); + }); + + server.create('user'); + this.set('modelType', 'user'); + + await render(hbs` +
+ {{#let (find-all modelType (hash include="company")) as |taskInstance|}} + {{#if taskInstance.isRunning}}loading{{/if}} + {{#if taskInstance.value}}{{taskInstance.value.firstObject.firstName}}{{/if}} + {{/let}} +
+ `); + }); + // TODO: there's probably a much better way to test this test('it properly requests a model and exposes the task instance with error state', async function(assert) { server.get('/users', {errors: ['There was an error']}, 500); diff --git a/tests/integration/helpers/find-record-test.js b/tests/integration/helpers/find-record-test.js index 5eca726..d230e2f 100644 --- a/tests/integration/helpers/find-record-test.js +++ b/tests/integration/helpers/find-record-test.js @@ -34,6 +34,28 @@ module('Integration | Helper | find-record', function(hooks) { assert.equal(this.element.textContent.trim(), user.firstName, 'it exposes the model as the value when loaded'); }); + test('it correctly passes an options hash to the findRecord method', async function(assert) { + assert.expect(1); + + server.timing = 100; + server.get('/users/:id', (schema, request) => { + assert.equal(request.queryParams.include, 'company', 'the include paramter is passed to the backend'); + return schema.users.find(request.params.id); + }); + + server.create('user'); + this.set('modelType', 'user'); + this.set('id', '1'); + + await render(hbs` +
+ {{#let (find-record modelType id (hash include="company")) as |taskInstance|}} + {{#if taskInstance.isRunning}}loading{{/if}} + {{#if taskInstance.value}}{{taskInstance.value.firstName}}{{/if}} + {{/let}} +
+ `); + }); // TODO: there's probably a much better way to test this test('it properly requests a model and exposes the task instance with error state', async function(assert) { From fde725d2461606765dba7e79321019ff0e089005 Mon Sep 17 00:00:00 2001 From: Dan Knutsen Date: Sat, 6 Apr 2019 20:17:11 -0500 Subject: [PATCH 2/2] 0.2.3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8c1035e..df3cdeb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "ember-needs-async", - "version": "0.2.2", + "version": "0.2.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index caf2c50..3e8d4cc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-needs-async", - "version": "0.2.2", + "version": "0.2.3", "description": "Declarative, composable primitives for loading and rendering async data directly from templates.", "keywords": [ "ember-addon"