├── .editorconfig
├── .ember-cli
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .npmignore
├── .travis.yml
├── .watchmanconfig
├── CHANGELOG.md
├── LICENSE
├── LICENSE.md
├── README.md
├── addon-test-support
└── qunit.js
├── addon
├── model.js
├── models
│ ├── filtered-record-array.js
│ ├── record-array.js
│ └── record-proxy.js
├── store.js
└── uuid.js
├── app
└── services
│ └── simple-store.js
├── config
├── ember-try.js
└── environment.js
├── ember-cli-build.js
├── index.js
├── package.json
├── testem.js
├── tests
├── .eslintrc.js
├── acceptance
│ ├── a-defaults-test.js
│ ├── a-test.js
│ ├── arrays-test.js
│ ├── b-defaults-test.js
│ ├── b-test.js
│ ├── delete-object-test.js
│ ├── edit-test.js
│ ├── filters-test.js
│ ├── isnone-test.js
│ ├── relationships-test.js
│ └── x-defaults-test.js
├── dummy
│ ├── app
│ │ ├── app.js
│ │ ├── components
│ │ │ └── .gitkeep
│ │ ├── controllers
│ │ │ ├── .gitkeep
│ │ │ ├── delete-object.js
│ │ │ └── relationships.js
│ │ ├── helpers
│ │ │ ├── .gitkeep
│ │ │ └── is-equal.js
│ │ ├── index.html
│ │ ├── models
│ │ │ ├── .gitkeep
│ │ │ ├── custom-key.js
│ │ │ ├── foo.js
│ │ │ ├── robot.js
│ │ │ ├── role.js
│ │ │ ├── user.js
│ │ │ ├── wat.js
│ │ │ ├── wow.js
│ │ │ ├── zap.js
│ │ │ └── zing.js
│ │ ├── resolver.js
│ │ ├── router.js
│ │ ├── routes
│ │ │ ├── .gitkeep
│ │ │ ├── arrays.js
│ │ │ ├── custom-key.js
│ │ │ ├── defaulta.js
│ │ │ ├── defaultb.js
│ │ │ ├── defaultx.js
│ │ │ ├── delete-object.js
│ │ │ ├── edit.js
│ │ │ ├── filters.js
│ │ │ ├── isnone.js
│ │ │ ├── relationships.js
│ │ │ ├── robots.js
│ │ │ └── wat.js
│ │ ├── styles
│ │ │ └── app.css
│ │ └── templates
│ │ │ ├── application.hbs
│ │ │ ├── arrays.hbs
│ │ │ ├── custom-key.hbs
│ │ │ ├── defaulta.hbs
│ │ │ ├── defaultb.hbs
│ │ │ ├── defaultx.hbs
│ │ │ ├── delete-object.hbs
│ │ │ ├── edit.hbs
│ │ │ ├── filters.hbs
│ │ │ ├── isnone.hbs
│ │ │ ├── relationships.hbs
│ │ │ ├── robots.hbs
│ │ │ └── wat.hbs
│ ├── config
│ │ ├── environment.js
│ │ └── targets.js
│ └── public
│ │ └── robots.txt
├── helpers
│ ├── .gitkeep
│ ├── destroy-app.js
│ ├── module-for-acceptance.js
│ ├── qunit.js
│ ├── registration.js
│ ├── resolver.js
│ └── start-app.js
├── index.html
├── test-helper.js
└── unit
│ ├── arrays-test.js
│ ├── default-attr-test.js
│ ├── model-test.js
│ ├── record-array-test.js
│ ├── relationship-test.js
│ ├── service-test.js
│ └── store-test.js
├── vendor
└── .gitkeep
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 |
8 | [*]
9 | end_of_line = lf
10 | charset = utf-8
11 | trim_trailing_whitespace = true
12 | insert_final_newline = true
13 | indent_style = space
14 | indent_size = 2
15 |
16 | [*.hbs]
17 | insert_final_newline = false
18 |
19 | [*.{diff,md}]
20 | trim_trailing_whitespace = false
21 |
--------------------------------------------------------------------------------
/.ember-cli:
--------------------------------------------------------------------------------
1 | {
2 | /**
3 | Ember CLI sends analytics information by default. The data is completely
4 | anonymous, but there are times when you might want to disable this behavior.
5 |
6 | Setting `disableAnalytics` to true will prevent any data from being sent.
7 | */
8 | "disableAnalytics": false
9 | }
10 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | # unconventional js
2 | /blueprints/*/files/
3 | /vendor/
4 |
5 | # compiled output
6 | /dist/
7 | /tmp/
8 |
9 | # dependencies
10 | /bower_components/
11 |
12 | # misc
13 | /coverage/
14 |
15 | # ember-try
16 | /.node_modules.ember-try/
17 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parserOptions: {
4 | ecmaVersion: 2017,
5 | sourceType: 'module'
6 | },
7 | plugins: [
8 | 'ember'
9 | ],
10 | extends: [
11 | 'eslint:recommended',
12 | 'plugin:ember/recommended'
13 | ],
14 | env: {
15 | browser: true
16 | },
17 | rules: {
18 | },
19 | overrides: [
20 | // node files
21 | {
22 | files: [
23 | 'ember-cli-build.js',
24 | 'index.js',
25 | 'testem.js',
26 | 'blueprints/*/index.js',
27 | 'config/**/*.js',
28 | 'tests/dummy/config/**/*.js'
29 | ],
30 | excludedFiles: [
31 | 'addon/**',
32 | 'addon-test-support/**',
33 | 'app/**',
34 | 'tests/dummy/app/**'
35 | ],
36 | parserOptions: {
37 | sourceType: 'script',
38 | ecmaVersion: 2015
39 | },
40 | env: {
41 | browser: false,
42 | node: true
43 | },
44 | plugins: ['node'],
45 | rules: Object.assign({}, require('eslint-plugin-node').configs.recommended.rules, {
46 | // add your custom rules and overrides for node files here
47 | })
48 | }
49 | ]
50 | };
51 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # compiled output
4 | /dist/
5 | /tmp/
6 |
7 | # dependencies
8 | /bower_components/
9 | /node_modules/
10 |
11 | # misc
12 | /.sass-cache
13 | /connect.lock
14 | /coverage/
15 | /libpeerconnection.log
16 | /npm-debug.log*
17 | /testem.log
18 | /yarn-error.log
19 |
20 | # ember-try
21 | /.node_modules.ember-try/
22 | /bower.json.ember-try
23 | /package.json.ember-try
24 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | /bower_components
2 | /config/ember-try.js
3 | /dist
4 | /tests
5 | /tmp
6 | **/.gitkeep
7 | .bowerrc
8 | .editorconfig
9 | .ember-cli
10 | .eslintrc.js
11 | .gitignore
12 | .watchmanconfig
13 | .travis.yml
14 | bower.json
15 | ember-cli-build.js
16 | testem.js
17 | yarn.lock
18 |
19 | # ember-try
20 | .node_modules.ember-try/
21 | bower.json.ember-try
22 | package.json.ember-try
23 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | ---
2 | language: node_js
3 | node_js:
4 | - "6"
5 |
6 | sudo: false
7 | dist: trusty
8 |
9 | addons:
10 | chrome: stable
11 |
12 | cache:
13 | yarn: true
14 |
15 | env:
16 | - EMBER_TRY_SCENARIO=ember-lts-2.12
17 | - EMBER_TRY_SCENARIO=ember-2.18.X
18 | - EMBER_TRY_SCENARIO=ember-3.1.X
19 | - EMBER_TRY_SCENARIO=ember-3.3.X
20 | - EMBER_TRY_SCENARIO=ember-3.4.X
21 | - EMBER_TRY_SCENARIO=ember-3.7.X
22 |
23 | before_install:
24 | - curl -o- -L https://yarnpkg.com/install.sh | bash
25 | - export PATH=$HOME/.yarn/bin:$PATH
26 |
27 | install:
28 | - yarn install --no-lockfile --non-interactive
29 |
30 | script:
31 | - yarn lint:js
32 | - node_modules/.bin/ember try:one $EMBER_TRY_SCENARIO --skip-cleanup
33 |
--------------------------------------------------------------------------------
/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {
2 | "ignore_dirs": ["tmp", "dist"]
3 | }
4 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ember-cli-simple-store Changelog
2 | ==============================
3 |
4 | 5.9.4
5 | -----
6 |
7 | * [DEPENDENCY]: fix for ember v3.4+ ([#91](https://github.com/toranb/ember-cli-simple-store/pull/91))
8 |
9 | 5.9.3
10 | -----
11 |
12 | * [DEPENDENCY]: upgrade to ember v3.1.1
13 |
14 | 5.9.2
15 | -----
16 |
17 | * [WORKAROUND]: ember v3.1 compatability with proxy
18 |
19 | 5.9.1
20 | -----
21 |
22 | * [DEPENDENCY]: update ember-runtime-enumerable-includes-polyfill to 2.1.0
23 |
24 | 5.9.0
25 | -----
26 |
27 | * [DEPENDENCY]: upgrade to 3.0 ([#83](https://github.com/toranb/ember-cli-simple-store/pull/83))
28 |
29 | * [UPDATE]: removed ember-uuid dependency ([commit](https://github.com/toranb/ember-cli-simple-store/commit/5c0fff4411b0641953882d11cb815bd8a0f6a58f))
30 |
31 | 5.8.0
32 | -----
33 |
34 | * [UPDATE]: testing updates ([#82](https://github.com/toranb/ember-cli-simple-store/pull/82))
35 |
36 | 5.7.0
37 | -----
38 |
39 | * [DEPENDENCY]: upgrade to ember 2.15.0 ([#80](https://github.com/toranb/ember-cli-simple-store/pull/80))
40 |
41 | * [CLEANUP]: ember-codemod based on #176 RFC ([#80](https://github.com/toranb/ember-cli-simple-store/pull/80))
42 |
43 | 5.6.0
44 | -----
45 |
46 | * [DEPENDENCY]: upgrade to ember-cli v2.13.2
47 | ([#78](https://github.com/toranb/ember-cli-simple-store/pull/78))
48 |
49 | 5.5.0
50 | -----
51 |
52 | * [BUILD]: update to ember-cli v2.10.1
53 | ([#76](https://github.com/toranb/ember-cli-simple-store/pull/76))
54 |
55 | * [BUG]: Change how dependent keys are registered on isDirty computed property
56 | ([#75](https://github.com/toranb/ember-cli-simple-store/pull/75))
57 |
58 | * [EMBER]: upgraded to ember 1.13.13
59 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/365c30a2cbc731e33d9ea9dcfd3f28892f0ab2ff))
60 |
61 | * [DEPRECATION]: use factoryFor
62 | ([#73](https://github.com/toranb/ember-cli-simple-store/pull/73))
63 |
64 | 5.4.0
65 | -----
66 |
67 | * [DOCS]: updated README to reflect pushArray api
68 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/b560d78f34751c7a483a435827549275dca152d5))
69 |
70 | * [FEATURE]: added pushArray api
71 | ([#71](https://github.com/toranb/ember-cli-simple-store/pull/71))
72 |
73 | 5.3.0
74 | -----
75 |
76 | * [DEPENDENCY]: updated ember-getowner-polyfill
77 | ([#70](https://github.com/toranb/ember-cli-simple-store/pull/70))
78 |
79 | * [UPDATE]: equal function to work with jquery && jquery 3.0 and above
80 | ([#68](https://github.com/toranb/ember-cli-simple-store/pull/68))
81 |
82 | 5.2.0
83 | -----
84 |
85 | * [BUG]: On willDestroy event set object/array refs are null
86 | ([#65](https://github.com/toranb/ember-cli-simple-store/pull/65))
87 |
88 | 5.1.0
89 | -----
90 |
91 | * [DEP WARNINGS]: fix w/ enumerable contains polyfill
92 | ([#64](https://github.com/toranb/ember-cli-simple-store/pull/64))
93 |
94 |
95 | 5.0.0
96 | -----
97 |
98 | * [CLEANUP]: removed find with filter dep warning
99 | ([#62](https://github.com/toranb/ember-cli-simple-store/pull/62))
100 |
101 | * [FEATURE]: remove and clear invoke destroy on the record
102 | ([#61](https://github.com/toranb/ember-cli-simple-store/pull/61))
103 |
104 |
105 | 4.3.0
106 | -----
107 |
108 | * [BUG]: Fix coerceId function and push record with coerced ids
109 | ([#59](https://github.com/toranb/ember-cli-simple-store/pull/59))
110 |
111 |
112 | 4.2.0
113 | -----
114 |
115 | * [BUG]: Switch the names of the properties on a record proxy to avoid collisions with defined values
116 | ([#57](https://github.com/toranb/ember-cli-simple-store/pull/57))
117 |
118 |
119 | 4.1.0
120 | -----
121 |
122 | * [FEATURE]: Add support for custom id properties
123 | ([#53](https://github.com/toranb/ember-cli-simple-store/pull/53))
124 |
125 |
126 | 4.0.1
127 | -----
128 |
129 | * [DOCS]: added ember 2.4 example app to the readme
130 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/71f1b02517291b88738deb5d92f6d891d595802e))
131 |
132 | * [DOCS]: Removing obsolete installation documentation
133 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/38e4a82c680662d65cbe3e556e065b162adf9919))
134 |
135 |
136 | 4.0.0
137 | -----
138 |
139 | * [DOCS]: updated the readme to be v4.0.0 friendly
140 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/1c7bbebf83a0cebca9bc5389f89670a3be6cb4dd))
141 |
142 | * [DEPRECATION]: added find with filter api dep warning for 3rd arg
143 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/f0ac6db144f3597876ab3fdb203e2909f47c5ddd))
144 |
145 | * [REFACTOR]: removed the unsubscribe api (never released) in favor of destroy
146 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/d1eeeb62f628b70d7a396178df6beb293809087c))
147 |
148 | * [REFACTOR]: Unsubscribe on destroy of record array
149 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/22908b22932e99772fc87ce66b5831c4dc48788c))
150 |
151 | * [REFACTOR]: Consider better compatability with ember-data
152 | ([#45](https://github.com/toranb/ember-cli-simple-store/issues/45))
153 |
154 | * [REFACTOR]: Expose Store as an Ember Service
155 | ([#44](https://github.com/toranb/ember-cli-simple-store/issues/44))
156 |
157 | * [REFACTOR]: Adding record proxy type
158 | ([#43](https://github.com/toranb/ember-cli-simple-store/issues/43))
159 |
160 | * [REFACTOR]: Fixing run loop scheduling
161 | ([#40](https://github.com/toranb/ember-cli-simple-store/issues/40))
162 |
163 | * [REFACTOR]: Removing bind and jQuery dep from store
164 | ([#39](https://github.com/toranb/ember-cli-simple-store/issues/39))
165 |
166 | * [REFACTOR]: Creating types for record array proxy
167 | ([#37](https://github.com/toranb/ember-cli-simple-store/issues/37))
168 |
169 | * [FEATURE]: v4.0.0 to improve performance
170 | ([#38](https://github.com/toranb/ember-cli-simple-store/issues/38))
171 |
172 |
173 | 3.6.0
174 | -----
175 |
176 | * [DOCS]: Update README.md
177 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/d7bc3808325785cd61f80707fb4db1e41c7e1d68))
178 |
179 | * [FEATURE]: Conditionally disable initializer
180 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/edf2d41b60ab2959224146dee4169e9805189a7a))
181 |
182 | * [DEPENDENCY]: Lock jQuery to 1.11.3
183 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/16de403f8b2eb7e3f115a83f8ff8f6402d02243c))
184 |
185 | * [DOCS]: Fix readme examples
186 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/2de430133dd9345de0034124880bf1c42fcef451))
187 |
188 |
189 | 3.5.0
190 | -----
191 |
192 | * [REFACTOR]: removed the duplicate ArrayProxy (filter w/ object)
193 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/454e4e4e2ad7cd3cd5faf2ea76d71685af5cc1dd))
194 |
195 |
196 | 3.4.0
197 | -----
198 |
199 | * [DEPENDENCY]: more getOwner cleanup
200 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/3f1b88b2492eaf81ecba8bd67ce465d18a37c9f6))
201 |
202 |
203 | 3.3.0
204 | -----
205 |
206 | * [DEPENDENCY]: using getOwner to support ember 2.3
207 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/dc6ac20e82ecb1750e5c23041075f7a2b2893512))
208 |
209 | * [REFACTOR]: cleaning up the computed properties
210 | ([#27](https://github.com/toranb/ember-cli-simple-store/pull/27))
211 |
212 | * [DEPENDENCY]: update ember-cli and all other dependencies
213 | ([#26](https://github.com/toranb/ember-cli-simple-store/pull/26))
214 |
215 |
216 | 3.2.0
217 | -----
218 |
219 | * [TEST]: added unit and acceptance tests for isPrimed (starting null)
220 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/1e1e6d0231c1a3a34974d06ffe352ffc5215a2d5))
221 |
222 | * [FEATURE]: replaced === undefined operator with Ember.isNone
223 | ([#21](https://github.com/toranb/ember-cli-simple-store/pull/21))
224 |
225 |
226 | 3.1.0
227 | -----
228 |
229 | * [DEPENDENCY]: removing container from the initializer for ember 2.1
230 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/1f68d63e445a83b9298d03c9bbf95af7b93680d7))
231 |
232 |
233 | 3.0.0
234 | -----
235 |
236 | * [FEATURE]: array proxy push returns record
237 | ([#19](https://github.com/toranb/ember-cli-simple-store/pull/19))
238 |
239 | * [FEATURE]: array proxy now supports remove
240 | ([#18](https://github.com/toranb/ember-cli-simple-store/pull/18))
241 |
242 | * [TEST]: added another array proxy push test to prove type is respected
243 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/f4353f9933983622d825438c94d662e955d95b3c))
244 |
245 | * [FEATURE]: find(all) now returns array proxy
246 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/f8e8fa725237804b0f2ca972c12a91d77a226c33))
247 |
248 |
249 | 2.4.0
250 | -----
251 |
252 | * [FEATURE]: bound array proxy now supports push
253 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/4a73bd9bb5147cc17aedfdc22cbdd36b6c7b9e2f))
254 |
255 | * [DEPENDENCY]: added es5Shim to test phantomJS w/ bind
256 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/4f46a392b3be0ec93864342ba2edddbd3430e293))
257 |
258 |
259 | 2.3.0
260 | -----
261 |
262 | * [BUG]: array attrs are now compared accurately
263 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/fd4b7dd7a8210cc4eb4da324a4a61e162ccf2ab7))
264 |
265 |
266 | 2.2.0
267 | -----
268 |
269 | * [DEPENDENCY]: updated ember-cli to 0.2.7
270 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/a4642351a3a93a264ad24710d0bcef70f91243db))
271 |
272 | * [DEPENDENCY]: bumping bower version of ember to 1.12.1
273 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/d8683cd20a14fe19ccbe32f0842bea5d0fab0e2d))
274 |
275 |
276 | 2.1.0
277 | -----
278 |
279 | * [FEATURE]: added isNotDirty to allow for easy inverse template usage
280 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/b28514a9f5504f3ebf2c28afd253846b7bbe527e))
281 |
282 |
283 | 2.0.0
284 | -----
285 |
286 | * [FEATURE]: attr now supports default value for dirty tracking
287 | ([#13](https://github.com/toranb/ember-cli-simple-store/pull/13))
288 |
289 |
290 | 1.0.4
291 | -----
292 |
293 | * [REFACTOR] removing prototype extensions
294 | ([#14](https://github.com/toranb/ember-cli-simple-store/pull/14))
295 |
296 | * [DEPENDENCY] getting new dependencies and bumping versions
297 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/9f2e9b867edf99a4b0b49e087bf4f8408768e4a1))
298 |
299 |
300 | 1.0.3
301 | -----
302 |
303 | * [BUG] when setting field to empty string, model is not dirty
304 | ([#12](https://github.com/toranb/ember-cli-simple-store/pull/12))
305 |
306 |
307 | 1.0.2
308 | -----
309 |
310 | * [TEST]: adding test for save then immediate rollback
311 | ([#10](https://github.com/toranb/ember-cli-simple-store/pull/10))
312 |
313 | * [BUG]: rollback is now idempotent
314 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/2d0cc9417b1bee7f674923906953045e8dc61a97))
315 |
316 | * [PERIPHERAL]: updating to ember 1.11.3
317 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/aa572e44b1a9c057726ea9d5a5782e59cb7e5727))
318 |
319 |
320 | 1.0.1
321 | -----
322 |
323 | * [BUG]: isDirty should remain when undefined attr set to empty str
324 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/944f9c56d4282c6d9d887128ca9a8f45d81998fe))
325 |
326 |
327 | 1.0.0
328 | -----
329 |
330 | * [DOCS]: added changelog
331 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/d93349710094cd9fdc7cfb5775582f1cb36a4cfe))
332 |
333 | * [DOCS]: updated the readme to show more example apps
334 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/0522f17209aed395de42e15175c8f7293f3944dd))
335 |
336 | * [FEATURE]: findOne is now computed (w/ proxy'd methods)
337 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/b89b1808e45986e2bf9f29fea09f4df8cf5e6c12))
338 |
339 | * [FEATURE]: findById is now computed (w/ proxy'd methods)
340 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/ab9c7dabe6da3efaa62480b96ccaecd1069f1e8b))
341 |
342 |
343 | 0.9.3
344 | -----
345 |
346 | * [DOCS]: updated readme with more modern examples
347 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/daa1b037fe550604a80bc92ab775ea563960157f))
348 |
349 | * [TEST]: adding tests to show behavior when object with no "id" is pushed into store
350 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/212ba12cedda8721859d78e011405c6a6c049990))
351 |
352 | 0.9.2
353 | -----
354 |
355 | * [DOCS]: simplified the store how-to in the readme
356 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/39b75b67fa68e7f8e7c42058c8c00d28fa9d2fd5))
357 |
358 | 0.9.1
359 | -----
360 |
361 | * [FEATURE]: Dirty tracking
362 | ([#7](https://github.com/toranb/ember-cli-simple-store/pull/7))
363 |
364 | * [REFACTOR]: fixing individual attrIsDirty check
365 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/558db91b818e22133f72d617821c1a402ea41d0b))
366 |
367 | * [ENHANCEMENT]: updated model to store isPrimed separate from isDirty
368 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/5a861b997c257fceceff01ad078330c428c60086))
369 |
370 | * [REFACTOR]: simplifying the isDirty computed property
371 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/cfdcdf9c3b1f30d1ed470db6a9dfe62b4b756123))
372 |
373 | * [TEST]: adding test to show working with ints
374 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/e8277b130fdb390c9fa0f6c06753fd82679f8627))
375 |
376 | * [ENHANCEMENT]: extracting isDirty property to computed property to be managed by model
377 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/52399c757053d97a26a24e712ccb0d483bbe8e9f))
378 |
379 | * [DOCS]: added downloads and emberobserver score to the readme
380 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/aff3a5680962f23498afb0fece8277cac166370b))
381 |
382 | 0.7.1
383 | -----
384 |
385 | * [PERIPHERAL]: updating unit tests to avoid container dep warning
386 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/1fcc7001635f30907d14cf9ded7e60b8178774f7))
387 |
388 | 0.7.0
389 | -----
390 |
391 | * [FEATURE]: added the ability to pass a custom filter func to find
392 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/20822288fbf0c37879659f6ef9f7149bd1eb3e70))
393 |
394 | * [BUILD]: setting up travis to run 0.12 and 0.10 versions of node
395 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/ab74ad171d0b8bd4531c8908e4c98e3feba1e973))
396 |
397 | 0.6.2
398 | -----
399 |
400 | * [DEPENDENCY]: upgrading ember to 1.11 beta 5
401 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/9e5ea860c89588ae5e5f5437ffa8315ca02174d9))
402 |
403 | * [DEPENDENCY]: upgrading ember-cli to 0.2.0
404 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/27bee82aad7b1b52161e695564ece7461df120a6))
405 |
406 | * [PERIPHERAL]: Updating package.json and bumping the version of ember-cli
407 | ([#2](https://github.com/toranb/ember-cli-simple-store/pull/2))
408 |
409 | * [DOC]: updating the documentation for the new clear API
410 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/e0b976601041eba69eaa99afaa405482b4e3b7c9))
411 |
412 | 0.6.1
413 | -----
414 |
415 | * [DEPENDENCY]: upgrading ember-cli to 0.1.15
416 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/2d9944bb91b2770f3d175742947fabe0655c2273))
417 |
418 | * [PERIPHERAL]: updating package.json
419 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/cae91b9d9a0e62751c55237e22a60219cc7912a5))
420 |
421 | * [FEATURE]: Adding the ability to clear all types from store
422 | ([#1](https://github.com/toranb/ember-cli-simple-store/pull/1))
423 |
424 | * [REFACTOR]: changes based on PR comments
425 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/9be10f8bdea08450a42eaec44250bb9ddc9dc484))
426 |
427 | 0.6.0
428 | -----
429 |
430 | * [ENHANCEMENT]: added the ability to remove all objects
431 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/25a6ae0d308e011b7f385de3aebd0ffc32153c19))
432 |
433 | 0.5.0
434 | -----
435 |
436 | * [FEATURE]: priming a model attr will not flip the dirty bit
437 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/c537a5858c2ad518e44f7a05c2500603e237df63))
438 |
439 |
440 | 0.4.1
441 | -----
442 |
443 | * [CLEANUP]: removed unnecessary return statement
444 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/c0e16247b2917e5ba81f9243b5d21a4ffdd17e47))
445 |
446 | 0.4.0
447 | -----
448 |
449 | * [FEATURE]: updated the isDirty api for property based access
450 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/9c198d764567678665b1d63ebee2383ba48008e0))
451 |
452 | 0.3.0
453 | -----
454 |
455 | * [DOCS]: added dirty tracking example app to the readme
456 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/081cd6a3450a987ae13c1ba21b6513aeb5fc80ae))
457 |
458 | * [FEATURE]: added dirty tracking at the property level
459 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/5b0801263e73ee8ecc684200a0c93c000ffa3763))
460 |
461 | 0.2.1
462 | -----
463 |
464 | * [BUG]: fixed the global state leak found in the attr
465 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/b812ccacadae665226a3db7b9b88652754661772))
466 |
467 | 0.2.0
468 | -----
469 |
470 | * [FEATURE]: added dirty tracking attr and model
471 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/0f61e0a0cc5be916107b88b5ac918aa630130496))
472 |
473 | 0.1.1
474 | -----
475 |
476 | * [BUG]: updated initializer name to be store/removed ember-data
477 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/d16e84e97303223dace0add7235a76f3d09ea4f9))
478 |
479 | * [DOCS]: updated the example app url
480 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/737eb7267fee5a3c4d17a1ad627537f4d4ae492f))
481 |
482 | 0.1.0
483 | -----
484 |
485 | * [FEATURE]: added findOne api
486 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/f7d35b9ce02ce65a633af2e1ec4092e0af6c5b96))
487 |
488 | * [DOCS]: updated the readme to fix a formatting issue
489 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/df7eb0f4f40cc1c9fa1c35da0258bff20dd276e0))
490 |
491 | * [DOCS]: updated the readme to further define the api documentation
492 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/36a5aa5e3179eaa777b569766ae8c1c1c38b3172))
493 |
494 | * [DOCS]: updated the readme to fix travis-ci build status image
495 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/08c65db8be2b9e9c08192c48a96d9c66e1458c3f))
496 |
497 | * [DOCS]: updated the readme to show the api is 4 methods
498 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/3ca803e6c5e43a776343e70d2951f922b849c5cd))
499 |
500 | * [DOCS]: updated the readme to call out that you must remove ember-data
501 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/4f0d6951c321c021fbe3f60cf072e4a4cebdae8b))
502 |
503 | * [INIT]: init addon commit
504 | ([commit](https://github.com/toranb/ember-cli-simple-store/commit/1d56e42710f20d1ea06d5d2c8cb891329d8d9d55))
505 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2015 Toran Billups http://toranbillups.com
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ember-cli-simple-store
2 |
3 | [![Build Status][]](https://travis-ci.org/toranb/ember-cli-simple-store)
4 | [![Code Climate][climate-badge]][climate]
5 | [](https://www.npmjs.com/package/ember-cli-simple-store)
6 | [](http://emberobserver.com/addons/ember-cli-simple-store)
7 | [![npm package][npm-badge]][npm]
8 |
9 | ## Description
10 |
11 | [ember-cli][] addon that provides a simple identity map for [ember.js][] web applications
12 |
13 | ## Installation
14 |
15 | ```
16 | ember install ember-cli-simple-store
17 | ```
18 |
19 | ## You get 6 methods: push/pushArray/remove/find/findOne/clear
20 |
21 | ```js
22 | //create or update person model
23 |
24 | simpleStore.push("person", {id: 1, name: "toran"});
25 | ```
26 |
27 | ```js
28 | //create or update multiple person models - observers are notified only once all models have been created or updated
29 |
30 | simpleStore.pushArray("person", [{id: 1, name: "john"}, {id: 2, name: "jane"}]);
31 | ```
32 |
33 | ```js
34 | //remove person model with id=123
35 |
36 | simpleStore.remove("person", 123);
37 | ```
38 |
39 | ```js
40 | //find all person models
41 |
42 | simpleStore.find("person");
43 | ```
44 |
45 | ```js
46 | //find a single person model with id=123
47 |
48 | simpleStore.find("person", 123);
49 | ```
50 |
51 | ```js
52 | //find all person models with account_id=789
53 |
54 | simpleStore.find("person", {account_id: 789});
55 | ```
56 |
57 | ```js
58 | //find all person models with name toran and salary > 100
59 |
60 | var filter = function(person) {
61 | var name = person.get("name");
62 | var salary = person.get("salary");
63 | return name === "toran" && salary > 100;
64 | }
65 | simpleStore.find("person", filter);
66 | ```
67 |
68 | ```js
69 | //find the first person model
70 |
71 | simpleStore.findOne("person");
72 | ```
73 |
74 | ```js
75 | //clear the entire identity map of all person models
76 |
77 | simpleStore.clear("person");
78 | ```
79 |
80 | ```js
81 | //clear the entire identity map of all models
82 |
83 | simpleStore.clear();
84 | ```
85 |
86 | ## Using the store by example
87 |
88 | Below I'll show how you can use the store with a simple ember object to find/add/remove/update
89 |
90 | The full example below relies on a small xhr addon [PromiseMixin][]
91 |
92 | ```js
93 | import Ember from "ember";
94 | import PromiseMixin from "ember-promise/mixins/promise";
95 |
96 | var PersonRepository = Ember.Object.extend({
97 | simpleStore: Ember.inject.service(),
98 | find() {
99 | var simpleStore = this.get("simpleStore");
100 | return PromiseMixin.xhr("/api/people/", "GET").then(function(response) {
101 | response.forEach(function(person) {
102 | simpleStore.push("person", person);
103 | });
104 | return simpleStore.find("person");
105 | });
106 | },
107 | findById(id) {
108 | var simpleStore = this.get("simpleStore");
109 | return simpleStore.find("person", id);
110 | },
111 | insert(person) {
112 | var simpleStore = this.get("simpleStore");
113 | var hash = {data: JSON.stringify(person)};
114 | return new Ember.RSVP.Promise(function(resolve,reject) {
115 | return PromiseMixin.xhr("/api/people/", "POST", hash).then(function(persisted) {
116 | var inserted = simpleStore.push("person", persisted);
117 | resolve(inserted);
118 | }, function(err) {
119 | reject(err);
120 | });
121 | });
122 | },
123 | update(person) {
124 | var person_id = person.get("id");
125 | var hash = {data: JSON.stringify(person)};
126 | var endpoint = "/api/people/%@/".fmt(person_id);
127 | return PromiseMixin.xhr(endpoint, "PUT", hash);
128 | },
129 | remove(person) {
130 | var simpleStore = this.get("simpleStore");
131 | var person_id = person.get("id");
132 | var endpoint = "/api/people/%@/".fmt(person_id);
133 | return new Ember.RSVP.Promise(function(resolve,reject) {
134 | return PromiseMixin.xhr(endpoint, "DELETE").then(function(arg) {
135 | simpleStore.remove("person", person_id);
136 | resolve(arg);
137 | }, function(err) {
138 | reject(err);
139 | });
140 | });
141 | }
142 | });
143 |
144 | export default PersonRepository;
145 | ```
146 |
147 | ## What about relationship support?
148 |
149 | A one-to-many example might look something like this
150 |
151 | ```js
152 | import Ember from 'ember';
153 |
154 | export default Ember.Object.extend({
155 | simpleStore: Ember.inject.service(),
156 | role: Ember.computed.alias('belongs_to.firstObject'),
157 | belongs_to: Ember.computed(function() {
158 | let userId = this.get('id');
159 | let simpleStore = this.get('simpleStore');
160 | let filter = function(role) {
161 | let users = role.get('users');
162 | return Ember.$.inArray(userId, users) > -1;
163 | };
164 | return simpleStore.find('role', filter);
165 | })
166 | });
167 |
168 | //a test to show how this api works from the outside
169 |
170 | test('role property returns associated model or undefined', function(assert) {
171 | let user = simpleStore.push('user', {id: 1});
172 | simpleStore.push('role', {id: 2, name: 'Admin', users: [1]});
173 | let role = user.get('role');
174 | assert.equal(role.get('id'), 2);
175 | assert.equal(role.get('name'), 'Admin');
176 | role.set('users', []);
177 | role = user.get('role');
178 | assert.equal(role, undefined);
179 | });
180 | ```
181 |
182 | ## What about dirty tracking?
183 |
184 | If you want the ability to track if your model is dirty use the attr for each field and the Model to get save/rollback
185 |
186 | ```js
187 | import { attr, Model } from "ember-cli-simple-store/model";
188 |
189 | var Person = Model.extend({
190 | firstName: attr(),
191 | lastName: attr(),
192 | fullName: function() {
193 | var first = this.get("firstName");
194 | var last = this.get("lastName");
195 | return first + " " + last;
196 | }.property("firstName", "lastName")
197 | });
198 |
199 | //save your object to reset isDirty
200 | var person = Person.create({id: 1, firstName: "x", lastName: "y"});
201 | person.set("firstName", "toran");
202 | person.save();
203 |
204 | //rollback your object to reset isDirty and restore it
205 | person.set("firstName", "foobar");
206 | person.rollback();
207 | ```
208 |
209 | If you want to know if an individual property isDirty you can ask like so
210 |
211 | ```js
212 | person.get("firstNameIsDirty"); //undefined
213 | person.set("firstName", "foobar");
214 | person.get("firstNameIsDirty"); //true
215 | ```
216 |
217 | For new forms that start with undefined properties you can define the default state for isDirty. Example: you have a model that is bound to a form with a checkbox input. The create form starts with a new model so each bound property is undefined. If the user decides to check the bound checkbox (setting the value to true) and then decides to uncheck it (setting the value to false) you would expect the form is not dirty - but because undefined !== false you find the model is dirty. To prevent this behavior set a default value for dirty tracking on the models attr like so.
218 |
219 | ```js
220 | var Animal = Model.extend({
221 | omnivore: attr(false)
222 | });
223 |
224 | var animal = Animal.create();
225 |
226 | animal.get("omnivore"); //undefined
227 | animal.get("isDirty"); //false
228 | animal.set("omnivore", true);
229 | animal.get("isDirty"); //true
230 | animal.set("omnivore", false);
231 | animal.get("isDirty"); //false
232 | ```
233 |
234 | ## What about custom primary keys?
235 |
236 | By default, simple store will use the 'id' property on your records as the primary key. If you wish to override this, reopen your
237 | model class and add a `primaryKey` attribute.
238 |
239 | ```js
240 | var Food = Ember.Object.extend({
241 | food_id: null,
242 | calories: null
243 | });
244 |
245 | Food.reopenClass({
246 | primaryKey: 'food_id'
247 | });
248 |
249 | simpleStore.push('food', {
250 | food_id: 5,
251 | calories: 500
252 | });
253 |
254 | // Returns the pushed record
255 | simpleStore.find('food', 5);
256 | ```
257 |
258 | ## Example applications
259 |
260 | **Simplest example with the least amount of complexity (tests included)**
261 |
262 | https://github.com/toranb/kanban-board-without-ember-data
263 |
264 | **Simple example running ember 2.4**
265 |
266 | https://github.com/toranb/ember-2-skeleton-app
267 |
268 | **Async example that will paint right away (loading section included w/ tests)**
269 |
270 | https://github.com/toranb/async-kanban-board-store-example
271 |
272 | **Async example with relationships (loading section included w/ tests)**
273 |
274 | https://github.com/toranb/async-kanban-with-relationships-store-example
275 |
276 | **Dirty tracking example with both save and rollback**
277 |
278 | https://github.com/toranb/ember-cli-store-dirty-tracking-example
279 |
280 | ## Running the unit tests
281 |
282 | npm install
283 | ember test
284 |
285 | ## License
286 |
287 | Copyright © 2015 Toran Billups http://toranbillups.com
288 |
289 | Licensed under the MIT License
290 |
291 |
292 | [Build Status]: https://travis-ci.org/toranb/ember-cli-simple-store.svg?branch=master
293 | [ember-cli]: http://www.ember-cli.com/
294 | [ember.js]: http://emberjs.com/
295 | [PromiseMixin]: https://github.com/toranb/ember-promise
296 |
297 | [npm-badge]: https://img.shields.io/npm/v/ember-cli-simple-store.svg?style=flat-square
298 | [npm]: https://www.npmjs.org/package/ember-cli-simple-store
299 |
300 | [climate-badge]: https://codeclimate.com/github/toranb/ember-cli-simple-store/badges/gpa.svg
301 | [climate]: https://codeclimate.com/github/toranb/ember-cli-simple-store
302 |
--------------------------------------------------------------------------------
/addon-test-support/qunit.js:
--------------------------------------------------------------------------------
1 | import { run } from '@ember/runloop';
2 | import { test as qunitTest } from 'qunit';
3 |
4 | let test = function(...args) {
5 |
6 | function wrapper(assert) {
7 | // this is needed for maintaining scope in a test
8 | let env = assert.test.testEnvironment;
9 | run(() => {
10 | callback.apply(env, arguments);
11 | });
12 | }
13 |
14 | // callback is original function
15 | let callback = args.splice(1, 1, wrapper)[0];
16 |
17 | // args is fixed with new wrapper function
18 | qunitTest.apply(null, args);
19 |
20 | };
21 |
22 | export { test };
23 |
--------------------------------------------------------------------------------
/addon/model.js:
--------------------------------------------------------------------------------
1 | import { not } from '@ember/object/computed';
2 | import { isNone } from '@ember/utils';
3 | import EmberObject, {
4 | get,
5 | defineProperty,
6 | computed
7 | } from '@ember/object';
8 |
9 | function equal(first, second) {
10 | if (first instanceof Array && second instanceof Array) {
11 | return first.length === second.length && first.every((v, i) => v === second[i]);
12 | }
13 |
14 | return first === second;
15 | }
16 |
17 | function factory(obj) {
18 | return obj.get("constructor.ClassMixin.ownerConstructor") || obj.constructor;
19 | }
20 |
21 | function attrs(obj) {
22 | let all = [];
23 | factory(obj).eachComputedProperty(function (key, meta) {
24 | if (meta.isAttribute) {
25 | all.push(key);
26 | }
27 | });
28 |
29 | return all;
30 | }
31 |
32 | function clone(obj) {
33 | let copy = {};
34 | factory(obj).eachComputedProperty(function (key, meta) {
35 | if (meta.isAttribute) {
36 | copy[key] = obj.get(key);
37 | }
38 | });
39 |
40 | return copy;
41 | }
42 |
43 | let attr = function() {
44 | let meta = {
45 | isAttribute: true,
46 | defaults: arguments[0]
47 | };
48 |
49 | return computed({
50 | get(key) {
51 | let data = this.get("_data") || {};
52 |
53 | return data[key];
54 | },
55 | set(key, value) {
56 | let data = this.get("_data") || {};
57 | let dirty = this.get("_dirty") || {};
58 | let primed = this.get("_primed") || {};
59 | let defaults = this.get("_defaults") || {};
60 |
61 | defaults[key] = meta.defaults;
62 |
63 | if (!this.get("isDirty")) {
64 | this.set("_oldState", clone(this));
65 | }
66 |
67 | let ready = value === "" && (isNone(data[key]));
68 |
69 | dirty[key + ":isDirty"] = true;
70 | data[key] = value;
71 |
72 | if(!ready && !primed[key + ":isPrimed"]) {
73 | primed[key + ":isPrimed"] = true;
74 | }
75 |
76 | return data[key];
77 | }
78 | }).property("_data").meta(meta);
79 | };
80 |
81 | let Model = EmberObject.extend({
82 | init() {
83 | this._super(...arguments);
84 | this._reset();
85 | this._setup();
86 | this.set("_defaults", {});
87 | this.set("_data", clone(this));
88 | this.set("_oldState", clone(this));
89 | },
90 | rollback() {
91 | let oldState = this.get("_oldState");
92 | for(let key in oldState){
93 | this.set(key, oldState[key]);
94 | }
95 | this._reset();
96 | },
97 | save() {
98 | let oldState = clone(this);
99 | this.set("_oldState", oldState);
100 | this._reset();
101 | },
102 | _reset() {
103 | this.set("isPrimed", false);
104 | this.set("_dirty", {});
105 | this.set("_primed", {});
106 | },
107 | _setup() {
108 | let model = this;
109 | let attributes = attrs(this);
110 |
111 | attributes.forEach((attrName) => {
112 | defineProperty(model, attrName + "IsDirty", computed(function() {
113 | let current = this.get(attrName);
114 | let defaults = this.get("_defaults")[attrName];
115 | let original = this.get("_oldState." + attrName);
116 | let dirty = this.get("_dirty");
117 | let dirtyKey = attrName + ":isDirty";
118 | let legit = (equal(current, defaults) && isNone(original)) || (equal(original, current));
119 |
120 | return legit ? undefined : dirty[dirtyKey];
121 | }).property("_dirty", "_defaults", "" + attrName));
122 |
123 | let dynamicPrimedKey = attrName + "IsPrimed";
124 |
125 | defineProperty(model, dynamicPrimedKey, computed(function() {
126 | let primed = this.get("_primed");
127 | let primedKey = attrName + ":isPrimed";
128 |
129 | return primed[primedKey];
130 | }).property("_primed", "" + attrName));
131 | });
132 |
133 | let modelIsDirtyAttrs = attributes.map((attr) => attr + "IsDirty");
134 | defineProperty(model, "isNotDirty", not('isDirty'));
135 |
136 | defineProperty(model, "isDirty", computed(...modelIsDirtyAttrs, function() {
137 | return modelIsDirtyAttrs.some((attr) => get(model, attr) === true);
138 | }));
139 | }
140 | });
141 |
142 | export { attr, Model };
143 |
--------------------------------------------------------------------------------
/addon/models/filtered-record-array.js:
--------------------------------------------------------------------------------
1 | import { A } from '@ember/array';
2 | import { computed } from '@ember/object';
3 | import RecordArray from './record-array';
4 |
5 | export default RecordArray.extend({
6 | content: computed(function () {
7 | return this.updateContent();
8 | }),
9 |
10 | updateContent() {
11 | let source = this.get("_source");
12 | let filter_func = this.get("_filter_func");
13 |
14 | return A(source.filter(filter_func));
15 | },
16 |
17 | willDestroy() {
18 | this._unregisterRecordArray();
19 | this._super(...arguments);
20 | },
21 |
22 | _unregisterRecordArray() {
23 | let store = this.get("_store");
24 | store._unsubscribe(this);
25 | }
26 | });
27 |
--------------------------------------------------------------------------------
/addon/models/record-array.js:
--------------------------------------------------------------------------------
1 | import { A } from '@ember/array';
2 | import ArrayProxy from '@ember/array/proxy';
3 | import { computed } from '@ember/object';
4 |
5 | export default ArrayProxy.extend({
6 | _store: null,
7 | _type: null,
8 |
9 | content: computed(function () {
10 | return A(this.get("_source"));
11 | }),
12 |
13 | push(data) {
14 | let type = this.get('_type');
15 | return this.get('_store').push(type, data);
16 | },
17 |
18 | remove(id) {
19 | let type = this.get('_type');
20 | this.get('_store').remove(type, id);
21 | }
22 | });
23 |
--------------------------------------------------------------------------------
/addon/models/record-proxy.js:
--------------------------------------------------------------------------------
1 | import ObjectProxy from '@ember/object/proxy';
2 | import { computed } from '@ember/object';
3 | import { getOwner } from '@ember/application';
4 |
5 | export default ObjectProxy.extend({
6 | _source: null,
7 | _store: null,
8 | _type: null,
9 |
10 | content: computed("_source.[]", function() {
11 | return this.compute();
12 | }),
13 |
14 | init() {
15 | this._super(...arguments);
16 | const store = this.get('_store');
17 | const type = this.get('_type');
18 |
19 | let model = getOwner(store).lookup(`model:${type}`);
20 |
21 | for(let method in model) {
22 | if(typeof model[method] === "function") {
23 | if(!this[method]) {
24 | this.proxyMethod(method);
25 | }
26 | }
27 | }
28 | },
29 |
30 | compute() { },
31 |
32 | proxyMethod(method) {
33 | this[method] = function() {
34 | let content = this.get("content");
35 | return content[method].apply(content, arguments);
36 | };
37 | }
38 | });
39 |
--------------------------------------------------------------------------------
/addon/store.js:
--------------------------------------------------------------------------------
1 | import Service from '@ember/service';
2 | import { uuid } from './uuid';
3 | import { A } from '@ember/array';
4 | import { run } from '@ember/runloop';
5 | import EmberObject, { setProperties, get } from '@ember/object';
6 | import { assert } from '@ember/debug';
7 | import { getOwner } from '@ember/application';
8 | import RecordProxy from "./models/record-proxy";
9 | import RecordArray from "./models/record-array";
10 | import FilteredRecordArray from "./models/filtered-record-array";
11 |
12 | function buildRecord(type, data, store) {
13 | let record = createRecord(type, data, store);
14 | arrayForType(type, store).pushObject(record);
15 |
16 | return record;
17 | }
18 |
19 | function createRecord(type, data, store) {
20 | let factory = factoryForType(type, store);
21 | let primaryKey = primaryKeyForType(type, store);
22 |
23 | assert("No model was found for type: " + type, factory);
24 |
25 | let record = factory.create(data);
26 | let id = data[primaryKey];
27 | identityMapForType(type, store)[id] = record;
28 |
29 | return record;
30 | }
31 |
32 | function factoryForType(type, store) {
33 | return getOwner(store).factoryFor("model:" + type);
34 | }
35 |
36 | function primaryKeyForType(type, store) {
37 | const factory = factoryForType(type, store) || {};
38 | // http://emberjs.com/deprecations/v2.x/#toc_migrating-from-_lookupfactory-to-factoryfor
39 | return factory.class && (factory.class.primaryKey || 'id');
40 | }
41 |
42 | function arrayForType(type, store) {
43 | let all = store.get("array");
44 | let models = all[type] || [];
45 | all[type] = models;
46 | return A(models);
47 | }
48 |
49 | function identityMapForType(type, store) {
50 | let typeIdentityMap = store.get("identityMap");
51 | let idIdentityMap = typeIdentityMap[type] || {};
52 | typeIdentityMap[type] = idIdentityMap;
53 |
54 | return idIdentityMap;
55 | }
56 |
57 | const ServiceType = Service || EmberObject;
58 |
59 | let Store = ServiceType.extend({
60 | init() {
61 | this._super(...arguments);
62 | this.reset();
63 | },
64 | reset() {
65 | this.set("recompute", A());
66 | this.set("filtersMap", {});
67 | this.set("identityMap", {});
68 |
69 | let array = this.get("array") || {};
70 | Object.keys(array).forEach((type) => {
71 | arrayForType(type, this).forEach(record => record.destroy());
72 | });
73 | this.set("array", {});
74 | },
75 | willDestroy() {
76 | this.setProperties({
77 | "array": null,
78 | "identityMap": null,
79 | "filtersMap": null,
80 | "recompute": null
81 | });
82 | },
83 | clear(type) {
84 | if (type === undefined) {
85 | this.reset();
86 | }
87 |
88 | delete this.get("identityMap")[type];
89 | let records = arrayForType(type, this);
90 | records.forEach(record => record.destroy());
91 | records.clear();
92 | this.scheduleUpdate(type);
93 | },
94 | remove(type, id) {
95 | let record = this._findById(type, id);
96 | if (record) {
97 | let primaryKey = primaryKeyForType(type, this);
98 | delete this.get("identityMap")[type][record[primaryKey]];
99 | arrayForType(type, this).removeObject(record);
100 | record.destroy();
101 | this.scheduleUpdate(type);
102 | }
103 | },
104 | push(type, data) {
105 | let primaryKey = primaryKeyForType(type, this);
106 | data[primaryKey] = this._coerceId(data[primaryKey]);
107 | let record = this._findById(type, data[primaryKey]);
108 |
109 | if (record) {
110 | setProperties(record, data);
111 | } else {
112 | record = buildRecord(type, data, this);
113 | }
114 |
115 | this.scheduleUpdate(type);
116 |
117 | return record;
118 | },
119 | pushArray(type, dataArray) {
120 | let primaryKey = primaryKeyForType(type, this);
121 | let records = [];
122 |
123 | dataArray.forEach((data) => {
124 | data[primaryKey] = this._coerceId(data[primaryKey]);
125 | let record = this._findById(type, data[primaryKey]);
126 |
127 | if (record) {
128 | setProperties(record, data);
129 | } else {
130 | record = createRecord(type, data, this);
131 | records.push(record);
132 | }
133 | });
134 |
135 | arrayForType(type, this).pushObjects(records);
136 |
137 | this.scheduleUpdate(type);
138 |
139 | return records;
140 | },
141 | scheduleUpdate(type) {
142 | let recompute = this.get("recompute");
143 | recompute.addObject(type);
144 | run.scheduleOnce('actions', this, 'updateFilters');
145 | },
146 | updateFilters() {
147 | if (this.get('isDestroyed') || this.get('isDestroying')) {
148 | return;
149 | }
150 | let recompute = this.get("recompute");
151 | let filtersMap = this.get("filtersMap");
152 |
153 | Object.keys(filtersMap).forEach((type) => {
154 | let filters = filtersMap[type] || [];
155 |
156 | filters.forEach((recordArray) => {
157 | if (recompute.includes(type)) {
158 | let updatedContent = recordArray.updateContent();
159 | recordArray.set("content", updatedContent);
160 | }
161 | });
162 | });
163 |
164 | this.set("recompute", A());
165 | },
166 | _unsubscribe(...args) {
167 | let updatedFiltersMap;
168 | let filterIds = A(args.map((func) => {
169 | let primaryKey = primaryKeyForType(func.type, this);
170 | return func[primaryKey];
171 | }));
172 | let filtersMap = this.get("filtersMap");
173 | Object.keys(filtersMap).forEach((type) => {
174 | let primaryKey = primaryKeyForType(type, this);
175 | let filters = filtersMap[type] || [];
176 | updatedFiltersMap = filters.filter((func) => !filterIds.includes(func[primaryKey]));
177 | filtersMap[type] = updatedFiltersMap;
178 | });
179 | },
180 | find(type, options) {
181 | if (typeof options === "undefined") {
182 | return this._findAllProxy(type);
183 | }
184 |
185 | if (options instanceof Function) {
186 | return this._findWithFilterFunc(type, options);
187 | }
188 |
189 | if (typeof options === "object") {
190 | let params = Object.keys(options);
191 |
192 | assert("No key was found in the filter options", params.length);
193 |
194 | let attr = params[0];
195 | let value = options[attr];
196 |
197 | return this._findWithFilterFunc(type, function filterFunction(m) {
198 | return get(m, attr) === value;
199 | });
200 | }
201 |
202 | return this._findByIdComputed(type, options);
203 | },
204 | findOne(type) {
205 | return RecordProxy.create({
206 | _store: this,
207 | _type: type,
208 | _source: this._findAll(type),
209 | compute() {
210 | return this.get("_source").objectAt(0);
211 | }
212 | });
213 | },
214 | _findById(type, id) {
215 | let identityMap = identityMapForType(type, this);
216 | return identityMap[id] || null;
217 | },
218 | _findAll(type) {
219 | return arrayForType(type, this);
220 | },
221 | _findAllProxy(type) {
222 | return RecordArray.create({
223 | _type: type,
224 | _store: this,
225 | _source: this._findAll(type)
226 | });
227 | },
228 | _findWithFilterFunc(type, filter_func) {
229 | let func = FilteredRecordArray.create({
230 | _type: type,
231 | _store: this,
232 | _id: uuid(),
233 | _filter_func: filter_func,
234 | _source: this._findAll(type)
235 | });
236 | let filtersMap = this.get("filtersMap");
237 | let filters = filtersMap[type] || [];
238 | filters.push(func);
239 | filtersMap[type] = filters;
240 | return func;
241 | },
242 | _coerceId(id) {
243 | let numberId = Number(id);
244 | if (!isNaN(numberId) && numberId.toString().length === id.toString().length) {
245 | return numberId;
246 | }
247 | return id;
248 | },
249 | _findByIdComputed(type, id) {
250 | let actualId = this._coerceId(id);
251 | let primaryKey = primaryKeyForType(type, this);
252 |
253 | return RecordProxy.create({
254 | _store: this,
255 | _type: type,
256 | _filter_value: actualId,
257 | _source: this._findAll(type),
258 | compute() {
259 | let filter_value = this.get("_filter_value");
260 | return this.get("_source").findBy(primaryKey, filter_value);
261 | }
262 | });
263 | }
264 | });
265 |
266 | export default Store;
267 |
--------------------------------------------------------------------------------
/addon/uuid.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Fast UUID generator, RFC4122 version 4 compliant.
3 | * @author Jeff Ward (jcward.com).
4 | * @license MIT license
5 | * @link http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136
6 | **/
7 |
8 | /**
9 | * ES 6 Module
10 | * @author Andrew Hacking (ahacking@gmail.com)
11 | *
12 | **/
13 | const lut = []; for (var i=0; i<256; i++) { lut[i] = (i<16?'0':'')+(i).toString(16); }
14 |
15 | /**
16 | `uuid` generates a Version 4 UUID using Jeff Wards high performance generator.
17 |
18 | @method v4uuid
19 | @for Orbit
20 | @returns {String} a version 4 UUID
21 | */
22 | export function uuid() {
23 | const d0 = Math.random()*0xffffffff|0;
24 | const d1 = Math.random()*0xffffffff|0;
25 | const d2 = Math.random()*0xffffffff|0;
26 | const d3 = Math.random()*0xffffffff|0;
27 | return lut[d0&0xff]+lut[d0>>8&0xff]+lut[d0>>16&0xff]+lut[d0>>24&0xff]+'-'+
28 | lut[d1&0xff]+lut[d1>>8&0xff]+'-'+lut[d1>>16&0x0f|0x40]+lut[d1>>24&0xff]+'-'+
29 | lut[d2&0x3f|0x80]+lut[d2>>8&0xff]+'-'+lut[d2>>16&0xff]+lut[d2>>24&0xff]+
30 | lut[d3&0xff]+lut[d3>>8&0xff]+lut[d3>>16&0xff]+lut[d3>>24&0xff];
31 | }
32 |
--------------------------------------------------------------------------------
/app/services/simple-store.js:
--------------------------------------------------------------------------------
1 | export { default } from 'ember-cli-simple-store/store';
2 |
--------------------------------------------------------------------------------
/config/ember-try.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node */
2 | module.exports = {
3 | useYarn: true,
4 | scenarios: [
5 | {
6 | name: 'ember-lts-2.12',
7 | npm: {
8 | devDependencies: {
9 | 'ember-source': '~2.12.0'
10 | }
11 | }
12 | },
13 | {
14 | name: 'ember-2.18.X',
15 | npm: {
16 | devDependencies: {
17 | 'ember-source': '~2.18.0'
18 | }
19 | }
20 | },
21 | {
22 | name: 'ember-3.1.X',
23 | npm: {
24 | devDependencies: {
25 | 'ember-source': '~3.1.1'
26 | }
27 | }
28 | },
29 | {
30 | name: 'ember-3.3.X',
31 | npm: {
32 | devDependencies: {
33 | 'ember-source': '~3.3.0'
34 | }
35 | }
36 | },
37 | {
38 | name: 'ember-3.4.X',
39 | npm: {
40 | devDependencies: {
41 | 'ember-source': '~3.4.0'
42 | }
43 | }
44 | },
45 | {
46 | name: 'ember-3.7.X',
47 | npm: {
48 | devDependencies: {
49 | 'ember-source': '~3.7.0'
50 | }
51 | }
52 | }
53 | ]
54 | };
55 |
--------------------------------------------------------------------------------
/config/environment.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function(/* environment, appConfig */) {
4 | return { };
5 | };
6 |
--------------------------------------------------------------------------------
/ember-cli-build.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const EmberAddon = require('ember-cli/lib/broccoli/ember-addon');
4 |
5 | module.exports = function(defaults) {
6 | let app = new EmberAddon(defaults, {
7 | // Add options here
8 | });
9 |
10 | /*
11 | This build file specifies the options for the dummy test app of this
12 | addon, located in `/tests/dummy`
13 | This build file does *not* influence how the addon or the app using it
14 | behave. You most likely want to be modifying `./index.js` or app's build file
15 | */
16 |
17 | return app.toTree();
18 | };
19 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | name: 'ember-cli-simple-store'
5 | };
6 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ember-cli-simple-store",
3 | "version": "5.9.4",
4 | "description": "ember-cli addon that provides a simple identity map for ember.js web applications",
5 | "scripts": {
6 | "lint:js": "eslint .",
7 | "start": "ember serve",
8 | "test": "ember try:each",
9 | "build": "ember build"
10 | },
11 | "homepage": "https://github.com/toranb/ember-cli-simple-store",
12 | "bugs": {
13 | "url": "https://github.com/toranb/ember-cli-simple-store/issues"
14 | },
15 | "engines": {
16 | "node": "6.* || 8.* || >= 10.*"
17 | },
18 | "devDependencies": {
19 | "broccoli-asset-rev": "^2.7.0",
20 | "ember-cli": "~3.3.0",
21 | "ember-cli-app-version": "^2.0.0",
22 | "ember-cli-dependency-checker": "^2.0.0",
23 | "ember-cli-eslint": "^4.2.1",
24 | "ember-cli-htmlbars": "^2.0.1",
25 | "ember-cli-htmlbars-inline-precompile": "^1.0.0",
26 | "ember-cli-inject-live-reload": "^1.4.1",
27 | "ember-cli-qunit": "^4.3.2",
28 | "ember-cli-shims": "^1.2.0",
29 | "ember-cli-sri": "^2.1.0",
30 | "ember-cli-uglify": "^2.0.0",
31 | "ember-disable-prototype-extensions": "^1.1.2",
32 | "ember-export-application-global": "^2.0.0",
33 | "ember-load-initializers": "^1.1.0",
34 | "ember-maybe-import-regenerator": "^0.1.6",
35 | "ember-resolver": "^4.0.0",
36 | "ember-source": "~3.4.7",
37 | "ember-try": "^0.2.23",
38 | "eslint-plugin-ember": "^5.0.0",
39 | "eslint-plugin-node": "^6.0.1",
40 | "loader.js": "^4.2.3"
41 | },
42 | "dependencies": {
43 | "ember-cli-babel": "^6.8.2",
44 | "ember-runtime-enumerable-includes-polyfill": "^2.1.0"
45 | },
46 | "keywords": [
47 | "data",
48 | "ember",
49 | "ember-addon",
50 | "ember-cli",
51 | "simple",
52 | "store"
53 | ],
54 | "repository": {
55 | "type": "git",
56 | "url": "https://github.com/toranb/ember-cli-simple-store"
57 | },
58 | "license": "MIT",
59 | "author": "Toran Billups toranb@gmail.com",
60 | "directories": {
61 | "doc": "doc",
62 | "test": "tests"
63 | },
64 | "ember-addon": {
65 | "configPath": "tests/dummy/config"
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/testem.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | test_page: 'tests/index.html?hidepassed',
3 | disable_watching: true,
4 | launch_in_ci: [
5 | 'Chrome'
6 | ],
7 | launch_in_dev: [
8 | 'Chrome'
9 | ],
10 | browser_args: {
11 | Chrome: {
12 | ci: [
13 | // --no-sandbox is needed when running Chrome inside a container
14 | process.env.CI ? '--no-sandbox' : null,
15 | '--headless',
16 | '--disable-gpu',
17 | '--disable-dev-shm-usage',
18 | '--disable-software-rasterizer',
19 | '--mute-audio',
20 | '--remote-debugging-port=0',
21 | '--window-size=1440,900'
22 | ].filter(Boolean)
23 | }
24 | }
25 | };
26 |
--------------------------------------------------------------------------------
/tests/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | embertest: true
4 | }
5 | };
6 |
--------------------------------------------------------------------------------
/tests/acceptance/a-defaults-test.js:
--------------------------------------------------------------------------------
1 | import { test } from 'qunit';
2 | import moduleForAcceptance from '../helpers/module-for-acceptance';
3 |
4 | moduleForAcceptance('Acceptance: Defaults A Test');
5 |
6 | test('text input with no default value should be dirty when value added then removed', function(assert) {
7 | visit('/defaulta');
8 | andThen(() => {
9 | assert.equal(find("input.name").val(), "");
10 | assert.equal(find(".nameDirty").text(), "");
11 | assert.equal(find(".namePrimed").text(), "");
12 | });
13 | fillIn("input.name", "x");
14 | andThen(() => {
15 | assert.equal(find("input.name").val(), "x");
16 | assert.equal(find(".nameDirty").text(), "true");
17 | assert.equal(find(".namePrimed").text(), "true");
18 | });
19 | fillIn("input.name", "");
20 | andThen(() => {
21 | assert.equal(find("input.name").val(), "");
22 | assert.equal(find(".nameDirty").text(), "true");
23 | assert.equal(find(".namePrimed").text(), "true");
24 | });
25 | });
26 |
27 | test('checkbox input with default value of false should not be dirty when unchecked', function(assert) {
28 | visit('/defaulta');
29 | andThen(() => {
30 | assert.equal(find("input.funny").is(":checked"), false);
31 | assert.equal(find(".funnyDirty").text(), "");
32 | assert.equal(find(".funnyPrimed").text(), "");
33 | });
34 | click("input.funny");
35 | andThen(() => {
36 | assert.equal(find("input.funny").is(":checked"), true);
37 | assert.equal(find(".funnyDirty").text(), "true");
38 | assert.equal(find(".funnyPrimed").text(), "true");
39 | });
40 | click("input.funny");
41 | andThen(() => {
42 | assert.equal(find("input.funny").is(":checked"), false);
43 | assert.equal(find(".funnyDirty").text(), "");
44 | assert.equal(find(".funnyPrimed").text(), "true");
45 | });
46 | });
47 |
--------------------------------------------------------------------------------
/tests/acceptance/a-test.js:
--------------------------------------------------------------------------------
1 | import Foo from "dummy/models/foo";
2 | import { test } from 'qunit';
3 | import moduleForAcceptance from '../helpers/module-for-acceptance';
4 |
5 | moduleForAcceptance('Acceptance: A Test', {
6 | beforeEach: () => {
7 | Foo.create({name: "wat"});
8 | }
9 | });
10 |
11 | test('the attr in test a should not hold global state across objects', function(assert) {
12 | visit('/wat');
13 | andThen(() => {
14 | assert.ok(true);
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/tests/acceptance/arrays-test.js:
--------------------------------------------------------------------------------
1 | import { test } from 'qunit';
2 | import moduleForAcceptance from '../helpers/module-for-acceptance';
3 |
4 | moduleForAcceptance('Acceptance: Arrays Test', {
5 | beforeEach() {
6 | this.store = this.application.__container__.lookup('service:simple-store');
7 | },
8 | afterEach() {
9 | this.store = null;
10 | }
11 | });
12 |
13 | test('pushArray will trigger filter for each subscription', function(assert) {
14 | visit('/arrays');
15 | andThen(() => {
16 | assert.equal(find('.one').find('option').length, 3);
17 | assert.equal(find('.two').find('option').length, 3);
18 | assert.equal(find('.three').find('option').length, 3);
19 | assert.equal(find('.four').find('option').length, 3);
20 |
21 | this.store.pushArray('robot', [{id: 2, size: 20}, {id: 1, size: 10}, {id: 3, size: 30}]);
22 | this.store.pushArray('zing', [{id: 2, number: 80}, {id: 1, number: 90}, {id: 3, number: 70}]);
23 | });
24 | andThen(() => {
25 | assert.equal(find('.one').find('option').length, 0);
26 | assert.equal(find('.two').find('option').length, 2);
27 | assert.equal(find('.three').find('option').length, 0);
28 | assert.equal(find('.four').find('option').length, 2);
29 | });
30 | });
31 |
--------------------------------------------------------------------------------
/tests/acceptance/b-defaults-test.js:
--------------------------------------------------------------------------------
1 | import { test } from 'qunit';
2 | import moduleForAcceptance from '../helpers/module-for-acceptance';
3 |
4 | moduleForAcceptance('Acceptance: Defaults B Test');
5 |
6 | test('text input with default value of empty string should not be dirty when value added then removed', function(assert) {
7 | visit('/defaultb');
8 | andThen(() => {
9 | assert.equal(find("input.name").val(), "");
10 | assert.equal(find(".nameDirty").text(), "");
11 | assert.equal(find(".namePrimed").text(), "");
12 | });
13 | fillIn("input.name", "x");
14 | andThen(() => {
15 | assert.equal(find("input.name").val(), "x");
16 | assert.equal(find(".nameDirty").text(), "true");
17 | assert.equal(find(".namePrimed").text(), "true");
18 | });
19 | fillIn("input.name", "");
20 | andThen(() => {
21 | assert.equal(find("input.name").val(), "");
22 | assert.equal(find(".nameDirty").text(), "");
23 | assert.equal(find(".namePrimed").text(), "true");
24 | });
25 | });
26 |
27 | test('checkbox input with no default value should be dirty when unchecked', function(assert) {
28 | visit('/defaultb');
29 | andThen(() => {
30 | assert.equal(find("input.funny").is(":checked"), false);
31 | assert.equal(find(".funnyDirty").text(), "");
32 | assert.equal(find(".funnyPrimed").text(), "");
33 | });
34 | click("input.funny");
35 | andThen(() => {
36 | assert.equal(find("input.funny").is(":checked"), true);
37 | assert.equal(find(".funnyDirty").text(), "true");
38 | assert.equal(find(".funnyPrimed").text(), "true");
39 | });
40 | click("input.funny");
41 | andThen(() => {
42 | assert.equal(find("input.funny").is(":checked"), false);
43 | assert.equal(find(".funnyDirty").text(), "true");
44 | assert.equal(find(".funnyPrimed").text(), "true");
45 | });
46 | });
47 |
--------------------------------------------------------------------------------
/tests/acceptance/b-test.js:
--------------------------------------------------------------------------------
1 | import { test } from 'qunit';
2 | import moduleForAcceptance from '../helpers/module-for-acceptance';
3 |
4 | moduleForAcceptance('Acceptance: B Test');
5 |
6 | test('the attr in test b should not hold global state across objects', function(assert) {
7 | visit('/wat');
8 | andThen(() => {
9 | assert.equal(find("input.name").val(), "");
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/tests/acceptance/delete-object-test.js:
--------------------------------------------------------------------------------
1 | import { run } from '@ember/runloop';
2 | import { test } from 'qunit';
3 | import moduleForAcceptance from '../helpers/module-for-acceptance';
4 |
5 | moduleForAcceptance('Acceptance: Delete Object Test');
6 |
7 | test('when object is removed from store all timers and observers are killed', function(assert) {
8 | let lastNumber;
9 | let done = assert.async();
10 | visit('/delete-object');
11 | andThen(() => {
12 | assert.ok(parseInt(find(".number-is").text(), 10) > 0);
13 | });
14 | run.later(() => {
15 | find("button.stop").trigger("click");
16 | lastNumber = parseInt(find(".number-is").text(), 10);
17 | }, 500);
18 | run.later(() => {
19 | assert.equal(parseInt(find(".number-is").text(), 10), lastNumber);
20 | assert.equal(window.number, lastNumber + 1);
21 | done();
22 | }, 1500);
23 | });
24 |
--------------------------------------------------------------------------------
/tests/acceptance/edit-test.js:
--------------------------------------------------------------------------------
1 | import { test } from 'qunit';
2 | import moduleForAcceptance from '../helpers/module-for-acceptance';
3 |
4 | moduleForAcceptance('Acceptance: Edit Test');
5 |
6 | test('attribute change from value to empty string should result in isPrimed', function(assert) {
7 | visit('/edit');
8 | andThen(() => {
9 | assert.equal(find("input.name").val(), "toran");
10 | assert.equal(find(".nameDirty").text(), "");
11 | assert.equal(find(".namePrimed").text(), "");
12 | });
13 | fillIn("input.name", "");
14 | andThen(() => {
15 | assert.equal(find("input.name").val(), "");
16 | assert.equal(find(".nameDirty").text(), "true");
17 | assert.equal(find(".namePrimed").text(), "true");
18 | });
19 | fillIn("input.name", "x");
20 | andThen(() => {
21 | assert.equal(find("input.name").val(), "x");
22 | assert.equal(find(".nameDirty").text(), "true");
23 | assert.equal(find(".namePrimed").text(), "true");
24 | });
25 | fillIn("input.name", "toran");
26 | andThen(() => {
27 | assert.equal(find("input.name").val(), "toran");
28 | assert.equal(find(".nameDirty").text(), "");
29 | assert.equal(find(".namePrimed").text(), "true");
30 | });
31 | });
32 |
--------------------------------------------------------------------------------
/tests/acceptance/filters-test.js:
--------------------------------------------------------------------------------
1 | import { test } from 'qunit';
2 | import moduleForAcceptance from '../helpers/module-for-acceptance';
3 |
4 | moduleForAcceptance('Acceptance: Filters Test', {
5 | beforeEach() {
6 | this.store = this.application.__container__.lookup('service:simple-store');
7 | },
8 | afterEach() {
9 | this.store = null;
10 | }
11 | });
12 |
13 | test('push will trigger filter for each subscription', function(assert) {
14 | visit('/filters');
15 | andThen(() => {
16 | assert.equal(find('.one').find('option').length, 3);
17 | assert.equal(find('.two').find('option').length, 3);
18 | assert.equal(find('.three').find('option').length, 3);
19 | assert.equal(find('.four').find('option').length, 3);
20 | this.store.push('robot', {id: 2, size: 20});
21 | this.store.push('robot', {id: 1, size: 10});
22 | this.store.push('robot', {id: 3, size: 30});
23 | this.store.push('zing', {id: 2, number: 80});
24 | this.store.push('zing', {id: 1, number: 90});
25 | this.store.push('zing', {id: 3, number: 70});
26 | });
27 | andThen(() => {
28 | assert.equal(find('.one').find('option').length, 0);
29 | assert.equal(find('.two').find('option').length, 2);
30 | assert.equal(find('.three').find('option').length, 0);
31 | assert.equal(find('.four').find('option').length, 2);
32 | });
33 | });
34 |
35 | test('filters can be thrown out when you navigate away from a given route', function(assert) {
36 | visit('/filters');
37 | andThen(() => {
38 | assert.equal(currentURL(), '/filters');
39 | let filtersMap = this.store.get('filtersMap');
40 | let robotFilters = filtersMap['robot'];
41 | let zingFilters = filtersMap['zing'];
42 | assert.equal(robotFilters.length, 2);
43 | assert.equal(zingFilters.length, 2);
44 | });
45 | click('.link-robots');
46 | andThen(() => {
47 | assert.equal(currentURL(), '/robots');
48 | let filtersMap = this.store.get('filtersMap');
49 | let robotFilters = filtersMap['robot'];
50 | let zingFilters = filtersMap['zing'];
51 | //the filters route did cleanup so removed the filters used :)
52 | assert.equal(robotFilters.length, 2);
53 | assert.equal(zingFilters.length, 0);
54 | });
55 | click('.link-wat');
56 | andThen(() => {
57 | assert.equal(currentURL(), '/wat');
58 | let filtersMap = this.store.get('filtersMap');
59 | let robotFilters = filtersMap['robot'];
60 | let zingFilters = filtersMap['zing'];
61 | //the robots route did not cleanup so we now have a memory leak :(
62 | assert.equal(robotFilters.length, 2);
63 | assert.equal(zingFilters.length, 0);
64 | });
65 | click('.link-filters');
66 | andThen(() => {
67 | assert.equal(currentURL(), '/filters');
68 | let filtersMap = this.store.get('filtersMap');
69 | let robotFilters = filtersMap['robot'];
70 | let zingFilters = filtersMap['zing'];
71 | //the wat route did not cleanup so we now have a memory leak :(
72 | assert.equal(robotFilters.length, 4);
73 | assert.equal(zingFilters.length, 2);
74 | });
75 | });
76 |
77 | test('filters on models with custom primary keys can be thrown out when you leave a route', function(assert) {
78 | visit('/custom-key');
79 | andThen(() => {
80 | assert.equal(currentURL(), '/custom-key');
81 | let filtersMap = this.store.get('filtersMap');
82 | let customKeyFilters = filtersMap['custom-key'];
83 | assert.equal(customKeyFilters.length, 1);
84 | });
85 | click('.link-wat');
86 | andThen(() => {
87 | assert.equal(currentURL(), '/wat');
88 | let filtersMap = this.store.get('filtersMap');
89 | let customKeyFilters = filtersMap['custom-key'];
90 | assert.equal(customKeyFilters.length, 0);
91 | });
92 | });
93 |
94 | test('each filter function will be updated during a push with multiple listeners across multiple routes', function(assert) {
95 | visit('/filters');
96 | andThen(() => {
97 | assert.equal(currentURL(), '/filters');
98 | assert.equal(find('.one').find('option').length, 3);
99 | assert.equal(find('.two').find('option').length, 3);
100 | assert.equal(find('.three').find('option').length, 3);
101 | assert.equal(find('.four').find('option').length, 3);
102 | this.store.push('robot', {id: 2, size: 20});
103 | this.store.push('robot', {id: 1, size: 10});
104 | this.store.push('robot', {id: 3, size: 30});
105 | this.store.push('zing', {id: 2, number: 80});
106 | this.store.push('zing', {id: 1, number: 90});
107 | this.store.push('zing', {id: 3, number: 70});
108 | });
109 | andThen(() => {
110 | assert.equal(find('.one').find('option').length, 0);
111 | assert.equal(find('.two').find('option').length, 2);
112 | assert.equal(find('.three').find('option').length, 0);
113 | assert.equal(find('.four').find('option').length, 2);
114 | });
115 | click('.link-robots');
116 | andThen(() => {
117 | assert.equal(currentURL(), '/robots');
118 | assert.equal(find('.nine').find('option').length, 1);
119 | assert.equal(find('.eight').find('option').length, 1);
120 | this.store.push('robot', {id: 15, name: 'seven', size: 15});
121 | });
122 | andThen(() => {
123 | assert.equal(find('.nine').find('option').length, 1);
124 | assert.equal(find('.eight').find('option').length, 2);
125 | });
126 | click('.link-filters');
127 | andThen(() => {
128 | assert.equal(currentURL(), '/filters');
129 | assert.equal(find('.one').find('option').length, 1);
130 | assert.equal(find('.two').find('option').length, 5);
131 | assert.equal(find('.three').find('option').length, 0);
132 | assert.equal(find('.four').find('option').length, 2);
133 | });
134 | });
135 |
--------------------------------------------------------------------------------
/tests/acceptance/isnone-test.js:
--------------------------------------------------------------------------------
1 | import { test } from 'qunit';
2 | import moduleForAcceptance from '../helpers/module-for-acceptance';
3 |
4 | moduleForAcceptance('Acceptance: isNone Test');
5 |
6 | test('attribute change from value to empty string should result in isPrimed for null and undefined', function(assert) {
7 | visit('/isnone');
8 | andThen(function() {
9 | assert.equal(find("input.name:eq(0)").val(), "");
10 | assert.equal(find(".nameDirty:eq(0)").text(), "");
11 | assert.equal(find(".namePrimed:eq(0)").text(), "");
12 | assert.equal(find("input.name:eq(1)").val(), "");
13 | assert.equal(find(".nameDirty:eq(1)").text(), "");
14 | assert.equal(find(".namePrimed:eq(1)").text(), "");
15 | });
16 | fillIn("input.name:eq(0)", "");
17 | fillIn("input.name:eq(1)", "");
18 | andThen(function() {
19 | assert.equal(find("input.name:eq(0)").val(), "");
20 | assert.equal(find(".nameDirty:eq(0)").text(), "true");
21 | assert.equal(find(".namePrimed:eq(0)").text(), "");
22 | assert.equal(find("input.name:eq(1)").val(), "");
23 | assert.equal(find(".nameDirty:eq(1)").text(), "true");
24 | assert.equal(find(".namePrimed:eq(1)").text(), "");
25 | });
26 | fillIn("input.name:eq(0)", "x");
27 | fillIn("input.name:eq(1)", "x");
28 | andThen(function() {
29 | assert.equal(find("input.name:eq(0)").val(), "x");
30 | assert.equal(find(".nameDirty:eq(0)").text(), "true");
31 | assert.equal(find(".namePrimed:eq(0)").text(), "true");
32 | assert.equal(find("input.name:eq(1)").val(), "x");
33 | assert.equal(find(".nameDirty:eq(1)").text(), "true");
34 | assert.equal(find(".namePrimed:eq(1)").text(), "true");
35 | });
36 | fillIn("input.name:eq(0)", "");
37 | fillIn("input.name:eq(1)", "");
38 | andThen(function() {
39 | assert.equal(find("input.name:eq(0)").val(), "");
40 | assert.equal(find(".nameDirty:eq(0)").text(), "true");
41 | assert.equal(find(".namePrimed:eq(0)").text(), "true");
42 | assert.equal(find("input.name:eq(1)").val(), "");
43 | assert.equal(find(".nameDirty:eq(1)").text(), "true");
44 | assert.equal(find(".namePrimed:eq(1)").text(), "true");
45 | });
46 | });
47 |
--------------------------------------------------------------------------------
/tests/acceptance/relationships-test.js:
--------------------------------------------------------------------------------
1 | import { test } from 'qunit';
2 | import moduleForAcceptance from '../helpers/module-for-acceptance';
3 |
4 | moduleForAcceptance('Acceptance: Relationships Test', {
5 | beforeEach() {
6 | this.store = this.application.__container__.lookup('service:simple-store');
7 | }
8 | });
9 |
10 | test('changing the users role will alter the underlying relationship', function(assert) {
11 | visit('/relationships');
12 | andThen(() => {
13 | let options = find('.all-roles');
14 | assert.equal(options.find('option').length, 2);
15 | assert.equal(options.find('option:eq(0)').val(), 8);
16 | assert.equal(options.find('option:eq(1)').val(), 9);
17 | assert.equal(options.find('option:eq(0)').text(), 'Admin');
18 | assert.equal(options.find('option:eq(1)').text(), 'Guest');
19 | assert.equal(options.find('option:selected').val(), 9);
20 | assert.equal(this.store.find('user', 2).get('role.id'), 9);
21 | });
22 | fillIn('.all-roles', 8);
23 | andThen(() => {
24 | let options = find('.all-roles');
25 | assert.equal(options.find('option').length, 2);
26 | assert.equal(options.find('option:selected').val(), 8);
27 | assert.equal(this.store.find('user', 2).get('role.id'), 8);
28 | });
29 | });
30 |
31 | test('updateContent only fires for models with subscribers and only once per run', function(assert) {
32 | let roleUpdated = 0;
33 | visit('/relationships');
34 | andThen(() => {
35 | assert.equal(this.store.find('user', 2).get('role.id'), 9);
36 | let filtersMap = this.store.get("filtersMap");
37 | let roleFunc = filtersMap["role"];
38 | let origRoleFunc = roleFunc[0].updateContent;
39 | roleFunc[0].updateContent = function() {
40 | roleUpdated = roleUpdated + 1;
41 | return origRoleFunc.apply(this, arguments);
42 | };
43 | let userFunc = filtersMap["user"];
44 | assert.equal(userFunc, undefined);
45 | });
46 | fillIn('.all-roles', 8);
47 | andThen(() => {
48 | assert.equal(this.store.find('user', 2).get('role.id'), 8);
49 | assert.equal(roleUpdated, 1);
50 | });
51 | });
52 |
--------------------------------------------------------------------------------
/tests/acceptance/x-defaults-test.js:
--------------------------------------------------------------------------------
1 | import { test } from 'qunit';
2 | import moduleForAcceptance from '../helpers/module-for-acceptance';
3 |
4 | moduleForAcceptance('Acceptance: Defaults X Test');
5 |
6 | test('checkbox input with default value should not be dirty when unchecked', function(assert) {
7 | visit('/defaultx');
8 | andThen(() => {
9 | assert.equal(find("input.funny").is(":checked"), true);
10 | assert.equal(find(".funnyDirty").text(), "");
11 | assert.equal(find(".funnyPrimed").text(), "");
12 | });
13 | click("input.funny");
14 | andThen(() => {
15 | assert.equal(find("input.funny").is(":checked"), false);
16 | assert.equal(find(".funnyDirty").text(), "true");
17 | assert.equal(find(".funnyPrimed").text(), "true");
18 | });
19 | click("input.funny");
20 | andThen(() => {
21 | assert.equal(find("input.funny").is(":checked"), true);
22 | assert.equal(find(".funnyDirty").text(), "");
23 | assert.equal(find(".funnyPrimed").text(), "true");
24 | });
25 | click("input.funny");
26 | andThen(() => {
27 | assert.equal(find("input.funny").is(":checked"), false);
28 | assert.equal(find(".funnyDirty").text(), "true");
29 | assert.equal(find(".funnyPrimed").text(), "true");
30 | });
31 | });
32 |
--------------------------------------------------------------------------------
/tests/dummy/app/app.js:
--------------------------------------------------------------------------------
1 | import Application from '@ember/application';
2 | import Resolver from './resolver';
3 | import loadInitializers from 'ember-load-initializers';
4 | import config from './config/environment';
5 |
6 | const App = Application.extend({
7 | modulePrefix: config.modulePrefix,
8 | podModulePrefix: config.podModulePrefix,
9 | Resolver
10 | });
11 |
12 | loadInitializers(App, config.modulePrefix);
13 |
14 | export default App;
15 |
--------------------------------------------------------------------------------
/tests/dummy/app/components/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toranb/ember-cli-simple-store/ac6955430e26a7cd833aa3764228f4e3f8f96748/tests/dummy/app/components/.gitkeep
--------------------------------------------------------------------------------
/tests/dummy/app/controllers/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toranb/ember-cli-simple-store/ac6955430e26a7cd833aa3764228f4e3f8f96748/tests/dummy/app/controllers/.gitkeep
--------------------------------------------------------------------------------
/tests/dummy/app/controllers/delete-object.js:
--------------------------------------------------------------------------------
1 | import { inject as service } from '@ember/service';
2 | import Controller from '@ember/controller';
3 |
4 | export default Controller.extend({
5 | simpleStore: service(),
6 | actions: {
7 | stop: function() {
8 | let simpleStore = this.get("simpleStore");
9 | simpleStore.remove("wat", 1);
10 | }
11 | }
12 | });
13 |
--------------------------------------------------------------------------------
/tests/dummy/app/controllers/relationships.js:
--------------------------------------------------------------------------------
1 | import Controller from '@ember/controller';
2 |
3 | export default Controller.extend({
4 | actions: {
5 | changed: function(new_role_id) {
6 | let user = this.get("model");
7 | user.change_role(new_role_id);
8 | }
9 | }
10 | });
11 |
--------------------------------------------------------------------------------
/tests/dummy/app/helpers/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toranb/ember-cli-simple-store/ac6955430e26a7cd833aa3764228f4e3f8f96748/tests/dummy/app/helpers/.gitkeep
--------------------------------------------------------------------------------
/tests/dummy/app/helpers/is-equal.js:
--------------------------------------------------------------------------------
1 | import { helper } from '@ember/component/helper';
2 |
3 | export default helper((params) => {
4 | return params[0] === params[1];
5 | });
6 |
--------------------------------------------------------------------------------
/tests/dummy/app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Dummy
7 |
8 |
9 |
10 | {{content-for "head"}}
11 |
12 |
13 |
14 |
15 | {{content-for "head-footer"}}
16 |
17 |
18 | {{content-for "body"}}
19 |
20 |
21 |
22 |
23 | {{content-for "body-footer"}}
24 |
25 |
26 |
--------------------------------------------------------------------------------
/tests/dummy/app/models/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toranb/ember-cli-simple-store/ac6955430e26a7cd833aa3764228f4e3f8f96748/tests/dummy/app/models/.gitkeep
--------------------------------------------------------------------------------
/tests/dummy/app/models/custom-key.js:
--------------------------------------------------------------------------------
1 | import { attr, Model } from "ember-cli-simple-store/model";
2 |
3 | let CustomKeyModel = Model.extend({
4 | name: attr()
5 | });
6 |
7 | CustomKeyModel.reopenClass({
8 | primaryKey: 'arbitraryKey'
9 | });
10 |
11 | export default CustomKeyModel;
12 |
--------------------------------------------------------------------------------
/tests/dummy/app/models/foo.js:
--------------------------------------------------------------------------------
1 | import { attr, Model } from "ember-cli-simple-store/model";
2 |
3 | export default Model.extend({
4 | name: attr(),
5 | funny: attr(false)
6 | });
7 |
--------------------------------------------------------------------------------
/tests/dummy/app/models/robot.js:
--------------------------------------------------------------------------------
1 | import { attr, Model } from "ember-cli-simple-store/model";
2 |
3 | export default Model.extend({
4 | name: attr()
5 | });
6 |
--------------------------------------------------------------------------------
/tests/dummy/app/models/role.js:
--------------------------------------------------------------------------------
1 | import { attr, Model } from "ember-cli-simple-store/model";
2 |
3 | export default Model.extend({
4 | name: attr()
5 | });
6 |
--------------------------------------------------------------------------------
/tests/dummy/app/models/user.js:
--------------------------------------------------------------------------------
1 | import { computed } from '@ember/object';
2 | import { alias } from '@ember/object/computed';
3 | import { inject as service } from '@ember/service';
4 | import { attr, Model } from "ember-cli-simple-store/model";
5 |
6 | export default Model.extend({
7 | name: attr(),
8 | simpleStore: service(),
9 | role: alias("belongs_to.firstObject"),
10 | belongs_to: computed(function() {
11 | let user_id = this.get("id");
12 | let store = this.get("simpleStore");
13 | let filter = function(role) {
14 | let users = role.get("users");
15 | return users.indexOf(user_id) > -1;
16 | };
17 | return store.find("role", filter);
18 | }),
19 | change_role(new_role_id) {
20 | let user_name = this.get("name");
21 | let user_id = this.get("id");
22 | let store = this.get("simpleStore");
23 | let old_role = this.get("role");
24 | let old_role_users = old_role.get("users") || [];
25 | let updated_old_role_users = old_role_users.filter((id) => {
26 | return id !== user_id;
27 | });
28 | let new_role = store.find("role", new_role_id);
29 | let new_role_users = new_role.get("users") || [];
30 | store.push("user", {id: user_id, name: user_name}); //only to test perf
31 | // old_role.set("users", updated_old_role_users); in v3 this worked but v4 requires a push
32 | store.push("role", {id: old_role.get("id"), users: updated_old_role_users});
33 | // new_role.set("users", new_role_users.concat(user_id)); in v3 this worked but v4 requires a push
34 | store.push("role", {id: new_role.get("id"), users: new_role_users.concat(user_id)});
35 | store.push("user", {id: user_id, nope: "wat"}); //only to test perf
36 | }
37 | });
38 |
--------------------------------------------------------------------------------
/tests/dummy/app/models/wat.js:
--------------------------------------------------------------------------------
1 | import { observer } from '@ember/object';
2 | import { later, cancel } from '@ember/runloop';
3 | import { attr, Model } from "ember-cli-simple-store/model";
4 |
5 | let onTimeout = function() {
6 | if(!this.isDestroyed) {
7 | let number = this.get("number");
8 | this.set("number", number + 1);
9 | }
10 | this.timer = later(onTimeout.bind(this), 100);
11 | };
12 |
13 | export default Model.extend({
14 | number: attr(),
15 | init() {
16 | this.timer = later(onTimeout.bind(this), 100);
17 | this._super();
18 | },
19 | observeNumber: observer("number", function() {
20 | let number = this.get("number");
21 | window.number = number + 1;
22 | }),
23 | willDestroy() {
24 | cancel(this.timer);
25 | }
26 | });
27 |
--------------------------------------------------------------------------------
/tests/dummy/app/models/wow.js:
--------------------------------------------------------------------------------
1 | import { attr, Model } from "ember-cli-simple-store/model";
2 |
3 | export default Model.extend({
4 | name: attr(""),
5 | funny: attr()
6 | });
7 |
--------------------------------------------------------------------------------
/tests/dummy/app/models/zap.js:
--------------------------------------------------------------------------------
1 | import { attr, Model } from "ember-cli-simple-store/model";
2 |
3 | export default Model.extend({
4 | name: attr(),
5 | funny: attr()
6 | });
7 |
--------------------------------------------------------------------------------
/tests/dummy/app/models/zing.js:
--------------------------------------------------------------------------------
1 | import { attr, Model } from "ember-cli-simple-store/model";
2 |
3 | export default Model.extend({
4 | name: attr()
5 | });
6 |
--------------------------------------------------------------------------------
/tests/dummy/app/resolver.js:
--------------------------------------------------------------------------------
1 | import Resolver from 'ember-resolver';
2 |
3 | export default Resolver;
4 |
--------------------------------------------------------------------------------
/tests/dummy/app/router.js:
--------------------------------------------------------------------------------
1 | import EmberRouter from '@ember/routing/router';
2 | import config from './config/environment';
3 |
4 | const Router = EmberRouter.extend({
5 | location: config.locationType,
6 | rootURL: config.rootURL
7 | });
8 |
9 | Router.map(function() {
10 | this.route("wat", {path: "/wat"});
11 | this.route("defaulta", {path: "/defaulta"});
12 | this.route("defaultb", {path: "/defaultb"});
13 | this.route("defaultx", {path: "/defaultx"});
14 | this.route("edit", {path: "/edit"});
15 | this.route("isnone", {path: "/isnone"});
16 | this.route("relationships", {path: "/relationships"});
17 | this.route("arrays", {path: "/arrays"});
18 | this.route("filters", {path: "/filters"});
19 | this.route("robots", {path: "/robots"});
20 | this.route("custom-key");
21 | this.route("delete-object");
22 | });
23 |
24 | export default Router;
25 |
--------------------------------------------------------------------------------
/tests/dummy/app/routes/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toranb/ember-cli-simple-store/ac6955430e26a7cd833aa3764228f4e3f8f96748/tests/dummy/app/routes/.gitkeep
--------------------------------------------------------------------------------
/tests/dummy/app/routes/arrays.js:
--------------------------------------------------------------------------------
1 | import { inject as service } from '@ember/service';
2 | import Route from '@ember/routing/route';
3 | import { get } from '@ember/object';
4 |
5 | let ArraysRoute = Route.extend({
6 | simpleStore: service(),
7 | model() {
8 | let simpleStore = this.get("simpleStore");
9 | if(simpleStore.find("robot").get("length") === 0) {
10 | // hack to prevent another push of the same data
11 | simpleStore.pushArray("robot",
12 | [
13 | {id: 1, name: "r one", size: 51},
14 | {id: 2, name: "r two", size: 52},
15 | {id: 3, name: "r three", size: 53}
16 | ]
17 | );
18 |
19 | simpleStore.pushArray("zing",
20 | [
21 | {id: 1, name: "z one", number: 49},
22 | {id: 2, name: "z two", number: 48},
23 | {id: 3, name: "z three", number: 47}
24 | ]
25 | );
26 | }
27 | let one = function(m) {
28 | return get(m, "size") > 50;
29 | };
30 | let two = function(m) {
31 | return get(m, "size") > 10;
32 | };
33 | let three = function(m) {
34 | return get(m, "number") < 50;
35 | };
36 | let four = function(m) {
37 | return get(m, "number") < 90;
38 | };
39 | let filterone = simpleStore.find("robot", one);
40 | let filtertwo = simpleStore.find("robot", two);
41 | let filterthree = simpleStore.find("zing", three);
42 | let filterfour = simpleStore.find("zing", four);
43 | return {filterone, filtertwo, filterthree, filterfour};
44 | },
45 | setupController(controller, hash) {
46 | controller.set("filterone", hash.filterone);
47 | controller.set("filtertwo", hash.filtertwo);
48 | controller.set("filterthree", hash.filterthree);
49 | controller.set("filterfour", hash.filterfour);
50 | },
51 | actions: {
52 | willTransition() {
53 | let currentModel = this.get("currentModel");
54 | currentModel.filterone.destroy();
55 | currentModel.filtertwo.destroy();
56 | currentModel.filterthree.destroy();
57 | currentModel.filterfour.destroy();
58 | }
59 | }
60 | });
61 |
62 | export default ArraysRoute;
63 |
--------------------------------------------------------------------------------
/tests/dummy/app/routes/custom-key.js:
--------------------------------------------------------------------------------
1 | import { inject as service } from '@ember/service';
2 | import Route from '@ember/routing/route';
3 |
4 | export default Route.extend({
5 | simpleStore: service(),
6 | model() {
7 | let simpleStore = this.get("simpleStore");
8 | if(simpleStore.find("custom-key").get("length") === 0) {
9 | //hack to prevent another push of the same data
10 | simpleStore.push("custom-key", {arbitraryKey: 1, name: "k one"});
11 | simpleStore.push("custom-key", {arbitraryKey: 2, name: "k two"});
12 | simpleStore.push("custom-key", {arbitraryKey: 3, name: "k three"});
13 | }
14 |
15 | return simpleStore.find('custom-key', (record =>
16 | record.get('name').indexOf('three') >= 0));
17 | },
18 | actions: {
19 | willTransition () {
20 | this.get('controller.model').destroy();
21 | }
22 | }
23 | });
24 |
--------------------------------------------------------------------------------
/tests/dummy/app/routes/defaulta.js:
--------------------------------------------------------------------------------
1 | import Route from '@ember/routing/route';
2 | import Foo from 'dummy/models/foo';
3 |
4 | export default Route.extend({
5 | model: function() {
6 | return Foo.create();
7 | }
8 | });
9 |
--------------------------------------------------------------------------------
/tests/dummy/app/routes/defaultb.js:
--------------------------------------------------------------------------------
1 | import Route from '@ember/routing/route';
2 | import Wow from 'dummy/models/wow';
3 |
4 | export default Route.extend({
5 | model: function() {
6 | return Wow.create();
7 | }
8 | });
9 |
--------------------------------------------------------------------------------
/tests/dummy/app/routes/defaultx.js:
--------------------------------------------------------------------------------
1 | import Route from '@ember/routing/route';
2 | import Foo from 'dummy/models/foo';
3 |
4 | export default Route.extend({
5 | model: function() {
6 | return Foo.create({name: "wat", funny: true});
7 | }
8 | });
9 |
--------------------------------------------------------------------------------
/tests/dummy/app/routes/delete-object.js:
--------------------------------------------------------------------------------
1 | import { inject as service } from '@ember/service';
2 | import Route from '@ember/routing/route';
3 |
4 | export default Route.extend({
5 | simpleStore: service(),
6 | model() {
7 | let simpleStore = this.get("simpleStore");
8 | return simpleStore.push("wat", {id: 1, number: 0});
9 | }
10 | });
11 |
--------------------------------------------------------------------------------
/tests/dummy/app/routes/edit.js:
--------------------------------------------------------------------------------
1 | import Route from '@ember/routing/route';
2 | import Foo from 'dummy/models/foo';
3 |
4 | let EditRoute = Route.extend({
5 | model: function() {
6 | return Foo.create({id: 1, name: "toran"});
7 | }
8 | });
9 |
10 | export default EditRoute;
11 |
--------------------------------------------------------------------------------
/tests/dummy/app/routes/filters.js:
--------------------------------------------------------------------------------
1 | import { inject as service } from '@ember/service';
2 | import Route from '@ember/routing/route';
3 | import { get } from '@ember/object';
4 |
5 | let FiltersRoute = Route.extend({
6 | simpleStore: service(),
7 | model() {
8 | let simpleStore = this.get("simpleStore");
9 | if(simpleStore.find("robot").get("length") === 0) {
10 | //hack to prevent another push of the same data
11 | simpleStore.push("robot", {id: 1, name: "r one", size: 51});
12 | simpleStore.push("robot", {id: 2, name: "r two", size: 52});
13 | simpleStore.push("robot", {id: 3, name: "r three", size: 53});
14 | simpleStore.push("zing", {id: 1, name: "z one", number: 49});
15 | simpleStore.push("zing", {id: 2, name: "z two", number: 48});
16 | simpleStore.push("zing", {id: 3, name: "z three", number: 47});
17 | }
18 | let one = function(m) {
19 | return get(m, "size") > 50;
20 | };
21 | let two = function(m) {
22 | return get(m, "size") > 10;
23 | };
24 | let three = function(m) {
25 | return get(m, "number") < 50;
26 | };
27 | let four = function(m) {
28 | return get(m, "number") < 90;
29 | };
30 | let filterone = simpleStore.find("robot", one);
31 | let filtertwo = simpleStore.find("robot", two);
32 | let filterthree = simpleStore.find("zing", three);
33 | let filterfour = simpleStore.find("zing", four);
34 | return {filterone, filtertwo, filterthree, filterfour};
35 | },
36 | setupController(controller, hash) {
37 | controller.set("filterone", hash.filterone);
38 | controller.set("filtertwo", hash.filtertwo);
39 | controller.set("filterthree", hash.filterthree);
40 | controller.set("filterfour", hash.filterfour);
41 | },
42 | actions: {
43 | willTransition() {
44 | let currentModel = this.get("currentModel");
45 | currentModel.filterone.destroy();
46 | currentModel.filtertwo.destroy();
47 | currentModel.filterthree.destroy();
48 | currentModel.filterfour.destroy();
49 | }
50 | }
51 | });
52 |
53 | export default FiltersRoute;
54 |
--------------------------------------------------------------------------------
/tests/dummy/app/routes/isnone.js:
--------------------------------------------------------------------------------
1 | import { A } from '@ember/array';
2 | import Route from '@ember/routing/route';
3 | import Foo from 'dummy/models/foo';
4 |
5 | let IsNoneRoute = Route.extend({
6 | model: function() {
7 | let one = Foo.create({id: 1, name: undefined});
8 | let two = Foo.create({id: 2, name: null});
9 | return A([one, two]);
10 | }
11 | });
12 |
13 | export default IsNoneRoute;
14 |
--------------------------------------------------------------------------------
/tests/dummy/app/routes/relationships.js:
--------------------------------------------------------------------------------
1 | import { inject as service } from '@ember/service';
2 | import Route from '@ember/routing/route';
3 |
4 | let RelationshipsRoute = Route.extend({
5 | simpleStore: service(),
6 | model() {
7 | let user_id = 2;
8 | let simpleStore = this.get("simpleStore");
9 | simpleStore.push("role", {id: 8, name: "Admin", users: []});
10 | simpleStore.push("role", {id: 9, name: "Guest", users: [user_id]});
11 | simpleStore.push("user", {id: user_id, name: "toran"});
12 | let model = simpleStore.find("user", user_id);
13 | let roles = simpleStore.find("role");
14 | return {model: model, roles: roles};
15 | },
16 | setupController(controller, hash) {
17 | controller.set("model", hash.model);
18 | controller.set("roles", hash.roles);
19 | }
20 | });
21 |
22 | export default RelationshipsRoute;
23 |
--------------------------------------------------------------------------------
/tests/dummy/app/routes/robots.js:
--------------------------------------------------------------------------------
1 | import { inject as service } from '@ember/service';
2 | import Route from '@ember/routing/route';
3 | import { get } from '@ember/object';
4 |
5 | let RobotsRoute = Route.extend({
6 | simpleStore: service(),
7 | model: function() {
8 | let simpleStore = this.get("simpleStore");
9 | simpleStore.push("robot", {id: 9, name: "nine", size: 229});
10 | simpleStore.push("robot", {id: 8, name: "eight", size: 9});
11 | simpleStore.push("robot", {id: 7, name: "seven", size: 11});
12 | //this filter existed previously but was removed (now it will be recreated)
13 | let one = function(m) {
14 | return get(m, "size") > 50;
15 | };
16 | //this filter is new and different
17 | let eight = function(m) {
18 | return get(m, "size") > 10 && get(m, "name") === "seven";
19 | };
20 | let filternine = simpleStore.find("robot", one);
21 | let filtereight = simpleStore.find("robot", eight);
22 | return {filternine, filtereight};
23 | },
24 | setupController: function(controller, hash) {
25 | controller.set("filternine", hash.filternine);
26 | controller.set("filtereight", hash.filtereight);
27 | }
28 | });
29 |
30 | export default RobotsRoute;
31 |
--------------------------------------------------------------------------------
/tests/dummy/app/routes/wat.js:
--------------------------------------------------------------------------------
1 | import Route from '@ember/routing/route';
2 | import Foo from 'dummy/models/foo';
3 |
4 | let WatRoute = Route.extend({
5 | model: function() {
6 | return Foo.create();
7 | }
8 | });
9 |
10 | export default WatRoute;
11 |
--------------------------------------------------------------------------------
/tests/dummy/app/styles/app.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | margin: 20px;
3 | }
4 |
--------------------------------------------------------------------------------
/tests/dummy/app/templates/application.hbs:
--------------------------------------------------------------------------------
1 | Welcome to Ember
2 |
3 | {{outlet}}
4 |
--------------------------------------------------------------------------------
/tests/dummy/app/templates/arrays.hbs:
--------------------------------------------------------------------------------
1 |
6 |
11 |
16 |
21 |
22 | {{#link-to 'wat' class='link-wat'}}wat{{/link-to}}
23 | {{#link-to 'robots' class='link-robots'}}robots{{/link-to}}
24 |
--------------------------------------------------------------------------------
/tests/dummy/app/templates/custom-key.hbs:
--------------------------------------------------------------------------------
1 |
6 | {{#link-to 'wat' class='link-wat'}}wat{{/link-to}}
7 |
--------------------------------------------------------------------------------
/tests/dummy/app/templates/defaulta.hbs:
--------------------------------------------------------------------------------
1 | {{input class="name" value=model.name}}
2 | {{input class="funny" checked=model.funny type="checkbox"}}
3 | {{model.nameIsDirty}}
4 | {{model.nameIsPrimed}}
5 | {{model.funnyIsDirty}}
6 | {{model.funnyIsPrimed}}
7 |
--------------------------------------------------------------------------------
/tests/dummy/app/templates/defaultb.hbs:
--------------------------------------------------------------------------------
1 | {{input class="name" value=model.name}}
2 | {{input class="funny" checked=model.funny type="checkbox"}}
3 | {{model.nameIsDirty}}
4 | {{model.nameIsPrimed}}
5 | {{model.funnyIsDirty}}
6 | {{model.funnyIsPrimed}}
7 |
--------------------------------------------------------------------------------
/tests/dummy/app/templates/defaultx.hbs:
--------------------------------------------------------------------------------
1 | {{input class="name" value=model.name}}
2 | {{input class="funny" checked=model.funny type="checkbox"}}
3 | {{model.nameIsDirty}}
4 | {{model.nameIsPrimed}}
5 | {{model.funnyIsDirty}}
6 | {{model.funnyIsPrimed}}
7 |
--------------------------------------------------------------------------------
/tests/dummy/app/templates/delete-object.hbs:
--------------------------------------------------------------------------------
1 | {{model.number}}
2 |
3 |
--------------------------------------------------------------------------------
/tests/dummy/app/templates/edit.hbs:
--------------------------------------------------------------------------------
1 | {{input class="name" value=model.name}}
2 | {{model.nameIsDirty}}
3 | {{model.nameIsPrimed}}
4 |
--------------------------------------------------------------------------------
/tests/dummy/app/templates/filters.hbs:
--------------------------------------------------------------------------------
1 |
6 |
11 |
16 |
21 |
22 | {{#link-to 'wat' class='link-wat'}}wat{{/link-to}}
23 | {{#link-to 'robots' class='link-robots'}}robots{{/link-to}}
24 |
--------------------------------------------------------------------------------
/tests/dummy/app/templates/isnone.hbs:
--------------------------------------------------------------------------------
1 | {{#each model as |item|}}
2 | {{input class="name" value=item.name}}
3 | {{item.nameIsDirty}}
4 | {{item.nameIsPrimed}}
5 | {{/each}}
6 |
--------------------------------------------------------------------------------
/tests/dummy/app/templates/relationships.hbs:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/tests/dummy/app/templates/robots.hbs:
--------------------------------------------------------------------------------
1 |
6 |
11 |
12 | {{#link-to 'wat' class='link-wat'}}wat{{/link-to}}
13 | {{#link-to 'filters' class='link-filters'}}filters{{/link-to}}
14 |
--------------------------------------------------------------------------------
/tests/dummy/app/templates/wat.hbs:
--------------------------------------------------------------------------------
1 | {{input class="name" value=model.name}}
2 |
3 | {{#link-to 'filters' class='link-filters'}}filters{{/link-to}}
4 | {{#link-to 'robots' class='link-robots'}}robots{{/link-to}}
5 |
--------------------------------------------------------------------------------
/tests/dummy/config/environment.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function(environment) {
4 | let ENV = {
5 | modulePrefix: 'dummy',
6 | environment,
7 | rootURL: '/',
8 | locationType: 'auto',
9 | EmberENV: {
10 | FEATURES: {
11 | // Here you can enable experimental features on an ember canary build
12 | // e.g. 'with-controller': true
13 | },
14 | EXTEND_PROTOTYPES: {
15 | // Prevent Ember Data from overriding Date.parse.
16 | Date: false
17 | }
18 | },
19 |
20 | APP: {
21 | // Here you can pass flags/options to your application instance
22 | // when it is created
23 | }
24 | };
25 |
26 | if (environment === 'development') {
27 | // ENV.APP.LOG_RESOLVER = true;
28 | // ENV.APP.LOG_ACTIVE_GENERATION = true;
29 | // ENV.APP.LOG_TRANSITIONS = true;
30 | // ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
31 | // ENV.APP.LOG_VIEW_LOOKUPS = true;
32 | }
33 |
34 | if (environment === 'test') {
35 | // Testem prefers this...
36 | ENV.locationType = 'none';
37 |
38 | // keep test console output quieter
39 | ENV.APP.LOG_ACTIVE_GENERATION = false;
40 | ENV.APP.LOG_VIEW_LOOKUPS = false;
41 |
42 | ENV.APP.rootElement = '#ember-testing';
43 | ENV.APP.autoboot = false;
44 | }
45 |
46 | if (environment === 'production') {
47 | // here you can enable a production-specific feature
48 | }
49 |
50 | return ENV;
51 | };
52 |
--------------------------------------------------------------------------------
/tests/dummy/config/targets.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const browsers = [
4 | 'last 1 Chrome versions',
5 | 'last 1 Firefox versions',
6 | 'last 1 Safari versions'
7 | ];
8 |
9 | const isCI = !!process.env.CI;
10 | const isProduction = process.env.EMBER_ENV === 'production';
11 |
12 | if (isCI || isProduction) {
13 | browsers.push('ie 11');
14 | }
15 |
16 | module.exports = {
17 | browsers
18 | };
19 |
--------------------------------------------------------------------------------
/tests/dummy/public/robots.txt:
--------------------------------------------------------------------------------
1 | # http://www.robotstxt.org
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/tests/helpers/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toranb/ember-cli-simple-store/ac6955430e26a7cd833aa3764228f4e3f8f96748/tests/helpers/.gitkeep
--------------------------------------------------------------------------------
/tests/helpers/destroy-app.js:
--------------------------------------------------------------------------------
1 | import { run } from '@ember/runloop';
2 |
3 | export default function destroyApp(application) {
4 | run(application, 'destroy');
5 | }
6 |
--------------------------------------------------------------------------------
/tests/helpers/module-for-acceptance.js:
--------------------------------------------------------------------------------
1 | import { resolve } from 'rsvp';
2 | import { module } from 'qunit';
3 | import startApp from '../helpers/start-app';
4 | import destroyApp from '../helpers/destroy-app';
5 |
6 | export default function(name, options = {}) {
7 | module(name, {
8 | beforeEach() {
9 | this.application = startApp();
10 |
11 | if (options.beforeEach) {
12 | return options.beforeEach.apply(this, arguments);
13 | }
14 | },
15 |
16 | afterEach() {
17 | let afterEach = options.afterEach && options.afterEach.apply(this, arguments);
18 | return resolve(afterEach).then(() => destroyApp(this.application));
19 | }
20 | });
21 | }
22 |
--------------------------------------------------------------------------------
/tests/helpers/qunit.js:
--------------------------------------------------------------------------------
1 | import { warn } from '@ember/debug';
2 |
3 | let qunit = function deprecatedQunitHelper() {
4 | warn(
5 | "The ember-cli-simple-store `qunit` test helper has been moved. Please update your imports to `import { test } from 'ember-cli-simple-store/test-support/qunit';`",
6 | false,
7 | { id: 'ember-cli-simple-store.qunit-import' }
8 | );
9 | }
10 |
11 | export { qunit };
12 |
--------------------------------------------------------------------------------
/tests/helpers/registration.js:
--------------------------------------------------------------------------------
1 | import SimpleStore from "ember-cli-simple-store/store";
2 |
3 | export default function(owner, keys) {
4 | let factory = window.require("ember-resolver")["default"];
5 | let resolver = factory.create({ namespace: { modulePrefix: "dummy" }});
6 |
7 | owner.register("service:simple-store", SimpleStore);
8 |
9 | keys.forEach((key) => {
10 | owner.register(key, resolver.resolve("dummy@" + key));
11 | });
12 |
13 | return owner.lookup("service:simple-store");
14 | }
15 |
--------------------------------------------------------------------------------
/tests/helpers/resolver.js:
--------------------------------------------------------------------------------
1 | import Resolver from '../../resolver';
2 | import config from '../../config/environment';
3 |
4 | const resolver = Resolver.create();
5 |
6 | resolver.namespace = {
7 | modulePrefix: config.modulePrefix,
8 | podModulePrefix: config.podModulePrefix
9 | };
10 |
11 | export default resolver;
12 |
--------------------------------------------------------------------------------
/tests/helpers/start-app.js:
--------------------------------------------------------------------------------
1 | import { run } from '@ember/runloop';
2 | import { merge } from '@ember/polyfills';
3 | import Application from '../../app';
4 | import config from '../../config/environment';
5 |
6 | export default function startApp(attrs) {
7 | let attributes = merge({}, config.APP);
8 | attributes.autoboot = true;
9 | attributes = merge(attributes, attrs); // use defaults, but you can override;
10 |
11 | return run(() => {
12 | let application = Application.create(attributes);
13 | application.setupForTesting();
14 | application.injectTestHelpers();
15 | return application;
16 | });
17 | }
18 |
--------------------------------------------------------------------------------
/tests/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Dummy Tests
7 |
8 |
9 |
10 | {{content-for "head"}}
11 | {{content-for "test-head"}}
12 |
13 |
14 |
15 |
16 |
17 | {{content-for "head-footer"}}
18 | {{content-for "test-head-footer"}}
19 |
20 |
21 | {{content-for "body"}}
22 | {{content-for "test-body"}}
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | {{content-for "body-footer"}}
31 | {{content-for "test-body-footer"}}
32 |
33 |
34 |
--------------------------------------------------------------------------------
/tests/test-helper.js:
--------------------------------------------------------------------------------
1 | import Application from '../app';
2 | import config from '../config/environment';
3 | import { setApplication } from '@ember/test-helpers';
4 | import { start } from 'ember-qunit';
5 |
6 | setApplication(Application.create(config.APP));
7 |
8 | start();
9 |
--------------------------------------------------------------------------------
/tests/unit/arrays-test.js:
--------------------------------------------------------------------------------
1 | import EmberObject, { observer } from '@ember/object';
2 | import { getOwner } from '@ember/application';
3 | import { moduleFor } from "ember-qunit";
4 | import { test } from "ember-cli-simple-store/test-support/qunit";
5 |
6 | let Thing, Stuff;
7 |
8 | moduleFor("service:simple-store", "arrays unit tests", {
9 | beforeEach: function () {
10 | const owner = getOwner(this);
11 | this.store = this.subject();
12 | Stuff = EmberObject.extend();
13 |
14 | Thing = EmberObject.extend({
15 | observationCount: 0,
16 | name: "",
17 | stuff: this.store.find("stuff"),
18 | observeStuff: observer("stuff.[]", function () {
19 | let currentObservations = this.get("observationCount");
20 | this.set("observationCount", currentObservations + 1);
21 | })
22 | });
23 | owner.register("model:stuff", Stuff);
24 | },
25 | afterEach: function() {
26 | delete this.store;
27 | }
28 | });
29 |
30 | test("observers are only notified once regardless of the number of models added to the store", function (assert) {
31 | let thing1 = Thing.create({name: "thing1"});
32 |
33 | this.store.pushArray("stuff", [{ id: "1", name: "stuff1"}, { id: "2", name: "stuff2"}]);
34 |
35 | assert.equal(thing1.get("observationCount"), 1);
36 | });
37 |
--------------------------------------------------------------------------------
/tests/unit/default-attr-test.js:
--------------------------------------------------------------------------------
1 | import { module, test } from 'qunit';
2 | import { attr, Model } from "ember-cli-simple-store/model";
3 |
4 | let Animal, leopard;
5 |
6 | module("default attr unit tests", {
7 | beforeEach: function() {
8 | Animal = Model.extend({
9 | name: attr(""),
10 | fast: attr(false)
11 | });
12 | }
13 | });
14 |
15 | test("isDirty property on class will show correctly when set to default string value", function(assert){
16 | leopard = Animal.create({name: "toran", fast: true});
17 | assert.equal(false, leopard.get("isDirty"));
18 | leopard.set("name", "baz");
19 | assert.equal(true, leopard.get("isDirty"));
20 | assert.equal("baz", leopard.get("name"));
21 | leopard.set("name", "");
22 | assert.equal(true, leopard.get("isDirty"));
23 | assert.equal("", leopard.get("name"));
24 | assert.equal(true, leopard.get("nameIsDirty"));
25 | assert.equal(true, leopard.get("nameIsPrimed"));
26 | });
27 |
28 | test("isDirty property on class will show correctly when set to default boolean value", function(assert){
29 | leopard = Animal.create({name: "toran", fast: true});
30 | assert.equal(false, leopard.get("isDirty"));
31 | leopard.set("fast", false);
32 | assert.equal(true, leopard.get("isDirty"));
33 | assert.equal(false, leopard.get("fast"));
34 | assert.equal(true, leopard.get("fastIsDirty"));
35 | assert.equal(true, leopard.get("fastIsPrimed"));
36 | });
37 |
38 | test("save will reset isDirty", function(assert){
39 | leopard = Animal.create({name: "toran", fast: true});
40 | assert.equal(false, leopard.get("isDirty"));
41 | leopard.set("name", "baz");
42 | assert.equal(true, leopard.get("isDirty"));
43 | leopard.save();
44 | assert.equal(false, leopard.get("isDirty"));
45 | assert.equal("baz", leopard.get("name"));
46 | });
47 |
48 | test("rollback will reset isDirty for string attr with default value", function(assert){
49 | leopard = Animal.create({name: "toran", fast: true});
50 | assert.equal(false, leopard.get("isDirty"));
51 | leopard.set("name", "baz");
52 | assert.equal(true, leopard.get("isDirty"));
53 | leopard.rollback();
54 | assert.equal(false, leopard.get("isDirty"));
55 | assert.equal("toran", leopard.get("name"));
56 | leopard.set("name", "");
57 | assert.equal(true, leopard.get("isDirty"));
58 | leopard.rollback();
59 | assert.equal(false, leopard.get("isDirty"));
60 | assert.equal("toran", leopard.get("name"));
61 | });
62 |
63 | test("rollback will reset isDirty for boolean attr with default value", function(assert){
64 | leopard = Animal.create({name: "toran", fast: true});
65 | assert.equal(false, leopard.get("isDirty"));
66 | leopard.set("fast", false);
67 | assert.equal(true, leopard.get("isDirty"));
68 | leopard.rollback();
69 | assert.equal(false, leopard.get("isDirty"));
70 | assert.equal(true, leopard.get("fast"));
71 | });
72 |
73 | test("rollback after it has been saved will be a no-op", function(assert){
74 | leopard = Animal.create({name: "toran", fast: true});
75 | assert.equal(false, leopard.get("isDirty"));
76 | leopard.set("name", "baz");
77 | assert.equal(true, leopard.get("isDirty"));
78 | leopard.set("name", "wat");
79 | assert.equal(true, leopard.get("isDirty"));
80 | leopard.save();
81 | assert.equal(false, leopard.get("isDirty"));
82 | assert.equal("wat", leopard.get("name"));
83 | leopard.rollback();
84 | assert.equal(false, leopard.get("isDirty"));
85 | assert.equal("wat", leopard.get("name"));
86 | });
87 |
88 | test("isDirty on the model is reset only after all values set back to original values", function(assert){
89 | leopard = Animal.create({name: "toran", fast: true});
90 | assert.equal("toran", leopard.get("name"));
91 | assert.equal(true, leopard.get("fast"));
92 | assert.equal(false, leopard.get("isDirty"));
93 | leopard.set("name", "foo");
94 | leopard.set("fast", false);
95 | assert.equal(true, leopard.get("isDirty"));
96 | leopard.set("name", "toran");
97 | assert.equal(true, leopard.get("isDirty"));
98 | leopard.set("fast", true);
99 | assert.equal(false, leopard.get("isDirty"));
100 | });
101 |
102 | test("isDirty on the model is not reset when value is undefined and set to empty string", function(assert){
103 | leopard = Animal.create({name: undefined, fast: true});
104 | assert.equal(undefined, leopard.get("name"));
105 | assert.equal(false, leopard.get("isDirty"));
106 | leopard.set("name", "baz");
107 | assert.equal(true, leopard.get("isDirty"));
108 | leopard.set("name", undefined);
109 | assert.equal(false, leopard.get("isDirty"));
110 | leopard.set("name", "");
111 | assert.equal(false, leopard.get("isDirty"));
112 | });
113 |
114 | test("isDirty on the model is not reset when value is null and set to empty string", function(assert){
115 | leopard = Animal.create({name: null, fast: true});
116 | assert.equal(null, leopard.get("name"));
117 | assert.equal(false, leopard.get("isDirty"));
118 | leopard.set("name", "baz");
119 | assert.equal(true, leopard.get("isDirty"));
120 | leopard.set("name", undefined);
121 | assert.equal(true, leopard.get("isDirty"));
122 | leopard.set("name", null);
123 | assert.equal(false, leopard.get("isDirty"));
124 | leopard.set("name", "");
125 | assert.equal(false, leopard.get("isDirty"));
126 | });
127 |
128 | test("isDirty on the model is not reset when value is undefined and set to default boolean value", function(assert){
129 | leopard = Animal.create({name: "toran", fast: undefined});
130 | assert.equal(undefined, leopard.get("fast"));
131 | assert.equal(false, leopard.get("isDirty"));
132 | leopard.set("fast", true);
133 | assert.equal(true, leopard.get("isDirty"));
134 | leopard.set("fast", undefined);
135 | assert.equal(false, leopard.get("isDirty"));
136 | leopard.set("fast", false);
137 | assert.equal(false, leopard.get("isDirty"));
138 | });
139 |
140 | test("isDirty on the model is not reset when value is null and set to default boolean value", function(assert){
141 | leopard = Animal.create({name: "toran", fast: null});
142 | assert.equal(undefined, leopard.get("fast"));
143 | assert.equal(false, leopard.get("isDirty"));
144 | leopard.set("fast", true);
145 | assert.equal(true, leopard.get("isDirty"));
146 | leopard.set("fast", undefined);
147 | assert.equal(true, leopard.get("isDirty"));
148 | leopard.set("fast", null);
149 | assert.equal(false, leopard.get("isDirty"));
150 | leopard.set("fast", false);
151 | assert.equal(false, leopard.get("isDirty"));
152 | });
153 |
154 | test("isDirty on the model is reset when value starts as empty array and set back to empty array value", function(assert){
155 | let Batman = Model.extend({batarangs: attr()});
156 | let watman = Batman.create({batarangs: []});
157 | assert.deepEqual([], watman.get("batarangs"));
158 | assert.equal(false, watman.get("isDirty"));
159 | watman.set("batarangs", [1, 2]);
160 | assert.equal(true, watman.get("isDirty"));
161 | watman.set("batarangs", []);
162 | assert.equal(false, watman.get("isDirty"));
163 | watman.set("batarangs", [3]);
164 | assert.equal(true, watman.get("isDirty"));
165 | watman.set("batarangs", []);
166 | assert.equal(false, watman.get("isDirty"));
167 | });
168 |
169 | test("isDirty on the model is reset when value starts as empty array and set back to empty array value and default value is empty array", function(assert){
170 | let Batman = Model.extend({batarangs: attr([])});
171 | let watman = Batman.create({batarangs: []});
172 | assert.deepEqual([], watman.get("batarangs"));
173 | assert.equal(false, watman.get("isDirty"));
174 | watman.set("batarangs", [1, 2]);
175 | assert.equal(true, watman.get("isDirty"));
176 | watman.set("batarangs", []);
177 | assert.equal(false, watman.get("isDirty"));
178 | watman.set("batarangs", [3]);
179 | assert.equal(true, watman.get("isDirty"));
180 | watman.set("batarangs", []);
181 | assert.equal(false, watman.get("isDirty"));
182 | });
183 |
184 | test("isDirty on the model is reset when value starts as undefined and set to default array value", function(assert){
185 | let Batman = Model.extend({batarangs: attr([])});
186 | let watman = Batman.create({batarangs: undefined});
187 | assert.equal(undefined, watman.get("batarangs"));
188 | assert.equal(false, watman.get("isDirty"));
189 | watman.set("batarangs", [1, 2]);
190 | assert.equal(true, watman.get("isDirty"));
191 | watman.set("batarangs", []);
192 | assert.equal(false, watman.get("isDirty"));
193 | });
194 |
195 | test("rolling back a model with no changes is a no-op", function(assert){
196 | leopard = Animal.create({name: "toran", fast: true});
197 | assert.equal("toran", leopard.get("name"));
198 | assert.equal(true, leopard.get("fast"));
199 | assert.equal(false, leopard.get("isDirty"));
200 | assert.equal(undefined, leopard.get("nameIsDirty"));
201 | assert.equal(undefined, leopard.get("nameIsPrimed"));
202 | assert.equal(undefined, leopard.get("fastIsDirty"));
203 | assert.equal(undefined, leopard.get("fastIsPrimed"));
204 |
205 | leopard.rollback();
206 | assert.equal("toran", leopard.get("name"));
207 | assert.equal(true, leopard.get("fast"));
208 | assert.equal(false, leopard.get("isDirty"));
209 | assert.equal(undefined, leopard.get("nameIsDirty"));
210 | assert.equal(undefined, leopard.get("nameIsPrimed"));
211 | assert.equal(undefined, leopard.get("fastIsDirty"));
212 | assert.equal(undefined, leopard.get("fastIsPrimed"));
213 | });
214 |
215 | test("rolling back and saving a new model with no changes is a no-op", function(assert){
216 | leopard = Animal.create();
217 | assert.equal(undefined, leopard.get("name"));
218 | assert.equal(undefined, leopard.get("fast"));
219 | assert.equal(false, leopard.get("isDirty"));
220 | assert.equal(undefined, leopard.get("nameIsDirty"));
221 | assert.equal(undefined, leopard.get("nameIsPrimed"));
222 | assert.equal(undefined, leopard.get("fastIsDirty"));
223 | assert.equal(undefined, leopard.get("fastIsPrimed"));
224 | leopard.set("name", "wat");
225 |
226 | leopard.rollback();
227 | assert.equal(undefined, leopard.get("name"));
228 | assert.equal(undefined, leopard.get("fast"));
229 | assert.equal(false, leopard.get("isDirty"));
230 | assert.equal(undefined, leopard.get("nameIsDirty"));
231 | assert.equal(undefined, leopard.get("nameIsPrimed"));
232 | assert.equal(undefined, leopard.get("fastIsDirty"));
233 | assert.equal(undefined, leopard.get("fastIsPrimed"));
234 |
235 | leopard.save();
236 | assert.equal(undefined, leopard.get("name"));
237 | assert.equal(undefined, leopard.get("fast"));
238 | assert.equal(false, leopard.get("isDirty"));
239 | assert.equal(undefined, leopard.get("nameIsDirty"));
240 | assert.equal(undefined, leopard.get("nameIsPrimed"));
241 | assert.equal(undefined, leopard.get("fastIsDirty"));
242 | assert.equal(undefined, leopard.get("fastIsPrimed"));
243 |
244 | leopard.set("name", "wat");
245 | leopard.save();
246 | assert.equal("wat", leopard.get("name"));
247 | assert.equal(undefined, leopard.get("fast"));
248 | assert.equal(false, leopard.get("isDirty"));
249 | assert.equal(undefined, leopard.get("nameIsDirty"));
250 | assert.equal(undefined, leopard.get("nameIsPrimed"));
251 | assert.equal(undefined, leopard.get("fastIsDirty"));
252 | assert.equal(undefined, leopard.get("fastIsPrimed"));
253 | });
254 |
255 | test("isDirty is true if the values are cleared out", function(assert){
256 | leopard = Animal.create({name: "toran", fast: true});
257 | assert.equal(false, leopard.get("isDirty"));
258 | leopard.set("name", "");
259 | assert.equal(true, leopard.get("isDirty"));
260 | leopard.set("name", "toran");
261 | assert.equal(false, leopard.get("isDirty"));
262 | leopard.set("fast", false);
263 | assert.equal(true, leopard.get("isDirty"));
264 | leopard.set("fast", true);
265 | assert.equal(false, leopard.get("isDirty"));
266 | });
267 |
--------------------------------------------------------------------------------
/tests/unit/model-test.js:
--------------------------------------------------------------------------------
1 | import { computed } from '@ember/object';
2 | import { module, test } from 'qunit';
3 | import { attr, Model } from "ember-cli-simple-store/model";
4 |
5 | let Person, brandon;
6 | let data = {id: 1, firstName: "Brandon", lastName: "Williams"};
7 |
8 | module("model unit tests", {
9 | beforeEach: function() {
10 | Person = Model.extend({
11 | wat: "",
12 | firstName: attr(),
13 | lastName: attr(),
14 | fullName: computed(function() {
15 | let first = this.get("firstName");
16 | let last = this.get("lastName");
17 | return first + " " + last;
18 | }).property("firstName", "lastName")
19 | });
20 | }
21 | });
22 |
23 | test("attr will serve as both gettr and settr", function(assert){
24 | brandon = Person.create(data);
25 | assert.equal("Brandon", brandon.get("firstName"));
26 | assert.equal("Williams", brandon.get("lastName"));
27 | assert.equal("Brandon Williams", brandon.get("fullName"));
28 | brandon.set("firstName", "x");
29 | brandon.set("lastName", "y");
30 | assert.equal("x", brandon.get("firstName"));
31 | assert.equal("y", brandon.get("lastName"));
32 | assert.equal("x y", brandon.get("fullName"));
33 | });
34 |
35 | test("isDirty property on class will update if attr is changed", function(assert){
36 | brandon = Person.create(data);
37 | assert.equal(false, brandon.get("isDirty"));
38 | brandon.set("firstName", "baz");
39 | assert.equal(true, brandon.get("isDirty"));
40 | });
41 |
42 | test("isNotDirty property on class will reflect the inverse of isDirty computed", function(assert){
43 | brandon = Person.create(data);
44 | assert.equal(false, brandon.get("isDirty"));
45 | assert.equal(true, brandon.get("isNotDirty"));
46 | brandon.set("firstName", "baz");
47 | assert.equal(true, brandon.get("isDirty"));
48 | assert.equal(false, brandon.get("isNotDirty"));
49 | brandon.set("firstName", "Brandon");
50 | assert.equal(false, brandon.get("isDirty"));
51 | assert.equal(true, brandon.get("isNotDirty"));
52 | });
53 |
54 | test("isDirty property on class will not update if non attr is changed", function(assert){
55 | brandon = Person.create(data);
56 | assert.equal(false, brandon.get("isDirty"));
57 | brandon.set("wat", "baz");
58 | assert.equal(false, brandon.get("isDirty"));
59 | });
60 |
61 | test("save will reset isDirty", function(assert){
62 | brandon = Person.create(data);
63 | assert.equal(false, brandon.get("isDirty"));
64 | brandon.set("firstName", "baz");
65 | assert.equal(true, brandon.get("isDirty"));
66 | brandon.save();
67 | assert.equal(false, brandon.get("isDirty"));
68 | assert.equal("baz", brandon.get("firstName"));
69 | });
70 |
71 | test("save will update internal state", function(assert){
72 | brandon = Person.create(data);
73 | let preState = brandon.get("_oldState");
74 | assert.equal(2, Object.keys(preState).length);
75 | assert.equal("Brandon", preState["firstName"]);
76 | assert.equal("Williams", preState["lastName"]);
77 |
78 | brandon.set("firstName", "baz");
79 | let initState = brandon.get("_oldState");
80 | assert.equal(2, Object.keys(initState).length);
81 | assert.equal("Brandon", initState["firstName"]);
82 | assert.equal("Williams", initState["lastName"]);
83 |
84 | brandon.save();
85 | let postState = brandon.get("_oldState");
86 | assert.equal(2, Object.keys(postState).length);
87 | assert.equal("baz", postState["firstName"]);
88 | assert.equal("Williams", postState["lastName"]);
89 | });
90 |
91 | test("rollback will reset isDirty", function(assert){
92 | brandon = Person.create(data);
93 | assert.equal(false, brandon.get("isDirty"));
94 | brandon.set("firstName", "baz");
95 | assert.equal(true, brandon.get("isDirty"));
96 | brandon.rollback();
97 | assert.equal(false, brandon.get("isDirty"));
98 | assert.equal("Brandon", brandon.get("firstName"));
99 | });
100 |
101 | test("rollback will not alter the internal state", function(assert){
102 | brandon = Person.create(data);
103 | let preState = brandon.get("_oldState");
104 | assert.equal(2, Object.keys(preState).length);
105 | assert.equal("Brandon", preState["firstName"]);
106 | assert.equal("Williams", preState["lastName"]);
107 |
108 | brandon.set("firstName", "baz");
109 | let initState = brandon.get("_oldState");
110 | assert.equal(2, Object.keys(initState).length);
111 | assert.equal("Brandon", initState["firstName"]);
112 | assert.equal("Williams", initState["lastName"]);
113 |
114 | brandon.rollback();
115 | let postState = brandon.get("_oldState");
116 | assert.equal(2, Object.keys(postState).length);
117 | assert.equal("Brandon", postState["firstName"]);
118 | assert.equal("Williams", postState["lastName"]);
119 | });
120 |
121 | test("rollback after it has been saved will be a no-op", function(assert){
122 | brandon = Person.create(data);
123 | assert.equal(false, brandon.get("isDirty"));
124 | brandon.set("firstName", "baz");
125 | assert.equal(true, brandon.get("isDirty"));
126 | brandon.set("firstName", "wat");
127 | assert.equal(true, brandon.get("isDirty"));
128 | brandon.save();
129 | assert.equal(false, brandon.get("isDirty"));
130 | assert.equal("wat", brandon.get("firstName"));
131 | brandon.rollback();
132 | assert.equal(false, brandon.get("isDirty"));
133 | assert.equal("wat", brandon.get("firstName"));
134 | });
135 |
136 | test("internal state will be only set the first time a property is set", function(assert){
137 | brandon = Person.create(data);
138 | let preState = brandon.get("_oldState");
139 | assert.equal(2, Object.keys(preState).length);
140 | assert.equal("Brandon", preState["firstName"]);
141 | assert.equal("Williams", preState["lastName"]);
142 |
143 | brandon.set("firstName", "baz");
144 | let initState = brandon.get("_oldState");
145 | assert.equal(2, Object.keys(initState).length);
146 | assert.equal("Brandon", initState["firstName"]);
147 | assert.equal("Williams", initState["lastName"]);
148 | brandon.set("_oldState.firstName", "nogo");
149 | brandon.set("_oldState.lastName", "nope");
150 |
151 | brandon.set("firstName", "baz");
152 | let postState = brandon.get("_oldState");
153 | assert.equal(2, Object.keys(postState).length);
154 | assert.equal("nogo", postState["firstName"]);
155 | assert.equal("nope", postState["lastName"]);
156 | });
157 |
158 | test("isDirty on the individual property will update if attr is changed", function(assert){
159 | brandon = Person.create(data);
160 | assert.equal("Brandon", brandon.get("firstName"));
161 | assert.equal("Williams", brandon.get("lastName"));
162 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
163 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
164 | assert.equal(undefined, brandon.get("lastNameIsDirty"));
165 | assert.equal(undefined, brandon.get("lastNameIsPrimed"));
166 | brandon.set("lastName", "wat");
167 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
168 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
169 | assert.equal(true, brandon.get("lastNameIsDirty"));
170 | assert.equal(true, brandon.get("lastNameIsPrimed"));
171 | });
172 |
173 | test("isDirty on the individual property is reset after save", function(assert){
174 | brandon = Person.create(data);
175 | assert.equal("Brandon", brandon.get("firstName"));
176 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
177 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
178 | brandon.set("firstName", "baz");
179 | assert.equal(true, brandon.get("firstNameIsDirty"));
180 | assert.equal(true, brandon.get("firstNameIsPrimed"));
181 | brandon.save();
182 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
183 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
184 | });
185 |
186 | test("isDirty on the model is reset only after all values set back to original values", function(assert){
187 | brandon = Person.create(data);
188 | assert.equal("Brandon", brandon.get("firstName"));
189 | assert.equal("Williams", brandon.get("lastName"));
190 | assert.equal(false, brandon.get("isDirty"));
191 | brandon.set("firstName", "foo");
192 | brandon.set("lastName", "bar");
193 | assert.equal(true, brandon.get("isDirty"));
194 | brandon.set("firstName", "Brandon");
195 | assert.equal(true, brandon.get("isDirty"));
196 | brandon.set("lastName", "Williams");
197 | assert.equal(false, brandon.get("isDirty"));
198 | });
199 |
200 | test("isDirty on the model is reset after value set back to original value", function(assert){
201 | brandon = Person.create(data);
202 | assert.equal("Brandon", brandon.get("firstName"));
203 | assert.equal(false, brandon.get("isDirty"));
204 | brandon.set("firstName", "baz");
205 | assert.equal(true, brandon.get("isDirty"));
206 | brandon.set("firstName", "Brandon");
207 | assert.equal(false, brandon.get("isDirty"));
208 | });
209 |
210 | test("isDirty on the model is updated when value is empty string and later set to undefined", function(assert){
211 | brandon = Person.create({id: 1, firstName: "", lastName: "Williams"});
212 | assert.equal("", brandon.get("firstName"));
213 | assert.equal(false, brandon.get("isDirty"));
214 | brandon.set("firstName", "baz");
215 | assert.equal(true, brandon.get("isDirty"));
216 | brandon.set("firstName", "");
217 | assert.equal(false, brandon.get("isDirty"));
218 | brandon.set("firstName", undefined);
219 | assert.equal(true, brandon.get("isDirty"));
220 | });
221 |
222 | test("isDirty on the model is updated when value is undefined then set to undefined and later empty string", function(assert){
223 | brandon = Person.create({id: 1, firstName: undefined, lastName: "Williams"});
224 | assert.equal(undefined, brandon.get("firstName"));
225 | assert.equal(false, brandon.get("isDirty"));
226 | brandon.set("firstName", "baz");
227 | assert.equal(true, brandon.get("isDirty"));
228 | brandon.set("firstName", undefined);
229 | assert.equal(false, brandon.get("isDirty"));
230 | brandon.set("firstName", "");
231 | assert.equal(true, brandon.get("isDirty"));
232 | });
233 |
234 | test("isDirty on the model is updated when value is null then set to empty string and later null", function(assert){
235 | brandon = Person.create({id: 1, firstName: null, lastName: "Williams"});
236 | assert.equal(null, brandon.get("firstName"));
237 | assert.equal(false, brandon.get("isDirty"));
238 | brandon.set("firstName", "baz");
239 | assert.equal(true, brandon.get("isDirty"));
240 | brandon.set("firstName", "");
241 | assert.equal(true, brandon.get("isDirty"));
242 | brandon.set("firstName", null);
243 | assert.equal(false, brandon.get("isDirty"));
244 | });
245 |
246 | test("isDirty on the model is updated when value is undefined then set to empty string and later undefined", function(assert){
247 | brandon = Person.create({id: 1, firstName: undefined, lastName: "Williams"});
248 | assert.equal(undefined, brandon.get("firstName"));
249 | assert.equal(false, brandon.get("isDirty"));
250 | brandon.set("firstName", "baz");
251 | assert.equal(true, brandon.get("isDirty"));
252 | brandon.set("firstName", "");
253 | assert.equal(true, brandon.get("isDirty"));
254 | brandon.set("firstName", undefined);
255 | assert.equal(false, brandon.get("isDirty"));
256 | });
257 |
258 | test("isDirty on the model is reset when original value is null and set back to null", function(assert){
259 | brandon = Person.create({id: 1, firstName: null, lastName: "Williams"});
260 | assert.equal(undefined, brandon.get("firstName"));
261 | assert.equal(false, brandon.get("isDirty"));
262 | brandon.set("firstName", "baz");
263 | assert.equal(true, brandon.get("isDirty"));
264 | brandon.set("firstName", null);
265 | assert.equal(false, brandon.get("isDirty"));
266 | assert.equal(undefined, brandon.get("firstName"));
267 | });
268 |
269 | test("isDirty on the model is reset when original value is 0 and set back to 0", function(assert){
270 | brandon = Person.create({id: 1, firstName: 0, lastName: "Williams"});
271 | assert.equal(0, brandon.get("firstName"));
272 | assert.equal(false, brandon.get("isDirty"));
273 | brandon.set("firstName", "baz");
274 | assert.equal(true, brandon.get("isDirty"));
275 | brandon.set("firstName", 0);
276 | assert.equal(false, brandon.get("isDirty"));
277 | brandon.set("firstName", "0");
278 | assert.equal(true, brandon.get("isDirty"));
279 | });
280 |
281 | test("isDirty on the individual property is reset after value set back to original value", function(assert){
282 | brandon = Person.create(data);
283 | assert.equal("Brandon", brandon.get("firstName"));
284 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
285 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
286 | brandon.set("firstName", "baz");
287 | assert.equal(true, brandon.get("firstNameIsDirty"));
288 | assert.equal(true, brandon.get("firstNameIsPrimed"));
289 | brandon.set("firstName", "Brandon");
290 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
291 | assert.equal(true, brandon.get("firstNameIsPrimed"));
292 | });
293 |
294 | test("isDirty on the individual property is reset after rollback", function(assert){
295 | brandon = Person.create(data);
296 | assert.equal("Brandon", brandon.get("firstName"));
297 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
298 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
299 | brandon.set("firstName", "baz");
300 | assert.equal(true, brandon.get("firstNameIsDirty"));
301 | assert.equal(true, brandon.get("firstNameIsPrimed"));
302 | brandon.rollback();
303 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
304 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
305 | });
306 |
307 | test("rollback after it has been saved will be a no-op at the property level also", function(assert){
308 | brandon = Person.create(data);
309 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
310 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
311 | brandon.set("firstName", "baz");
312 | assert.equal(true, brandon.get("firstNameIsDirty"));
313 | assert.equal(true, brandon.get("firstNameIsPrimed"));
314 | brandon.save();
315 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
316 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
317 | assert.equal("baz", brandon.get("firstName"));
318 | brandon.rollback();
319 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
320 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
321 | assert.equal("baz", brandon.get("firstName"));
322 | });
323 |
324 | test("a prime of the attr with an empty string will alter isDirty but not isPrimed", function(assert) {
325 | brandon = Person.create();
326 | assert.equal(undefined, brandon.get("firstName"));
327 | assert.equal(false, brandon.get("isDirty"));
328 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
329 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
330 | brandon.set("firstName", "");
331 | assert.equal("", brandon.get("firstName"));
332 | assert.equal(true, brandon.get("isDirty"));
333 | assert.equal(true, brandon.get("firstNameIsDirty"));
334 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
335 | });
336 |
337 | test("a prime of the attr with a non empty string will alter both isDirty and isPrimed", function(assert) {
338 | brandon = Person.create();
339 | assert.equal(undefined, brandon.get("firstName"));
340 | assert.equal(false, brandon.get("isDirty"));
341 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
342 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
343 | brandon.set("firstName", "x");
344 | assert.equal("x", brandon.get("firstName"));
345 | assert.equal(true, brandon.get("isDirty"));
346 | assert.equal(true, brandon.get("firstNameIsDirty"));
347 | assert.equal(true, brandon.get("firstNameIsPrimed"));
348 | });
349 |
350 | test("isDirty is smart enough to know when the attr has been restored", function(assert){
351 | brandon = Person.create(data);
352 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
353 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
354 | brandon.set("firstName", "baz");
355 | assert.equal(true, brandon.get("firstNameIsDirty"));
356 | assert.equal(true, brandon.get("firstNameIsPrimed"));
357 | assert.equal("baz", brandon.get("firstName"));
358 | brandon.set("firstName", "Brandon");
359 | assert.equal("Brandon", brandon.get("firstName"));
360 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
361 | assert.equal(true, brandon.get("firstNameIsPrimed"));
362 | });
363 |
364 | test("rolling back a model with no changes is a no-op", function(assert){
365 | brandon = Person.create(data);
366 | assert.equal("Brandon", brandon.get("firstName"));
367 | assert.equal("Williams", brandon.get("lastName"));
368 | assert.equal(false, brandon.get("isDirty"));
369 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
370 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
371 | assert.equal(undefined, brandon.get("lastNameIsDirty"));
372 | assert.equal(undefined, brandon.get("lastNameIsPrimed"));
373 |
374 | brandon.rollback();
375 | assert.equal("Brandon", brandon.get("firstName"));
376 | assert.equal("Williams", brandon.get("lastName"));
377 | assert.equal(false, brandon.get("isDirty"));
378 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
379 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
380 | assert.equal(undefined, brandon.get("lastNameIsDirty"));
381 | assert.equal(undefined, brandon.get("lastNameIsPrimed"));
382 | });
383 |
384 | test("saving a model with no changes is a no-op", function(assert){
385 | brandon = Person.create(data);
386 | assert.equal("Brandon", brandon.get("firstName"));
387 | assert.equal("Williams", brandon.get("lastName"));
388 | assert.equal(false, brandon.get("isDirty"));
389 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
390 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
391 | assert.equal(undefined, brandon.get("lastNameIsDirty"));
392 | assert.equal(undefined, brandon.get("lastNameIsPrimed"));
393 |
394 | brandon.save();
395 | assert.equal("Brandon", brandon.get("firstName"));
396 | assert.equal("Williams", brandon.get("lastName"));
397 | assert.equal(false, brandon.get("isDirty"));
398 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
399 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
400 | assert.equal(undefined, brandon.get("lastNameIsDirty"));
401 | assert.equal(undefined, brandon.get("lastNameIsPrimed"));
402 | });
403 |
404 | test("rolling back a model after initial state is modified should revert to original value", function(assert){
405 | brandon = Person.create(data);
406 | assert.equal("Brandon", brandon.get("firstName"));
407 | brandon.set("firstName", "");
408 | assert.equal("", brandon.get("firstName"));
409 | brandon.rollback();
410 | assert.equal("Brandon", brandon.get("firstName"));
411 | brandon.set("firstName", undefined);
412 | assert.equal(undefined, brandon.get("firstName"));
413 | brandon.rollback();
414 | assert.equal("Brandon", brandon.get("firstName"));
415 | brandon.set("firstName", null);
416 | assert.equal(null, brandon.get("firstName"));
417 | brandon.rollback();
418 | assert.equal("Brandon", brandon.get("firstName"));
419 | assert.equal("Williams", brandon.get("lastName"));
420 | assert.equal(false, brandon.get("isDirty"));
421 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
422 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
423 | assert.equal(undefined, brandon.get("lastNameIsDirty"));
424 | assert.equal(undefined, brandon.get("lastNameIsPrimed"));
425 | });
426 |
427 | test("rolling back a model after initial state is modified should revert to original value when array", function(assert){
428 | let Beast = Model.extend({things: attr()});
429 | let beast = Beast.create({id: 1, things: [1, 2]});
430 | assert.deepEqual([1, 2], beast.get("things"));
431 | beast.set("things", [1]);
432 | assert.equal(true, beast.get("isDirty"));
433 | assert.deepEqual([1], beast.get("things"));
434 | assert.equal(true, beast.get("thingsIsDirty"));
435 | assert.equal(true, beast.get("thingsIsPrimed"));
436 | beast.rollback();
437 | assert.equal(false, beast.get("isDirty"));
438 | assert.deepEqual([1, 2], beast.get("things"));
439 | assert.equal(undefined, beast.get("thingsIsDirty"));
440 | assert.equal(undefined, beast.get("thingsIsPrimed"));
441 | beast.set("things", undefined);
442 | assert.equal(true, beast.get("isDirty"));
443 | assert.equal(undefined, beast.get("things"));
444 | assert.equal(true, beast.get("thingsIsDirty"));
445 | assert.equal(true, beast.get("thingsIsPrimed"));
446 | beast.rollback();
447 | assert.equal(false, beast.get("isDirty"));
448 | assert.deepEqual([1, 2], beast.get("things"));
449 | assert.equal(undefined, beast.get("thingsIsDirty"));
450 | assert.equal(undefined, beast.get("thingsIsPrimed"));
451 | beast.set("things", null);
452 | assert.equal(true, beast.get("isDirty"));
453 | assert.equal(null, beast.get("things"));
454 | assert.equal(true, beast.get("thingsIsDirty"));
455 | assert.equal(true, beast.get("thingsIsPrimed"));
456 | beast.rollback();
457 | assert.equal(false, beast.get("isDirty"));
458 | assert.deepEqual([1, 2], beast.get("things"));
459 | assert.equal(false, beast.get("isDirty"));
460 | assert.equal(undefined, beast.get("thingsIsDirty"));
461 | assert.equal(undefined, beast.get("thingsIsPrimed"));
462 | });
463 |
464 | test("rolling back and saving a new model with no changes is a no-op", function(assert){
465 | brandon = Person.create();
466 | assert.equal(undefined, brandon.get("firstName"));
467 | assert.equal(undefined, brandon.get("lastName"));
468 | assert.equal(false, brandon.get("isDirty"));
469 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
470 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
471 | assert.equal(undefined, brandon.get("lastNameIsDirty"));
472 | assert.equal(undefined, brandon.get("lastNameIsPrimed"));
473 | brandon.set("firstName", "wat");
474 |
475 | brandon.rollback();
476 | assert.equal(undefined, brandon.get("firstName"));
477 | assert.equal(undefined, brandon.get("lastName"));
478 | assert.equal(false, brandon.get("isDirty"));
479 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
480 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
481 | assert.equal(undefined, brandon.get("lastNameIsDirty"));
482 | assert.equal(undefined, brandon.get("lastNameIsPrimed"));
483 |
484 | brandon.save();
485 | assert.equal(undefined, brandon.get("firstName"));
486 | assert.equal(undefined, brandon.get("lastName"));
487 | assert.equal(false, brandon.get("isDirty"));
488 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
489 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
490 | assert.equal(undefined, brandon.get("lastNameIsDirty"));
491 | assert.equal(undefined, brandon.get("lastNameIsPrimed"));
492 |
493 | brandon.set("firstName", "wat");
494 | brandon.save();
495 | assert.equal("wat", brandon.get("firstName"));
496 | assert.equal(undefined, brandon.get("lastName"));
497 | assert.equal(false, brandon.get("isDirty"));
498 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
499 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
500 | assert.equal(undefined, brandon.get("lastNameIsDirty"));
501 | assert.equal(undefined, brandon.get("lastNameIsPrimed"));
502 | });
503 |
504 | test("saving and rolling back a new model immediately is a no-op", function(assert){
505 | brandon = Person.create();
506 | assert.equal(undefined, brandon.get("firstName"));
507 | assert.equal(undefined, brandon.get("lastName"));
508 | assert.equal(false, brandon.get("isDirty"));
509 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
510 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
511 | assert.equal(undefined, brandon.get("lastNameIsDirty"));
512 | assert.equal(undefined, brandon.get("lastNameIsPrimed"));
513 |
514 | brandon.set("firstName", "Brandon");
515 | brandon.set("lastName", "Williams");
516 | brandon.save();
517 | brandon.rollback();
518 | assert.equal("Brandon", brandon.get("firstName"));
519 | assert.equal("Williams", brandon.get("lastName"));
520 | assert.equal(false, brandon.get("isDirty"));
521 | assert.equal(undefined, brandon.get("firstNameIsDirty"));
522 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
523 | assert.equal(undefined, brandon.get("lastNameIsDirty"));
524 | assert.equal(undefined, brandon.get("lastNameIsPrimed"));
525 | });
526 |
527 | test("isDirty and isPrimed are true if the values are cleared out", function(assert){
528 | brandon = Person.create({id: 1, firstName: "x"});
529 | assert.equal(false, brandon.get("isDirty"));
530 | brandon.set("firstName", "");
531 | assert.equal(true, brandon.get("isDirty"));
532 | assert.equal(true, brandon.get("firstNameIsDirty"));
533 | assert.equal(true, brandon.get("firstNameIsPrimed"));
534 | });
535 |
536 | test("isPrimed is undefined when attr is undefined and later set to empty string", function(assert){
537 | brandon = Person.create({id: 1, firstName: undefined, lastName: "Williams"});
538 | assert.equal(undefined, brandon.get("firstName"));
539 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
540 | brandon.set("firstName", "");
541 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
542 | });
543 |
544 | test("isPrimed is true when attr is empty string and later set to undefined", function(assert){
545 | brandon = Person.create({id: 1, firstName: "", lastName: "Williams"});
546 | assert.equal("", brandon.get("firstName"));
547 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
548 | brandon.set("firstName", undefined);
549 | assert.equal(true, brandon.get("firstNameIsPrimed"));
550 | assert.equal(true, brandon.get("isDirty"));
551 | });
552 |
553 | test("isPrimed is true when attr is undefined and later set to valid string", function(assert){
554 | brandon = Person.create({id: 1, firstName: undefined, lastName: "Williams"});
555 | assert.equal(undefined, brandon.get("firstName"));
556 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
557 | brandon.set("firstName", "");
558 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
559 | brandon.set("firstName", "x");
560 | assert.equal(true, brandon.get("firstNameIsPrimed"));
561 | });
562 |
563 | test("isPrimed is true when attr is undefined then string and again undefined", function(assert){
564 | brandon = Person.create({id: 1, firstName: undefined, lastName: "Williams"});
565 | assert.equal(undefined, brandon.get("firstName"));
566 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
567 | brandon.set("firstName", "");
568 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
569 | brandon.set("firstName", "x");
570 | assert.equal(true, brandon.get("firstNameIsPrimed"));
571 | brandon.set("firstName", undefined);
572 | assert.equal(true, brandon.get("firstNameIsPrimed"));
573 | });
574 |
575 | test("isPrimed is undefined after save and rollback", function(assert){
576 | brandon = Person.create({id: 1, firstName: undefined, lastName: "Williams"});
577 | assert.equal(undefined, brandon.get("firstName"));
578 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
579 | brandon.set("firstName", "");
580 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
581 | brandon.set("firstName", "x");
582 | assert.equal(true, brandon.get("firstNameIsPrimed"));
583 | brandon.save();
584 | assert.equal("x", brandon.get("firstName"));
585 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
586 | brandon.set("firstName", "xe");
587 | assert.equal(true, brandon.get("firstNameIsPrimed"));
588 | brandon.rollback();
589 | assert.equal("x", brandon.get("firstName"));
590 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
591 | });
592 |
593 | test("isPrimed is undefined after save and rollback on new object", function(assert){
594 | brandon = Person.create();
595 | assert.equal(undefined, brandon.get("firstName"));
596 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
597 | brandon.rollback();
598 | assert.equal(undefined, brandon.get("firstName"));
599 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
600 | brandon.save();
601 | assert.equal(undefined, brandon.get("firstName"));
602 | assert.equal(undefined, brandon.get("firstNameIsPrimed"));
603 | });
604 |
605 | test("isPrimed is null after save and rollback (starting with null value)", function(assert){
606 | brandon = Person.create({id: 1, firstName: null, lastName: "Williams"});
607 | assert.equal(null, brandon.get("firstName"));
608 | assert.equal(null, brandon.get("firstNameIsPrimed"));
609 | brandon.set("firstName", "");
610 | assert.equal(null, brandon.get("firstNameIsPrimed"));
611 | brandon.set("firstName", "x");
612 | assert.equal(true, brandon.get("firstNameIsPrimed"));
613 | brandon.save();
614 | assert.equal("x", brandon.get("firstName"));
615 | assert.equal(null, brandon.get("firstNameIsPrimed"));
616 | brandon.set("firstName", "xe");
617 | assert.equal(true, brandon.get("firstNameIsPrimed"));
618 | brandon.rollback();
619 | assert.equal("x", brandon.get("firstName"));
620 | assert.equal(null, brandon.get("firstNameIsPrimed"));
621 | });
622 |
--------------------------------------------------------------------------------
/tests/unit/record-array-test.js:
--------------------------------------------------------------------------------
1 | import EmberObject from '@ember/object';
2 | import { run } from '@ember/runloop';
3 | import { moduleFor, test } from 'ember-qunit';
4 | import FilteredRecordArray from 'ember-cli-simple-store/models/filtered-record-array';
5 |
6 | function createFilter(simpleStore) {
7 | simpleStore.push("foo", { id: 1, name: "toran" });
8 |
9 | return simpleStore.find('foo', (foo) => {
10 | return foo.name === 'toran';
11 | });
12 | }
13 |
14 | moduleFor('service:simple-store', "unit: user model test", {
15 | beforeEach() {
16 | this.register('model:foo', EmberObject.extend({}));
17 | }
18 | });
19 |
20 | test("returns an instance of filtered record array", function(assert) {
21 | assert.expect(1);
22 |
23 | const simpleStore = this.subject();
24 |
25 | run(() => {
26 | const recordArray = createFilter(simpleStore);
27 | assert.ok(recordArray instanceof FilteredRecordArray);
28 | });
29 | });
30 |
31 | test("manually calling unsubscribe removes from filtersMap", function(assert) {
32 | assert.expect(2);
33 |
34 | const simpleStore = this.subject();
35 |
36 | run(() => {
37 | const recordArray = createFilter(simpleStore);
38 | const filters = simpleStore.get('filtersMap');
39 |
40 | assert.equal(filters.foo.length, 1);
41 | simpleStore._unsubscribe(recordArray);
42 | assert.equal(filters.foo.length, 0);
43 | });
44 | });
45 |
46 | test("the record array being destroy triggers an unsubscribe", function(assert) {
47 | assert.expect(3);
48 |
49 | const done = assert.async();
50 | const simpleStore = this.subject();
51 |
52 | run(() => {
53 | const recordArray = createFilter(simpleStore);
54 | const filters = simpleStore.get('filtersMap');
55 |
56 | assert.equal(filters.foo.length, 1);
57 | recordArray.destroy();
58 | assert.equal(recordArray.isDestroying, true);
59 |
60 | run.next(() => {
61 | assert.equal(filters.foo.length, 0);
62 | done();
63 | });
64 | });
65 | });
66 |
--------------------------------------------------------------------------------
/tests/unit/relationship-test.js:
--------------------------------------------------------------------------------
1 | import { run } from '@ember/runloop';
2 | import { getOwner } from '@ember/application';
3 | import { test } from "ember-cli-simple-store/test-support/qunit";
4 | import { moduleFor } from 'ember-qunit';
5 | import registration from "dummy/tests/helpers/registration";
6 |
7 | let store, user, role;
8 |
9 | moduleFor('service:simple-store', "unit: user model test", {
10 | beforeEach() {
11 | const owner = getOwner(this);
12 | store = registration(owner, ["model:user", "model:role"]);
13 | }
14 | });
15 |
16 | test("role property returns associated model or undefined", function(assert) {
17 | user = store.push("user", {id: 1, name: "toran"});
18 | store.push("role", {id: 9, name: "Guest", users: [1]});
19 | role = user.get("role");
20 | assert.equal(role.get("id"), 9);
21 | assert.equal(role.get("name"), "Guest");
22 | // role.set("users", []); in v3 this worked but v4 requires a push
23 | run(() => {
24 | store.push("role", {id: 9, users: []});
25 | });
26 | role = user.get("role");
27 | assert.equal(role, undefined);
28 | });
29 |
30 | test("change_role will append user id to the (new) role users array", function(assert) {
31 | user = store.push("user", {id: 1, name: "toran"});
32 | store.push("role", {id: 8, name: "Admin", users: [9, 8]});
33 | store.push("role", {id: 9, name: "Guest", users: [1]});
34 | role = user.get("role");
35 | assert.equal(role.get("id"), 9);
36 | run(() => {
37 | user.change_role(8);
38 | });
39 | role = user.get("role");
40 | assert.equal(role.get("id"), 8);
41 | assert.deepEqual(role.get("users"), [9, 8, 1]);
42 | });
43 |
44 | test("change_role will remove user id from the (old) role users array", function(assert) {
45 | let guest;
46 | user = store.push("user", {id: 1, name: "toran"});
47 | guest = store.push("role", {id: 9, name: "Guest", users: [9, 1, 8]});
48 | store.push("role", {id: 8, name: "Admin", users: []});
49 | role = user.get("role");
50 | assert.equal(role.get("id"), 9);
51 | run(() => {
52 | user.change_role(8);
53 | });
54 | role = user.get("role");
55 | assert.equal(role.get("id"), 8);
56 | assert.deepEqual(guest.get("users"), [9, 8]);
57 | });
58 |
--------------------------------------------------------------------------------
/tests/unit/service-test.js:
--------------------------------------------------------------------------------
1 | import { inject as service } from '@ember/service';
2 | import Controller from '@ember/controller';
3 | import SimpleStore from 'ember-cli-simple-store/store';
4 | import { moduleFor, test } from 'ember-qunit';
5 |
6 | moduleFor('service:simple-store', 'Unit | Service | simple-store');
7 |
8 | test("it exists", function(assert) {
9 | assert.ok(this.subject(), 'a service exists');
10 | });
11 |
12 | test("it is an instance of ember-cli-simple-store/store", function(assert) {
13 | assert.ok(this.subject() instanceof SimpleStore, 'a service is an instance of SimpleStore');
14 | });
15 |
16 | test("it is injectable", function(assert) {
17 | this.register('controller:injection-subject', Controller.extend({
18 | simpleStore: service()
19 | }));
20 |
21 | let subject = this.container.lookup('controller:injection-subject');
22 | assert.ok(subject.get('simpleStore') instanceof SimpleStore);
23 | });
24 |
--------------------------------------------------------------------------------
/tests/unit/store-test.js:
--------------------------------------------------------------------------------
1 | import EmberObject from '@ember/object';
2 | import { run } from '@ember/runloop';
3 | import { getOwner } from '@ember/application';
4 | import { moduleFor } from "ember-qunit";
5 | import { test } from "ember-cli-simple-store/test-support/qunit";
6 |
7 | let store, Person, Toran, Cat;
8 |
9 | moduleFor("service:simple-store", "store unit tests", {
10 | beforeEach: function() {
11 | Person = EmberObject.extend({
12 | firstName: "",
13 | lastName: "",
14 | cat_id: null,
15 | demo: function() {
16 | let firstName = this.get("firstName");
17 | return firstName + " 777";
18 | }
19 | });
20 | Toran = Person.extend({
21 | fake: function() {
22 | let firstName = this.get("firstName");
23 | return firstName + " 999";
24 | }
25 | });
26 | Cat = EmberObject.extend({
27 | color: ""
28 | });
29 | const owner = getOwner(this);
30 | store = this.subject();
31 | owner.register("model:person", Person);
32 | owner.register("model:toran", Toran);
33 | owner.register("model:cat", Cat);
34 | }
35 | });
36 |
37 | test("records can be pushed into the store", function(assert) {
38 | store.push("person", {
39 | id: "toranb",
40 | firstName: "Toran",
41 | lastName: "Billups"
42 | });
43 |
44 | let toranb = store.find("person", "toranb");
45 | assert.ok(toranb, "The toranb record was found");
46 |
47 | assert.equal(toranb.get("firstName"), "Toran", "the firstName property is correct");
48 | assert.equal(toranb.get("lastName"), "Billups", "the lastName property is correct");
49 | assert.equal(toranb.get("id"), "toranb", "the id property is correct");
50 | });
51 |
52 | test("multiple records can be pushed into the store", function(assert) {
53 | let person1 = {
54 | id: "johndoe",
55 | firstName: "john",
56 | lastName: "doe"
57 | };
58 |
59 | let person2 = {
60 | id: "janedoe",
61 | firstName: "jane",
62 | lastName: "doe"
63 | };
64 |
65 | store.pushArray("person", [person1, person2]);
66 |
67 | let foundPerson1 = store.find("person", "johndoe");
68 | let foundPerson2 = store.find("person", "janedoe");
69 |
70 | assert.equal(foundPerson1.get("id"), person1.id, "person 1 id not found");
71 | assert.equal(foundPerson2.get("id"), person2.id, "person 2 id not found");
72 | });
73 |
74 | test("push returns the created record", function(assert) {
75 | let pushedToranb = store.push("person", {
76 | id: "toranb",
77 | firstName: "Toran",
78 | lastName: "Billups"
79 | });
80 |
81 | let gottenToranb = store.find("person", "toranb");
82 |
83 | assert.strictEqual(pushedToranb, gottenToranb.get("content"), "both records are identical");
84 | });
85 |
86 | test("push array returns the created records", function(assert) {
87 | let person1 = {
88 | id: "johndoe",
89 | firstName: "john",
90 | lastName: "doe"
91 | };
92 |
93 | let person2 = {
94 | id: "janedoe",
95 | firstName: "jane",
96 | lastName: "doe"
97 | };
98 |
99 | let data = [person1, person2];
100 |
101 | let pushedRecords = store.pushArray("person", data);
102 |
103 | assert.equal(pushedRecords.length, data.length);
104 | assert.equal(pushedRecords[0].get("id"), data[0].id);
105 | assert.equal(pushedRecords[1].get("id"), data[1].id);
106 | });
107 |
108 | test("willDestroy sets refs to complex objects to null", function(assert) {
109 | store.push("person", {
110 | id: "gambler",
111 | firstName: "Wyatt",
112 | lastName: "Earp"
113 | });
114 | assert.equal(store.get('array')['person'][0].id, 'gambler', 'gambler in store');
115 | run(function() {
116 | store.destroy();
117 | });
118 | assert.equal(store.get('array'), null, 'store#array set to null');
119 | assert.equal(store.get('identityMap'), null, 'store#identityMap set to null');
120 | assert.equal(store.get('filtersMap'), null, 'store#filtersMap set to null');
121 | assert.equal(store.get('recompute'), null, 'store#recompute set to null');
122 | });
123 |
124 | test("pushing a record into the store twice updates the original record", function(assert) {
125 | store.push("person", {
126 | id: "toranb",
127 | firstName: "Toran",
128 | lastName: "Billups"
129 | });
130 |
131 | let toranb = store.find("person", "toranb");
132 | assert.ok(toranb, "The toranb record was found");
133 |
134 | assert.equal(toranb.get("firstName"), "Toran", "the firstName property is correct");
135 | assert.equal(toranb.get("lastName"), "Billups", "the lastName property is correct");
136 | assert.equal(toranb.get("id"), "toranb", "the id property is correct");
137 |
138 | store.push("person", {
139 | id: "toranb",
140 | firstName: "X",
141 | lastName: "Y"
142 | });
143 |
144 | assert.equal(toranb.get("firstName"), "X", "the firstName property is correct");
145 | assert.equal(toranb.get("lastName"), "Y", "the lastName property is correct");
146 | assert.equal(toranb.get("id"), "toranb", "the id property is is correct");
147 | });
148 |
149 | test("pushing doesn't mangle string ids", function(assert) {
150 | store.push("person", {
151 | id: "toranb",
152 | firstName: "Toran",
153 | lastName: "Billups"
154 | });
155 |
156 | let toranb = store.find("person", "toranb");
157 | assert.strictEqual(toranb.get("id"), "toranb");
158 | });
159 |
160 | test("models with int based ids must be lookedup by int and string value", function(assert) {
161 | store.push("person", {
162 | id: 123,
163 | firstName: "Toran",
164 | lastName: "Billups"
165 | });
166 |
167 | let toranbByNum = store.find("person", 123);
168 | assert.strictEqual(toranbByNum.get("id"), 123);
169 | assert.ok(toranbByNum.get("content") instanceof Person);
170 |
171 | toranbByNum = store.find("person", "123");
172 | assert.strictEqual(toranbByNum.get("id"), 123);
173 | assert.ok(toranbByNum.get("content") instanceof Person);
174 | });
175 |
176 | test("models with str based ids must be lookedup by str value", function(assert) {
177 | store.push("person", {
178 | id: "abc",
179 | firstName: "Toran",
180 | lastName: "Billups"
181 | });
182 |
183 | let toranbByStr = store.find("person", "abc");
184 | assert.strictEqual(toranbByStr.get("id"), "abc");
185 | assert.ok(toranbByStr.get("content") instanceof Person);
186 | });
187 |
188 | test("models with int !0 id in string must be lookedup by int and string value", function(assert) {
189 | store.push("person", {
190 | id: "1234",
191 | firstName: "Guillaume",
192 | lastName: "Gérard"
193 | });
194 |
195 | let guillaumeByNum = store.find("person", "1234");
196 | assert.strictEqual(guillaumeByNum.get("id"), 1234);
197 | assert.ok(guillaumeByNum.get("content") instanceof Person);
198 |
199 | guillaumeByNum = store.find("person", 1234);
200 | assert.strictEqual(guillaumeByNum.get("id"), 1234);
201 | assert.ok(guillaumeByNum.get("content") instanceof Person);
202 | });
203 |
204 | test("pushArray - models with int !0 id in string must be lookedup by int and string value", function(assert) {
205 | store.pushArray("person", [{
206 | id: "1234",
207 | firstName: "Guillaume",
208 | lastName: "Gérard"
209 | }]);
210 |
211 | let guillaumeByNum = store.find("person", "1234");
212 | assert.strictEqual(guillaumeByNum.get("id"), 1234);
213 | assert.ok(guillaumeByNum.get("content") instanceof Person);
214 |
215 | guillaumeByNum = store.find("person", 1234);
216 | assert.strictEqual(guillaumeByNum.get("id"), 1234);
217 | assert.ok(guillaumeByNum.get("content") instanceof Person);
218 | });
219 |
220 | test("models with int 0 id must be lookedup by int and string value", function(assert) {
221 | store.push("person", {
222 | id: 0,
223 | firstName: "Guillaume",
224 | lastName: "Gérard"
225 | });
226 |
227 | let guillaumeByNum = store.find("person", "0");
228 | assert.strictEqual(guillaumeByNum.get("id"), 0);
229 | assert.ok(guillaumeByNum.get("content") instanceof Person);
230 |
231 | guillaumeByNum = store.find("person", 0);
232 | assert.strictEqual(guillaumeByNum.get("id"), 0);
233 | assert.ok(guillaumeByNum.get("content") instanceof Person);
234 | });
235 |
236 | test("models with int 0 id in string must be lookedup by int and string value", function(assert) {
237 | store.push("person", {
238 | id: "0",
239 | firstName: "Guillaume",
240 | lastName: "Gérard"
241 | });
242 |
243 | let guillaumeByNum = store.find("person", "0");
244 | assert.strictEqual(guillaumeByNum.get("id"), 0);
245 | assert.ok(guillaumeByNum.get("content") instanceof Person);
246 |
247 | guillaumeByNum = store.find("person", 0);
248 | assert.strictEqual(guillaumeByNum.get("id"), 0);
249 | assert.ok(guillaumeByNum.get("content") instanceof Person);
250 | });
251 |
252 | test("models with float id in string must be lookedup by int float and string value", function(assert) {
253 | store.push("person", {
254 | id: "3.14159265359",
255 | firstName: "Guillaume",
256 | lastName: "Gérard"
257 | });
258 |
259 | let guillaumeByNum = store.find("person", "3.14159265359");
260 | assert.strictEqual(guillaumeByNum.get("id"), 3.14159265359);
261 | assert.ok(guillaumeByNum.get("content") instanceof Person);
262 |
263 | guillaumeByNum = store.find("person", 3.14159265359);
264 | assert.strictEqual(guillaumeByNum.get("id"), 3.14159265359);
265 | assert.ok(guillaumeByNum.get("content") instanceof Person);
266 | });
267 |
268 | test("find should return array of bound models", function(assert) {
269 | store.push("person", {
270 | id: 1,
271 | firstName: "Toran",
272 | lastName: "Billups"
273 | });
274 |
275 | store.push("person", {
276 | id: 2,
277 | firstName: "Brandon",
278 | lastName: "Williams"
279 | });
280 |
281 | let found_data = store.find("person");
282 | assert.equal(found_data.get("length"), 2);
283 | assert.equal(found_data.objectAt(0).get("firstName"), "Toran");
284 | assert.equal(found_data.objectAt(1).get("firstName"), "Brandon");
285 |
286 | store.push("person", {
287 | id: 3,
288 | firstName: "Scott",
289 | lastName: "Newcomer"
290 | });
291 |
292 | assert.equal(found_data.get("length"), 3);
293 | assert.equal(found_data.objectAt(0).get("firstName"), "Toran");
294 | assert.equal(found_data.objectAt(1).get("firstName"), "Brandon");
295 | assert.equal(found_data.objectAt(2).get("firstName"), "Scott");
296 | });
297 |
298 | test("remove should destroy the item by type", function(assert) {
299 | assert.expect(7);
300 |
301 | let first = store.push("person", {
302 | id: 1,
303 | firstName: "Toran",
304 | lastName: "Billups"
305 | });
306 |
307 | let last = store.push("person", {
308 | id: 2,
309 | firstName: "Brandon",
310 | lastName: "Williams"
311 | });
312 |
313 | assert.equal(store.find("person").get("length"), 2);
314 | store.remove("person", first.get("id"));
315 | assert.equal(store.find("person").get("length"), 1);
316 |
317 | let first_person = store.find("person", first.id);
318 | assert.ok(!first_person.get("content"), "The toran record was still found");
319 | assert.equal(first_person.get("firstName"), undefined);
320 |
321 | let last_person = store.find("person", last.id);
322 | assert.ok(last_person.get("content"), "The brandon record was not found");
323 | assert.equal(last_person.get("firstName"), "Brandon");
324 |
325 | run.next(() => {
326 | try {
327 | first.set("firstName", "X");
328 | } catch (e) {
329 | assert.ok(e.message.indexOf("Assertion Failed: calling set on destroyed object") !== -1);
330 | }
331 | });
332 | });
333 |
334 | test("find with filter should return array of models filtered by value", function(assert) {
335 | store.push("person", {
336 | id: 9,
337 | firstName: "Jarrod",
338 | lastName: "Taylor",
339 | cat_id: 1
340 | });
341 |
342 | store.push("person", {
343 | id: 8,
344 | firstName: "Brandon",
345 | lastName: "Williams",
346 | cat_id: 2
347 | });
348 |
349 | store.push("person", {
350 | id: 7,
351 | firstName: "Toran",
352 | lastName: "Billups",
353 | cat_id: 1
354 | });
355 |
356 | store.push("cat", {
357 | id: 1,
358 | color: "red"
359 | });
360 |
361 | store.push("cat", {
362 | id: 2,
363 | color: "blue"
364 | });
365 |
366 | assert.equal(store.find("person").get("length"), 3);
367 | assert.equal(store.find("person").objectAt(0).get("cat_id"), 1);
368 | assert.equal(store.find("person").objectAt(1).get("cat_id"), 2);
369 | assert.equal(store.find("person").objectAt(2).get("cat_id"), 1);
370 |
371 | assert.equal(store.find("person", {cat_id: 1}).get("length"), 2);
372 | assert.equal(store.find("person", {cat_id: 2}).get("length"), 1);
373 |
374 | store.push("person", {
375 | id: 14,
376 | firstName: "wat",
377 | lastName: "hat",
378 | cat_id: 1
379 | });
380 | assert.equal(store.find("person", {cat_id: 1}).get("length"), 3);
381 | assert.equal(store.find("person", {cat_id: 2}).get("length"), 1);
382 |
383 | store.push("person", {
384 | id: 15,
385 | firstName: "xor",
386 | lastName: "nope",
387 | cat_id: 2
388 | });
389 | assert.equal(store.find("person", {cat_id: 2}).get("length"), 2);
390 | assert.equal(store.find("person", {cat_id: 1}).get("length"), 3);
391 |
392 | assert.equal(store.find("person").get("length"), 5);
393 | });
394 |
395 | test("find with filter does not trump type property of object", function(assert) {
396 | store.push("person", {
397 | id: 9,
398 | firstName: "Jarrod",
399 | lastName: "Taylor",
400 | source: "Jarrod's Mom",
401 | store: "Walmart",
402 | type: "developer"
403 | });
404 |
405 |
406 | let found = store.find("person", 9);
407 | assert.equal(found.get("type"), "developer");
408 | assert.equal(found.get("store"), "Walmart");
409 | assert.equal(found.get("source"), "Jarrod's Mom");
410 | });
411 |
412 | test("find with filter should return array of models that tracks changes without asking for an update", function(assert) {
413 | store.push("person", {
414 | id: 9,
415 | firstName: "Brandon",
416 | lastName: "Williams",
417 | cat_id: 1
418 | });
419 |
420 | store.push("person", {
421 | id: 8,
422 | firstName: "Toran",
423 | lastName: "Billups",
424 | cat_id: 1
425 | });
426 |
427 | store.push("cat", {
428 | id: 1,
429 | color: "red"
430 | });
431 |
432 | let firstBoundProperty = store.find("person", {cat_id: 1});
433 | assert.equal(firstBoundProperty.get("length"), 2);
434 |
435 | run(() => {
436 | store.push("person", {
437 | id: 14,
438 | firstName: "Another",
439 | lastName: "Person",
440 | cat_id: 1
441 | });
442 | });
443 |
444 | assert.equal(firstBoundProperty.get("length"), 3);
445 | });
446 |
447 | test("find with filter works with string based values", function(assert) {
448 | store.push("person", {
449 | id: 9,
450 | firstName: "Jarrod",
451 | lastName: "Taylor",
452 | nickname: "foo"
453 | });
454 |
455 | store.push("person", {
456 | id: 8,
457 | firstName: "Brandon",
458 | lastName: "Williams",
459 | nickname: "bar"
460 | });
461 |
462 | store.push("person", {
463 | id: 7,
464 | firstName: "Toran",
465 | lastName: "Billups",
466 | nickname: "foo"
467 | });
468 |
469 | let foo_data = store.find("person", {nickname: "foo"});
470 | let bar_data = store.find("person", {nickname: "bar"});
471 |
472 | assert.equal(foo_data.get("length"), 2);
473 | assert.equal(bar_data.get("length"), 1);
474 | assert.equal(foo_data.objectAt(0).get("firstName"), "Jarrod");
475 | assert.equal(foo_data.objectAt(1).get("firstName"), "Toran");
476 | assert.equal(bar_data.objectAt(0).get("firstName"), "Brandon");
477 | });
478 |
479 | test("clear will destroy everything for a given type", function(assert) {
480 | assert.expect(16);
481 |
482 | let firstPerson = store.push("person", {
483 | id: 9,
484 | firstName: "Brandon",
485 | lastName: "Williams",
486 | cat_id: 1
487 | });
488 |
489 | let lastPerson = store.push("person", {
490 | id: 8,
491 | firstName: "Toran",
492 | lastName: "Billups",
493 | cat_id: 1
494 | });
495 |
496 | let firstCat = store.push("cat", {
497 | id: 1,
498 | color: "red"
499 | });
500 |
501 | let catBefore = store.find("cat", 1);
502 | assert.equal(catBefore.get("color"), "red");
503 |
504 | let catsBefore = store.find("cat");
505 | assert.equal(catsBefore.get("length"), 1);
506 |
507 | let firstBoundProperty = store.find("person", {cat_id: 1});
508 | assert.equal(firstBoundProperty.get("length"), 2);
509 |
510 | let individualFirstBefore = store.find("person", 9);
511 | assert.equal(individualFirstBefore.get("firstName"), "Brandon");
512 |
513 | let individualLastBefore = store.find("person", 8);
514 | assert.equal(individualLastBefore.get("firstName"), "Toran");
515 |
516 | run(() => {
517 | store.clear("person");
518 | });
519 |
520 | assert.equal(firstBoundProperty.get("length"), 0);
521 |
522 | let all = store.find("person");
523 | assert.equal(all.get("length"), 0);
524 |
525 | let individualFirstAfter = store.find("person", 9);
526 | assert.equal(individualFirstAfter.get("content"), null);
527 | assert.equal(individualFirstAfter.get("firstName"), undefined);
528 |
529 | let individualLastAfter = store.find("person", 8);
530 | assert.equal(individualLastAfter.get("content"), null);
531 | assert.equal(individualLastAfter.get("firstName"), undefined);
532 |
533 | let catAfter = store.find("cat", 1);
534 | assert.equal(catAfter.get("color"), "red");
535 |
536 | let catsAfter = store.find("cat");
537 | assert.equal(catsAfter.get("length"), 1);
538 |
539 | run.next(() => {
540 | try {
541 | firstPerson.set("firstName", "X");
542 | } catch (e) {
543 | assert.ok(e.message.indexOf("Assertion Failed: calling set on destroyed object") !== -1);
544 | }
545 |
546 | try {
547 | lastPerson.set("firstName", "X");
548 | } catch (e) {
549 | assert.ok(e.message.indexOf("Assertion Failed: calling set on destroyed object") !== -1);
550 | }
551 |
552 | firstCat.set("color", "purple");
553 | assert.equal(firstCat.get("color"), "purple");
554 | });
555 | });
556 |
557 | test("clear without type will destroy everything", function(assert) {
558 | assert.expect(10);
559 |
560 | let firstPerson = store.push("person", {
561 | id: 9,
562 | firstName: "Brandon",
563 | lastName: "Williams",
564 | cat_id: 1
565 | });
566 |
567 | let lastPerson = store.push("person", {
568 | id: 8,
569 | firstName: "Toran",
570 | lastName: "Billups",
571 | cat_id: 1
572 | });
573 |
574 | let firstCat = store.push("cat", {
575 | id: 1,
576 | color: "red"
577 | });
578 |
579 | firstPerson.set("firstName", "R");
580 | lastPerson.set("firstName", "M");
581 | firstCat.set("color", "purple");
582 |
583 | assert.equal(firstPerson.get("firstName"), "R");
584 | assert.equal(lastPerson.get("firstName"), "M");
585 | assert.equal(firstCat.get("color"), "purple");
586 |
587 | assert.equal(store.find("person").get("length"), 2);
588 | assert.equal(store.find("cat").get("length"), 1);
589 |
590 | run(() => {
591 | store.clear();
592 | });
593 |
594 | assert.equal(store.find("person").get("length"), 0);
595 | assert.equal(store.find("cat").get("length"), 0);
596 |
597 | run.next(() => {
598 | try {
599 | firstPerson.set("firstName", "X");
600 | } catch (e) {
601 | assert.ok(e.message.indexOf("Assertion Failed: calling set on destroyed object") !== -1);
602 | }
603 |
604 | try {
605 | lastPerson.set("firstName", "X");
606 | } catch (e) {
607 | assert.ok(e.message.indexOf("Assertion Failed: calling set on destroyed object") !== -1);
608 | }
609 |
610 | try {
611 | firstCat.set("color", "rain");
612 | } catch (e) {
613 | assert.ok(e.message.indexOf("Assertion Failed: calling set on destroyed object") !== -1);
614 | }
615 | });
616 | });
617 |
618 | test("invoking clear multiple times will only schedule a recompute once per type", function(assert) {
619 | run(() => {
620 | store.clear("foo");
621 | store.clear("foo");
622 | store.clear("bar");
623 | store.clear("foo");
624 | assert.equal(store.get("recompute.length"), 2);
625 | });
626 | });
627 |
628 | test("find with filter should raise clear exception when invalid options are passed", function(assert) {
629 | try {
630 | store.find("person", {});
631 | assert.ok(false, "filter did not fail with clear exception message");
632 | } catch(e) {
633 | assert.equal(e.message, "Assertion Failed: No key was found in the filter options");
634 | }
635 | });
636 |
637 | test("pushing a model that does not exist should raise clear exception", function(assert) {
638 | try {
639 | store.push("goat", {id: 4, name: "billy"});
640 | assert.ok(false, "model lookup did not fail with clear exception message");
641 | } catch(e) {
642 | assert.equal(e.message, "Assertion Failed: No model was found for type: goat");
643 | }
644 | });
645 |
646 | test("findOne will return the first record", function(assert) {
647 | store.push("toran", {
648 | id: 1,
649 | firstName: "Jake",
650 | lastName: "Good"
651 | });
652 |
653 | store.push("toran", {
654 | id: 2,
655 | firstName: "Brandon",
656 | lastName: "Williams"
657 | });
658 |
659 | assert.equal(store.find("toran").get("length"), 2);
660 |
661 | let toranb = store.findOne("toran");
662 | assert.equal(toranb.get("firstName"), "Jake", "the firstName property is correct");
663 | assert.equal(toranb.get("lastName"), "Good", "the lastName property is correct");
664 | assert.equal(toranb.get("id"), "1", "the id property is correct");
665 | assert.equal(toranb.get("content").fake(), "Jake 999");
666 | assert.equal(toranb.get("content").demo(), "Jake 777");
667 | assert.equal(toranb.fake(), "Jake 999");
668 | assert.equal(toranb.demo(), "Jake 777");
669 | });
670 |
671 | test("findOne should return null when no objects exist in the cache for given type", function(assert) {
672 | assert.equal(store.find("person").get("length"), 0);
673 | let person = store.findOne("person");
674 | assert.equal(person.get("content"), null);
675 | });
676 |
677 | test("find with filter function will return bound array", function(assert) {
678 | store.push("person", {
679 | id: 9,
680 | firstName: "Jarrod",
681 | lastName: "Taylor",
682 | nickname: "foo",
683 | group: 2
684 | });
685 |
686 | store.push("person", {
687 | id: 8,
688 | firstName: "Brandon",
689 | lastName: "Williams",
690 | nickname: "bar",
691 | group: 3
692 | });
693 |
694 | store.push("person", {
695 | id: 7,
696 | firstName: "Toran",
697 | lastName: "Billups",
698 | nickname: "foo",
699 | group: 8
700 | });
701 |
702 | let filter = function(person) {
703 | return person.get("group") > 2 || person.get("nickname") === "bar";
704 | };
705 |
706 | let filtered_data = store.find("person", filter);
707 |
708 | assert.equal(filtered_data.get("length"), 2);
709 | assert.equal(filtered_data.objectAt(0).get("firstName"), "Brandon");
710 | assert.equal(filtered_data.objectAt(1).get("firstName"), "Toran");
711 |
712 | run(() => {
713 | store.push("person", {
714 | id: 6,
715 | firstName: "Taylor",
716 | lastName: "Hobbs",
717 | nickname: "zzz",
718 | group: 8
719 | });
720 | });
721 |
722 | assert.equal(filtered_data.get("length"), 3);
723 | assert.equal(filtered_data.objectAt(0).get("firstName"), "Brandon");
724 | assert.equal(filtered_data.objectAt(1).get("firstName"), "Toran");
725 | assert.equal(filtered_data.objectAt(2).get("firstName"), "Taylor");
726 |
727 | run(() => {
728 | store.push("person", {
729 | id: 5,
730 | firstName: "Matt",
731 | lastName: "Morrison",
732 | nickname: "bar",
733 | group: 0
734 | });
735 | });
736 |
737 | assert.equal(filtered_data.get("length"), 4);
738 | assert.equal(filtered_data.objectAt(0).get("firstName"), "Brandon");
739 | assert.equal(filtered_data.objectAt(1).get("firstName"), "Toran");
740 | assert.equal(filtered_data.objectAt(2).get("firstName"), "Taylor");
741 | assert.equal(filtered_data.objectAt(3).get("firstName"), "Matt");
742 |
743 | let taylor = store.find("person", 6);
744 | assert.equal(taylor.get("firstName"), "Taylor");
745 | // taylor.set("group", 1); in v3 this worked but v4 requires a push
746 | run(() => {
747 | store.push("person", {id: taylor.get("id"), group: 1});
748 | });
749 |
750 | assert.equal(filtered_data.get("length"), 3);
751 | assert.equal(filtered_data.objectAt(0).get("firstName"), "Brandon");
752 | assert.equal(filtered_data.objectAt(1).get("firstName"), "Toran");
753 | assert.equal(filtered_data.objectAt(2).get("firstName"), "Matt");
754 |
755 | let brandon = store.find("person", 8);
756 | assert.equal(brandon.get("firstName"), "Brandon");
757 | // brandon.set("group", 1); in v3 this worked but v4 requires a push
758 | run(() => {
759 | store.push("person", {id: brandon.get("id"), group: 1});
760 | });
761 |
762 | assert.equal(filtered_data.get("length"), 3);
763 | assert.equal(filtered_data.objectAt(0).get("firstName"), "Brandon");
764 | assert.equal(filtered_data.objectAt(1).get("firstName"), "Toran");
765 | assert.equal(filtered_data.objectAt(2).get("firstName"), "Matt");
766 |
767 | // brandon.set("nickname", "x"); in v3 this worked but v4 requires a push
768 | run(() => {
769 | store.push("person", {id: brandon.get("id"), nickname: "x"});
770 | });
771 |
772 | assert.equal(filtered_data.get("length"), 2);
773 | assert.equal(filtered_data.objectAt(0).get("firstName"), "Toran");
774 | assert.equal(filtered_data.objectAt(1).get("firstName"), "Matt");
775 | });
776 |
777 | test("findByIdComputed result will be computed property that updates as records are pushed into the store", function(assert) {
778 | let done = assert.async();
779 | let toranb = store.find("person", 123);
780 | assert.equal(toranb.get("id"), undefined);
781 | assert.equal(toranb.get("firstName"), undefined);
782 | assert.equal(toranb.get("lastName"), undefined);
783 |
784 | setTimeout(function() {
785 | run(() => {
786 | store.push("person", {
787 | id: 123,
788 | firstName: "Toran",
789 | lastName: "Billups"
790 | });
791 | });
792 | setTimeout(function() {
793 | assert.equal(toranb.get("id"), 123);
794 | assert.equal(toranb.get("firstName"), "Toran");
795 | assert.equal(toranb.get("lastName"), "Billups");
796 | done();
797 | }, 0);
798 | }, 0);
799 | });
800 |
801 | test("findByIdComputed also works with string based ids", function(assert) {
802 | let done = assert.async();
803 | let toranb = store.find("person", "abc123");
804 | assert.equal(toranb.get("id"), undefined);
805 | assert.equal(toranb.get("firstName"), undefined);
806 | assert.equal(toranb.get("lastName"), undefined);
807 |
808 | setTimeout(function() {
809 | run(() => {
810 | store.push("person", {
811 | id: "abc123",
812 | firstName: "Toran",
813 | lastName: "Billups"
814 | });
815 | });
816 | setTimeout(function() {
817 | assert.equal(toranb.get("id"), "abc123");
818 | assert.equal(toranb.get("firstName"), "Toran");
819 | assert.equal(toranb.get("lastName"), "Billups");
820 | done();
821 | }, 0);
822 | }, 0);
823 | });
824 |
825 | test("findByIdComputed truly works with guid based ids", function(assert) {
826 | let done = assert.async();
827 | let toranb = store.find("person", "55555555-ca0d-4126-8929-afdsaf789883");
828 | assert.equal(toranb.get("id"), undefined);
829 | assert.equal(toranb.get("firstName"), undefined);
830 | assert.equal(toranb.get("lastName"), undefined);
831 |
832 | setTimeout(function() {
833 | run(() => {
834 | store.push("person", {
835 | id: "55555555-ca0d-4126-8929-afdsaf789883",
836 | firstName: "Toran",
837 | lastName: "Billups"
838 | });
839 | });
840 | setTimeout(function() {
841 | assert.equal(toranb.get("id"), "55555555-ca0d-4126-8929-afdsaf789883");
842 | assert.equal(toranb.get("firstName"), "Toran");
843 | assert.equal(toranb.get("lastName"), "Billups");
844 | done();
845 | }, 0);
846 | }, 0);
847 | });
848 |
849 | test("findByIdComputed will return result with int based id using string", function(assert) {
850 | let done = assert.async();
851 | let toranb = store.find("person", "4");
852 | assert.equal(toranb.get("id"), undefined);
853 | assert.equal(toranb.get("firstName"), undefined);
854 | assert.equal(toranb.get("lastName"), undefined);
855 |
856 | setTimeout(function() {
857 | run(() => {
858 | store.push("person", {
859 | id: 4,
860 | firstName: "Toran",
861 | lastName: "Billups"
862 | });
863 | });
864 | setTimeout(function() {
865 | assert.equal(toranb.get("id"), 4);
866 | assert.equal(toranb.get("firstName"), "Toran");
867 | assert.equal(toranb.get("lastName"), "Billups");
868 | done();
869 | }, 0);
870 | }, 0);
871 | });
872 |
873 | test("findById will proxy each method for the given type when updated", function(assert) {
874 | let done = assert.async();
875 | let toranb = store.find("toran", 6);
876 | assert.equal(toranb.get("id"), undefined);
877 |
878 | setTimeout(function() {
879 | run(() => {
880 | store.push("toran", {
881 | id: 6,
882 | firstName: "Toran",
883 | lastName: "Billups"
884 | });
885 | });
886 | setTimeout(function() {
887 | assert.equal(toranb.get("id"), 6);
888 | assert.equal(toranb.get("firstName"), "Toran");
889 | assert.equal(toranb.get("content").fake(), "Toran 999");
890 | assert.equal(toranb.get("content").demo(), "Toran 777");
891 | assert.equal(toranb.fake(), "Toran 999");
892 | assert.equal(toranb.demo(), "Toran 777");
893 |
894 | done();
895 | }, 0);
896 | }, 0);
897 | });
898 |
899 | test("findById will proxy each method for the given type when already in the store", function(assert) {
900 | store.push("toran", {
901 | id: 5,
902 | firstName: "Toran",
903 | lastName: "Billups"
904 | });
905 | store.push("toran", {
906 | id: 3,
907 | firstName: "Other",
908 | lastName: "Person"
909 | });
910 |
911 | let toranb = store.find("toran", 5);
912 | assert.ok(toranb, "The toranb record was found");
913 |
914 | assert.equal(toranb.get("firstName"), "Toran");
915 | assert.equal(toranb.get("content").fake(), "Toran 999");
916 | assert.equal(toranb.get("content").demo(), "Toran 777");
917 | assert.equal(toranb.fake(), "Toran 999");
918 | assert.equal(toranb.demo(), "Toran 777");
919 |
920 | let other = store.find("toran", 3);
921 | assert.ok(other, "The other record was found");
922 |
923 | assert.equal(other.get("firstName"), "Other");
924 | assert.equal(other.get("content").fake(), "Other 999");
925 | assert.equal(other.get("content").demo(), "Other 777");
926 | assert.equal(other.fake(), "Other 999");
927 | assert.equal(other.demo(), "Other 777");
928 |
929 | toranb = store.find("toran", 5);
930 | assert.ok(toranb, "The toranb record was found");
931 |
932 | assert.equal(toranb.get("firstName"), "Toran");
933 | assert.equal(toranb.get("content").fake(), "Toran 999");
934 | assert.equal(toranb.get("content").demo(), "Toran 777");
935 | assert.equal(toranb.fake(), "Toran 999");
936 | assert.equal(toranb.demo(), "Toran 777");
937 | });
938 |
939 | test("findOne result will be computed property that updates as records are pushed into the store", function(assert) {
940 | let done = assert.async();
941 | let toran = store.findOne("toran");
942 | assert.equal(toran.get("id"), undefined);
943 | assert.equal(toran.get("firstName"), undefined);
944 | assert.equal(toran.get("lastName"), undefined);
945 | setTimeout(function() {
946 | run(() => {
947 | store.push("toran", {
948 | id: 123,
949 | firstName: "Toran",
950 | lastName: "Billups"
951 | });
952 | });
953 |
954 | setTimeout(function() {
955 | assert.equal(toran.get("id"), 123);
956 | assert.equal(toran.get("firstName"), "Toran");
957 | assert.equal(toran.get("lastName"), "Billups");
958 | assert.equal(toran.get("content").fake(), "Toran 999");
959 | assert.equal(toran.get("content").demo(), "Toran 777");
960 | assert.equal(toran.fake(), "Toran 999");
961 | assert.equal(toran.demo(), "Toran 777");
962 |
963 | done();
964 | }, 0);
965 | }, 0);
966 | });
967 |
968 | test("store will not update object with id of undefined", function(assert) {
969 | store.push("person", {});
970 | assert.equal(store.find("person").get("length"), 1);
971 | store.push("person", {id: 1, name: "foo"});
972 | assert.equal(store.find("person").get("length"), 2);
973 | let people = store.find("person");
974 | assert.equal(people.objectAt(0).id, undefined);
975 | assert.equal(people.objectAt(1).id, 1);
976 | });
977 |
978 | test("store will update object with id of undefined when setting properties", function(assert) {
979 | let person = store.push("person", {});
980 | assert.equal(store.find("person").get("length"), 1);
981 | person.setProperties({id: 1, name: "foo"});
982 | assert.equal(store.find("person").get("length"), 1);
983 | let people = store.find("person");
984 | assert.equal(people.objectAt(0).id, 1);
985 | });
986 |
987 | test("find with filter returns array proxy with push function that adds record", function(assert) {
988 | store.push("person", {
989 | id: 9,
990 | firstName: "Jarrod",
991 | lastName: "Taylor",
992 | nickname: "foo",
993 | group: 2
994 | });
995 |
996 | store.push("person", {
997 | id: 8,
998 | firstName: "Toran",
999 | lastName: "Billups",
1000 | nickname: "wat",
1001 | group: 3
1002 | });
1003 |
1004 | let filtered_data = store.find("person", {group: 2});
1005 |
1006 | assert.equal(filtered_data.get("length"), 1);
1007 | assert.equal(filtered_data.objectAt(0).get("firstName"), "Jarrod");
1008 |
1009 | let created;
1010 | run(() => {
1011 | created = filtered_data.push({
1012 | id: 6,
1013 | firstName: "Taylor",
1014 | lastName: "Hobbs",
1015 | nickname: "zzz",
1016 | group: 2
1017 | });
1018 | });
1019 |
1020 | assert.equal(created.get("id"), 6);
1021 | assert.equal(created.get("firstName"), "Taylor");
1022 |
1023 | assert.equal(filtered_data.get("length"), 2);
1024 | assert.equal(filtered_data.objectAt(0).get("firstName"), "Jarrod");
1025 | assert.equal(filtered_data.objectAt(1).get("firstName"), "Taylor");
1026 |
1027 | assert.equal(store.find("person", 6).get("firstName"), "Taylor");
1028 | assert.equal(store.find("person", 9).get("firstName"), "Jarrod");
1029 | });
1030 |
1031 | test("find with filter function returns array proxy with push function that adds record", function(assert) {
1032 | store.push("person", {
1033 | id: 9,
1034 | firstName: "Jarrod",
1035 | lastName: "Taylor",
1036 | nickname: "foo",
1037 | group: 2
1038 | });
1039 |
1040 | store.push("person", {
1041 | id: 8,
1042 | firstName: "Brandon",
1043 | lastName: "Williams",
1044 | nickname: "bar",
1045 | group: 3
1046 | });
1047 |
1048 | store.push("person", {
1049 | id: 7,
1050 | firstName: "Toran",
1051 | lastName: "Billups",
1052 | nickname: "foo",
1053 | group: 8
1054 | });
1055 |
1056 | let filter = function(person) {
1057 | return person.get("group") > 2 || person.get("nickname") === "bar";
1058 | };
1059 |
1060 | let filtered_data = store.find("person", filter);
1061 |
1062 | assert.equal(filtered_data.get("length"), 2);
1063 | assert.equal(filtered_data.objectAt(0).get("firstName"), "Brandon");
1064 | assert.equal(filtered_data.objectAt(1).get("firstName"), "Toran");
1065 |
1066 | run(() => {
1067 | store.push("person", {
1068 | id: 6,
1069 | firstName: "Taylor",
1070 | lastName: "Hobbs",
1071 | nickname: "zzz",
1072 | group: 8
1073 | });
1074 | });
1075 |
1076 | assert.equal(filtered_data.get("length"), 3);
1077 | assert.equal(filtered_data.objectAt(0).get("firstName"), "Brandon");
1078 | assert.equal(filtered_data.objectAt(1).get("firstName"), "Toran");
1079 | assert.equal(filtered_data.objectAt(2).get("firstName"), "Taylor");
1080 |
1081 | let created;
1082 | run(() => {
1083 | created = filtered_data.push({
1084 | id: 5,
1085 | firstName: "Scott",
1086 | lastName: "Newcomer",
1087 | nickname: "bar",
1088 | group: 1
1089 | });
1090 | });
1091 |
1092 | assert.equal(filtered_data.get("length"), 4);
1093 | assert.equal(filtered_data.objectAt(0).get("firstName"), "Brandon");
1094 | assert.equal(filtered_data.objectAt(1).get("firstName"), "Toran");
1095 | assert.equal(filtered_data.objectAt(2).get("firstName"), "Taylor");
1096 | assert.equal(filtered_data.objectAt(3).get("firstName"), "Scott");
1097 |
1098 | assert.equal(created.get("id"), 5);
1099 | assert.equal(created.get("firstName"), "Scott");
1100 |
1101 | assert.equal(store.find("person", 8).get("firstName"), "Brandon");
1102 | assert.equal(store.find("person", 7).get("firstName"), "Toran");
1103 | assert.equal(store.find("person", 6).get("firstName"), "Taylor");
1104 | assert.equal(store.find("person", 5).get("firstName"), "Scott");
1105 | });
1106 |
1107 | test("find returns array proxy with push function that adds record", function(assert) {
1108 | store.push("person", {
1109 | id: 1,
1110 | firstName: "Toran",
1111 | lastName: "Billups"
1112 | });
1113 |
1114 | store.push("person", {
1115 | id: 2,
1116 | firstName: "Brandon",
1117 | lastName: "Williams"
1118 | });
1119 |
1120 | let found_data = store.find("person");
1121 | assert.equal(found_data.get("length"), 2);
1122 | assert.equal(found_data.objectAt(0).get("firstName"), "Toran");
1123 | assert.equal(found_data.objectAt(1).get("firstName"), "Brandon");
1124 |
1125 | let created;
1126 | run(() => {
1127 | created = found_data.push({
1128 | id: 3,
1129 | firstName: "Scott",
1130 | lastName: "Newcomer"
1131 | });
1132 | });
1133 |
1134 | assert.equal(found_data.get("length"), 3);
1135 | assert.equal(found_data.objectAt(0).get("firstName"), "Toran");
1136 | assert.equal(found_data.objectAt(1).get("firstName"), "Brandon");
1137 | assert.equal(found_data.objectAt(2).get("firstName"), "Scott");
1138 |
1139 | assert.equal(created.get("id"), 3);
1140 | assert.equal(created.get("firstName"), "Scott");
1141 |
1142 | assert.equal(store.find("person", 1).get("firstName"), "Toran");
1143 | assert.equal(store.find("person", 2).get("firstName"), "Brandon");
1144 | assert.equal(store.find("person", 3).get("firstName"), "Scott");
1145 | });
1146 |
1147 | test("bound array proxy from find will correctly respect the push of different types", function(assert) {
1148 | store.push("person", {
1149 | id: 1,
1150 | firstName: "Toran",
1151 | lastName: "Billups"
1152 | });
1153 |
1154 | store.push("person", {
1155 | id: 2,
1156 | firstName: "Brandon",
1157 | lastName: "Williams"
1158 | });
1159 |
1160 | store.push("cat", {
1161 | id: 1,
1162 | color: "red"
1163 | });
1164 |
1165 | store.push("cat", {
1166 | id: 2,
1167 | color: "green"
1168 | });
1169 |
1170 | let found_data = store.find("person");
1171 | assert.equal(found_data.get("length"), 2);
1172 | assert.equal(found_data.objectAt(0).get("firstName"), "Toran");
1173 | assert.equal(found_data.objectAt(1).get("firstName"), "Brandon");
1174 |
1175 | run(() => {
1176 | found_data.push({
1177 | id: 3,
1178 | firstName: "Scott",
1179 | lastName: "Newcomer"
1180 | });
1181 | });
1182 |
1183 | assert.equal(found_data.get("length"), 3);
1184 | assert.equal(found_data.objectAt(0).get("firstName"), "Toran");
1185 | assert.equal(found_data.objectAt(1).get("firstName"), "Brandon");
1186 | assert.equal(found_data.objectAt(2).get("firstName"), "Scott");
1187 |
1188 | assert.equal(store.find("person", 1).get("firstName"), "Toran");
1189 | assert.equal(store.find("person", 2).get("firstName"), "Brandon");
1190 | assert.equal(store.find("person", 3).get("firstName"), "Scott");
1191 |
1192 | let found_cats = store.find("cat");
1193 | assert.equal(found_cats.get("length"), 2);
1194 | assert.equal(found_cats.objectAt(0).get("color"), "red");
1195 | assert.equal(found_cats.objectAt(1).get("color"), "green");
1196 |
1197 | run(() => {
1198 | found_cats.push({
1199 | id: 3,
1200 | color: "yellow"
1201 | });
1202 | });
1203 |
1204 | assert.equal(found_cats.get("length"), 3);
1205 | assert.equal(found_cats.objectAt(0).get("color"), "red");
1206 | assert.equal(found_cats.objectAt(1).get("color"), "green");
1207 | assert.equal(found_cats.objectAt(2).get("color"), "yellow");
1208 |
1209 | assert.equal(store.find("cat", 1).get("color"), "red");
1210 | assert.equal(store.find("cat", 2).get("color"), "green");
1211 | assert.equal(store.find("cat", 3).get("color"), "yellow");
1212 |
1213 | run(() => {
1214 | found_data.push({
1215 | id: 4,
1216 | firstName: "Matt",
1217 | lastName: "Morrison"
1218 | });
1219 | });
1220 |
1221 | assert.equal(found_cats.get("length"), 3);
1222 | assert.equal(found_data.get("length"), 4);
1223 | });
1224 |
1225 | test("find returns array proxy that has a remove function that removes the record", function(assert) {
1226 | store.push("person", {
1227 | id: 1,
1228 | firstName: "Toran",
1229 | lastName: "Billups"
1230 | });
1231 |
1232 | store.push("person", {
1233 | id: 2,
1234 | firstName: "Brandon",
1235 | lastName: "Williams"
1236 | });
1237 |
1238 | let found_data = store.find("person");
1239 | assert.equal(found_data.get("length"), 2);
1240 | assert.equal(found_data.objectAt(0).get("firstName"), "Toran");
1241 | assert.equal(found_data.objectAt(1).get("firstName"), "Brandon");
1242 |
1243 | run(() => {
1244 | found_data.remove(1);
1245 | });
1246 |
1247 | assert.equal(found_data.get("length"), 1);
1248 | assert.equal(found_data.objectAt(0).get("firstName"), "Brandon");
1249 | assert.equal(store.find("person", 2).get("firstName"), "Brandon");
1250 |
1251 | run(() => {
1252 | found_data.push({
1253 | id: 1,
1254 | lastName: "new"
1255 | });
1256 | });
1257 |
1258 | assert.equal(store._findById("person", 1).get("firstName"), "");
1259 | assert.equal(store._findById("person", 1).get("lastName"), "new");
1260 | });
1261 |
1262 | test("find with filter returns array proxy that has a remove function that removes the record", function(assert) {
1263 | store.push("person", {
1264 | id: 9,
1265 | firstName: "Jarrod",
1266 | lastName: "Taylor",
1267 | nickname: "foo",
1268 | group: 2
1269 | });
1270 |
1271 | store.push("person", {
1272 | id: 8,
1273 | firstName: "Toran",
1274 | lastName: "Billups",
1275 | nickname: "wat",
1276 | group: 3
1277 | });
1278 |
1279 | store.push("person", {
1280 | id: 7,
1281 | firstName: "Scott",
1282 | lastName: "Newcomer",
1283 | nickname: "barz",
1284 | group: 2
1285 | });
1286 |
1287 | let filtered_data = store.find("person", {group: 2});
1288 |
1289 | assert.equal(filtered_data.get("length"), 2);
1290 | assert.equal(filtered_data.objectAt(0).get("firstName"), "Jarrod");
1291 |
1292 | run(() => {
1293 | filtered_data.remove(9);
1294 | });
1295 |
1296 | assert.equal(filtered_data.get("length"), 1);
1297 | assert.equal(filtered_data.objectAt(0).get("firstName"), "Scott");
1298 | assert.equal(store.find("person", 7).get("firstName"), "Scott");
1299 | assert.equal(store.find("person", 8).get("firstName"), "Toran");
1300 |
1301 | run(() => {
1302 | filtered_data.push({
1303 | id: 9,
1304 | lastName: "new"
1305 | });
1306 | });
1307 |
1308 | assert.equal(store._findById("person", 9).get("firstName"), "");
1309 | assert.equal(store._findById("person", 9).get("lastName"), "new");
1310 | });
1311 |
1312 | test("find with filter function returns array proxy that has a remove function that removes the record", function(assert) {
1313 | store.push("person", {
1314 | id: 9,
1315 | firstName: "Jarrod",
1316 | lastName: "Taylor",
1317 | nickname: "foo",
1318 | group: 2
1319 | });
1320 |
1321 | store.push("person", {
1322 | id: 8,
1323 | firstName: "Brandon",
1324 | lastName: "Williams",
1325 | nickname: "bar",
1326 | group: 3
1327 | });
1328 |
1329 | store.push("person", {
1330 | id: 7,
1331 | firstName: "Toran",
1332 | lastName: "Billups",
1333 | nickname: "foo",
1334 | group: 8
1335 | });
1336 |
1337 | let filter = function(person) {
1338 | return person.get("group") > 2 || person.get("nickname") === "bar";
1339 | };
1340 |
1341 | let filtered_data = store.find("person", filter);
1342 |
1343 | assert.equal(filtered_data.get("length"), 2);
1344 | assert.equal(filtered_data.objectAt(0).get("firstName"), "Brandon");
1345 | assert.equal(filtered_data.objectAt(1).get("firstName"), "Toran");
1346 |
1347 | run(() => {
1348 | filtered_data.remove(8);
1349 | });
1350 |
1351 | assert.equal(filtered_data.get("length"), 1);
1352 | assert.equal(filtered_data.objectAt(0).get("firstName"), "Toran");
1353 |
1354 | run(() => {
1355 | filtered_data.push({
1356 | id: 8,
1357 | lastName: "new"
1358 | });
1359 | });
1360 |
1361 | assert.equal(store._findById("person", 8).get("firstName"), "");
1362 | assert.equal(store._findById("person", 8).get("lastName"), "new");
1363 | });
1364 |
1365 | let Listing;
1366 |
1367 | moduleFor("service:simple-store", "store unit tests -- custom primary key", {
1368 | beforeEach: function() {
1369 | Listing = EmberObject.extend({
1370 | listing_id: null,
1371 | description: null
1372 | });
1373 |
1374 | Listing.reopenClass({
1375 | primaryKey: "listing_id"
1376 | });
1377 | const owner = getOwner(this);
1378 | store = this.subject();
1379 | owner.register("model:listing", Listing);
1380 | }
1381 | });
1382 |
1383 | test("store#push and store#find use the specified primary key", function(assert) {
1384 | store.push("listing", {
1385 | listing_id: 5,
1386 | description: "A lovely vase"
1387 | });
1388 |
1389 | let listing = store.find("listing", 5);
1390 | assert.ok(listing, "The listing record was found");
1391 |
1392 | assert.equal(listing.get("description"), "A lovely vase", "the description property is correct");
1393 | });
1394 |
1395 | test("remove should destory the item by type", function(assert) {
1396 | let first = store.push("listing", {
1397 | listing_id: 1,
1398 | description: "Ugly vase"
1399 | });
1400 |
1401 | let last = store.push("listing", {
1402 | listing_id: 2,
1403 | description: "A 'Sorcier des Glaces' CD"
1404 | });
1405 |
1406 | assert.equal(store.find("listing").get("length"), 2);
1407 | store.remove("listing", first.listing_id);
1408 | assert.equal(store.find("listing").get("length"), 1);
1409 |
1410 | let first_listing = store.find("listing", first.listing_id);
1411 | assert.ok(!first_listing.get("content"), "The ugly vase record was not found");
1412 | assert.equal(first_listing.get("description"), undefined);
1413 |
1414 | let last_listing = store.find("listing", last.listing_id);
1415 | assert.ok(last_listing.get("content"), "The 'Sorcier des Glaces' record was still found");
1416 | assert.equal(last_listing.get("description"), "A 'Sorcier des Glaces' CD");
1417 | });
1418 |
--------------------------------------------------------------------------------
/vendor/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toranb/ember-cli-simple-store/ac6955430e26a7cd833aa3764228f4e3f8f96748/vendor/.gitkeep
--------------------------------------------------------------------------------