Compare commits
213 Commits
Author | SHA1 | Date |
---|---|---|
|
f8c5b257f0 | |
|
cc685989a3 | |
|
b056255ecd | |
|
9917e1d283 | |
|
2167e802a9 | |
|
b26da798a9 | |
|
60a47b4439 | |
|
40e278ab96 | |
|
7c196af109 | |
|
83d9b865d5 | |
|
88771f10fc | |
|
29676f6510 | |
|
f3b849bb47 | |
|
e63bbcf9cd | |
|
9096e0873e | |
|
63f04a28d4 | |
|
1d8ca908f6 | |
|
3df1826730 | |
|
8ebccb65d1 | |
|
6d017c1e34 | |
|
da323964f5 | |
|
2190f2510f | |
|
5a661a064a | |
|
4ebc421c11 | |
|
3e02e36314 | |
|
cbb3f6f98a | |
|
93b89f3a51 | |
|
570da781b8 | |
|
e9baea77e0 | |
|
7d45463a22 | |
|
f7af629e96 | |
|
5cbc3bfae7 | |
|
e7274a39dc | |
|
af1d959613 | |
|
cbc8c8efe0 | |
|
5492e59207 | |
|
26d25d60fd | |
|
e251f05914 | |
|
9bfab2b5a2 | |
|
485ad3ee78 | |
|
c62ba21307 | |
|
553c9448ac | |
|
d87e3bf8fb | |
|
4544401368 | |
|
5b836bdae0 | |
|
71ef3dd095 | |
|
839a2c6c66 | |
|
fae9fd69c0 | |
|
f6c054e3f4 | |
|
70b7b1533d | |
|
de70d746e8 | |
|
f8da9783bc | |
|
a1b9b42d11 | |
|
d7a5429f52 | |
|
adcebab371 | |
|
69ce75c662 | |
|
9923ddb29b | |
|
552dfc8f24 | |
|
c96f471efd | |
|
e038b28e8c | |
|
a1683fca59 | |
|
6acedc3bae | |
|
342eb866be | |
|
959a821be5 | |
|
70a1552df8 | |
|
459fc93012 | |
|
09fbfe9410 | |
|
e3d76f7f19 | |
|
8caf4c8327 | |
|
ff184aec16 | |
|
c3eca4025c | |
|
a9d381605e | |
|
fde4c0bfd6 | |
|
da57136fed | |
|
8208e8ab63 | |
|
7e8198f88b | |
|
35e64d2e0b | |
|
4d965d2de1 | |
|
b7266bd1cb | |
|
76398b7f45 | |
|
e103b50b63 | |
|
24eb3d3953 | |
|
74312c9948 | |
|
94ca3bcd9d | |
|
8edca500c1 | |
|
d84b481483 | |
|
d324696d2a | |
|
71d4adb0b0 | |
|
f663917fe9 | |
|
d385dfa9d6 | |
|
64a9b8d506 | |
|
a9d10ebfbb | |
|
95bc2e93cc | |
|
b15681968b | |
|
12aadd4266 | |
|
44e1d29879 | |
|
fce166245f | |
|
25345d56eb | |
|
9afaecaada | |
|
cf432fceec | |
|
b95d5ca182 | |
|
f4302363d3 | |
|
65c8ec41e0 | |
|
0bd7270f84 | |
|
a1a9bac9ba | |
|
de84a8bc7d | |
|
4f76475ee9 | |
|
ab47ecfbab | |
|
24a9a96a26 | |
|
873cb4eab6 | |
|
2c1a056ade | |
|
5001a98135 | |
|
2fb6a96d77 | |
|
6d4e0513a7 | |
|
f7cfe25b60 | |
|
df4a3643eb | |
|
27efed9c5f | |
|
421597c998 | |
|
9d0d41d660 | |
|
d8d89bea9d | |
|
1750583a15 | |
|
5a20ea1a08 | |
|
9da0e501da | |
|
b4d2d19ac6 | |
|
a8a105c3ee | |
|
1b266bcf00 | |
|
72b3179da1 | |
|
8013b6acd4 | |
|
0dee7fbec7 | |
|
9557558c8f | |
|
7f277b2563 | |
|
837f58f82d | |
|
8a07627c81 | |
|
5a594d4855 | |
|
fc2c429963 | |
|
a96a8f379a | |
|
fa65094583 | |
|
1615caca9d | |
|
6efd00698b | |
|
69cc091ef4 | |
|
f1a70094fa | |
|
4e5ae72eef | |
|
8173a4306c | |
|
ebcb5a0546 | |
|
6736d72b98 | |
|
35f14c38dc | |
|
48e949e996 | |
|
5f8e28a6c0 | |
|
892c228797 | |
|
26718c733a | |
|
bfbdd15f1d | |
|
af8cf19242 | |
|
baef033115 | |
|
be17bedcc5 | |
|
9bf60e0d74 | |
|
534a0e5892 | |
|
dddf0ee09a | |
|
7aa9cb357d | |
|
2e11dbfe35 | |
|
c093648525 | |
|
05ea5467cd | |
|
39907c6421 | |
|
0d5cff5a0a | |
|
a9f69bcbc6 | |
|
a6f499703e | |
|
65d6d6a508 | |
|
ee6c0ad461 | |
|
4c7d862cee | |
|
bec9142100 | |
|
f65b542dab | |
|
289eac7565 | |
|
feca7481e9 | |
|
4000b70e38 | |
|
a5187765f6 | |
|
fd1afdf6e6 | |
|
1eeacd0255 | |
|
0de6dd72a4 | |
|
7d7662bfef | |
|
90f04181a4 | |
|
09ad9e4711 | |
|
7773963b62 | |
|
7eee0afb52 | |
|
fbd8b67766 | |
|
093a69328c | |
|
216a537a23 | |
|
81abac19f3 | |
|
0aa3a2f407 | |
|
000b5b002a | |
|
de9e0e81b2 | |
|
a73521f161 | |
|
da9b77a015 | |
|
96a9759d6d | |
|
0d11186850 | |
|
08faf9f5de | |
|
0008a1dd6d | |
|
1268e0f9ac | |
|
1cbeb10c96 | |
|
27526d90ed | |
|
be9853686d | |
|
79990e31b0 | |
|
3ed05426be | |
|
ca766f1437 | |
|
dbdf915334 | |
|
96588622b8 | |
|
8ca67c3d48 | |
|
5fdd521985 | |
|
2f71622e11 | |
|
3bc2dacb1b | |
|
2423db1571 | |
|
174237e6a6 | |
|
9b1766f1d5 | |
|
e4719638c7 | |
|
95050e3a95 |
|
@ -0,0 +1,2 @@
|
|||
coverage
|
||||
support
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"extends": "loopback",
|
||||
"rules": {
|
||||
"max-len": ["error", 110, 4, {
|
||||
"ignoreComments": true,
|
||||
"ignoreUrls": true,
|
||||
"ignorePattern": "^\\s*var\\s.+=\\s*(require\\s*\\()|(/)"
|
||||
}],
|
||||
// NOTE we should eventually remove this override
|
||||
// and fix all of those 100+ violations
|
||||
"one-var": "off",
|
||||
"no-unused-expressions": "off"
|
||||
}
|
||||
}
|
|
@ -12,3 +12,4 @@ docs/man
|
|||
npm-debug.log
|
||||
.project
|
||||
test/memory.json
|
||||
|
||||
|
|
|
@ -9,3 +9,4 @@ benchmark.js
|
|||
analyse.r
|
||||
docs/html
|
||||
npm-debug.log
|
||||
.travis.yml
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
sudo: false
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.10"
|
||||
- "0.12"
|
||||
- "iojs"
|
||||
- "6"
|
||||
- "8"
|
||||
- "10"
|
||||
|
|
336
CHANGES.md
336
CHANGES.md
|
@ -1,3 +1,333 @@
|
|||
2018-05-18, Version 2.57.0
|
||||
==========================
|
||||
|
||||
* Add support for Node.js 8.x and 10.x, drop 4.x (Miroslav Bajtoš)
|
||||
|
||||
|
||||
2018-01-19, Version 2.56.0
|
||||
==========================
|
||||
|
||||
* fix unauthorized fk change (#1540) (Taranveer Virk)
|
||||
|
||||
* drop support for node 0.10 / 0.12 (#1541) (Taranveer Virk)
|
||||
|
||||
|
||||
2017-09-26, Version 2.55.3
|
||||
==========================
|
||||
|
||||
* fix(model-builder): __data may be null. (#1415) (Samuel Reed)
|
||||
|
||||
* package: use qs@6.5.0 (#1470) (Kevin Delisle)
|
||||
|
||||
|
||||
2017-07-28, Version 2.55.2
|
||||
==========================
|
||||
|
||||
* Fix #1434 2.55.1 Throws when using where query against "JSON Object or ANY" Type (#1444) (Shing)
|
||||
|
||||
* castPropertyValue: throw on malformed types (Kevin Delisle)
|
||||
|
||||
|
||||
2017-07-21, Version 2.55.1
|
||||
==========================
|
||||
|
||||
* Catch errors using cb (loay)
|
||||
|
||||
* Recursively cast props on fromDb for memory conn. (nVitius)
|
||||
|
||||
* Recursively coerce nested properties in dao (nVitius)
|
||||
|
||||
* Fix #1079 - Polymorphic hasMany inverse relation (#1296) (Janny)
|
||||
|
||||
|
||||
2017-07-10, Version 2.55.0
|
||||
==========================
|
||||
|
||||
* Backport - Apply hasManyThrough filter on target model (#1404) (Janny)
|
||||
|
||||
|
||||
2017-06-13, Version 2.54.2
|
||||
==========================
|
||||
|
||||
* Fix assert as array does not guarantee order (Candy)
|
||||
|
||||
* Fixed empty objList in linkOneToMany fn (#1287) (somename85)
|
||||
|
||||
* remove equality value for user-defined id (#1292) (Matteo Padovano)
|
||||
|
||||
* override collection name for arangodb (#1274) (Matteo Padovano)
|
||||
|
||||
* fix missing findOrCreate error callback (Ryan Graham)
|
||||
|
||||
|
||||
2017-03-13, Version 2.54.1
|
||||
==========================
|
||||
|
||||
* fix incorrect engines property in package.json (Ryan Graham)
|
||||
|
||||
* Fix datasource to report connector-loading errors (Miroslav Bajtoš)
|
||||
|
||||
* Add two basic tests for "inq" operator (Miroslav Bajtoš)
|
||||
|
||||
|
||||
2017-01-17, Version 2.54.0
|
||||
==========================
|
||||
|
||||
* Replace deprecated node-uuid with uuid module (Raymond Feng)
|
||||
|
||||
* Coerce array-like objects into arrays (Heath Morrison)
|
||||
|
||||
* Throw error when model relation name is trigger (Brian Schemp)
|
||||
|
||||
* Update package.json for LB3 release (Simon Ho)
|
||||
|
||||
|
||||
2016-12-21, Version 2.53.1
|
||||
==========================
|
||||
|
||||
* Fix HasOne.update to propagate options arg (Miroslav Bajtoš)
|
||||
|
||||
* Update ko translation file (Candy)
|
||||
|
||||
* Back-port fixes for linter errors from master (Miroslav Bajtoš)
|
||||
|
||||
* Update chinese simplified translation file (Candy)
|
||||
|
||||
* Apply style guide to test names (Amir Jafarian)
|
||||
|
||||
* Continue _coerce after logical operators (Heath Morrison)
|
||||
|
||||
* Fix manually (Amir Jafarian)
|
||||
|
||||
* Auto-update by eslint --fix (Amir Jafarian)
|
||||
|
||||
* update eslintrc according to master branch (Amir Jafarian)
|
||||
|
||||
* Update eslint (Amir Jafarian)
|
||||
|
||||
* test/kvao: add connectorCapabilities options (Miroslav Bajtoš)
|
||||
|
||||
* Update validations.js (Rand McKinney)
|
||||
|
||||
* Fix bug when near filter is used (Amir Jafarian)
|
||||
|
||||
|
||||
2016-10-13, Version 2.52.0
|
||||
==========================
|
||||
|
||||
* Support {defaultFn: 'shortid'} (#1110) (Simon Ho)
|
||||
|
||||
* Add ilike and nilike operators (#1136) (Simon Ho)
|
||||
|
||||
* Fix JSdoc (Amir Jafarian)
|
||||
|
||||
* Update ja translation file (Candy)
|
||||
|
||||
* Update translation files - round#2 (Candy)
|
||||
|
||||
* Add 'isNewInstance' for updateAttributes (Amir Jafarian)
|
||||
|
||||
* Add globalization strings (Amir Jafarian)
|
||||
|
||||
* Add docs for KVAO (Simon Ho)
|
||||
|
||||
* Skip test temporarily (Loay)
|
||||
|
||||
|
||||
2016-09-12, Version 2.51.0
|
||||
==========================
|
||||
|
||||
* Add missing "done" arg in test/kvao/ttl.suite (Miroslav Bajtoš)
|
||||
|
||||
* Support nested queries for arrays (pponugo)
|
||||
|
||||
* Remove expired item before executing expire (Simon Ho)
|
||||
|
||||
* Fix failures for connectors (Amir Jafarian)
|
||||
|
||||
* upsertWithWhere feature support in juggler DAO (Sonali Samantaray)
|
||||
|
||||
* Remove ESLint from dependencies (Simon Ho)
|
||||
|
||||
* Refactor TTL test suite (Simon Ho)
|
||||
|
||||
|
||||
2016-08-26, Version 2.50.0
|
||||
==========================
|
||||
|
||||
* test/memory: remove dummy findOrCreate impl (Miroslav Bajtoš)
|
||||
|
||||
* Implement `notify` for find method (Amir Jafarian)
|
||||
|
||||
* kvao: implement key filter (Miroslav Bajtoš)
|
||||
|
||||
* kvao: add iterateKeys() and keys() (Miroslav Bajtoš)
|
||||
|
||||
* Globalize KeyValue Memory connector (Simon Ho)
|
||||
|
||||
* test: Rename KVAO get test suite (Simon Ho)
|
||||
|
||||
|
||||
2016-08-16, Version 2.49.0
|
||||
==========================
|
||||
|
||||
* Fix error message for missing global.Promise (Miroslav Bajtoš)
|
||||
|
||||
* Add TTL for KeyValue related features (Simon Ho)
|
||||
|
||||
* test/kvao: setup global.Promise on Node v0.10 (Miroslav Bajtoš)
|
||||
|
||||
* kv-memory: fix crash in regular cleanup (Miroslav Bajtoš)
|
||||
|
||||
* Backport globalization (Amir Jafarian)
|
||||
|
||||
|
||||
2016-08-09, Version 2.48.0
|
||||
==========================
|
||||
|
||||
* Return error if connector does not implement (Amir Jafarian)
|
||||
|
||||
* kvao: return 404 when expiring unknown key (Miroslav Bajtoš)
|
||||
|
||||
* Update doc for `validatesFormatOf` (Amir Jafarian)
|
||||
|
||||
* Implement KeyValue API and memory connector (Miroslav Bajtoš)
|
||||
|
||||
* Fix test case typo (Amir Jafarian)
|
||||
|
||||
* Remove unused variables in model.js (Amir Jafarian)
|
||||
|
||||
* Add test for updateOrCreate (Amir Jafarian)
|
||||
|
||||
* Declare `definition` (Amir Jafarian)
|
||||
|
||||
* Add test to catch invalid date property (Supasate Choochaisri)
|
||||
|
||||
|
||||
2016-07-14, Version 2.47.0
|
||||
==========================
|
||||
|
||||
* Ensure stable order of items in DAO.find() (Miroslav Bajtoš)
|
||||
|
||||
* give options to validators #984 (RobinBiondi)
|
||||
|
||||
* Update datasource.js (Amir Jafarian)
|
||||
|
||||
* Give warning if PK is changed in hooks (Amir Jafarian)
|
||||
|
||||
* Persist changes on parent for embedsOne (Dimitris Halatsis)
|
||||
|
||||
|
||||
2016-06-03, Version 2.46.1
|
||||
==========================
|
||||
|
||||
* fix (Miroslav Bajtoš)
|
||||
|
||||
* Retun err for UPSERT if the connector returns err (Amir Jafarian)
|
||||
|
||||
* Fix error message (Amir Jafarian)
|
||||
|
||||
* Add test's description (Amir Jafarian)
|
||||
|
||||
* ModelBuilder: add new setting strictEmbeddedModels (Dimitris Halatsis)
|
||||
|
||||
* Fix incompatibility between different connectors PR#938 (Amir Jafarian)
|
||||
|
||||
* travis: add v4, v6, drop io.js (Miroslav Bajtoš)
|
||||
|
||||
* Backport ESLint from master (Simon Ho)
|
||||
|
||||
* Set ESLint as devdep (Simon Ho)
|
||||
|
||||
* Use mocha instead of Makefile for testing (Simon Ho)
|
||||
|
||||
* Implement operation hooks for EmbedsMany methods (Miroslav Bajtoš)
|
||||
|
||||
* Implement operation hooks for EmbedsOne methods (Miroslav Bajtoš)
|
||||
|
||||
* eslint config 2.0 + remove extra empty lines (Miroslav Bajtoš)
|
||||
|
||||
* Fix eslint errors in memory connector (Miroslav Bajtoš)
|
||||
|
||||
* Run `eslint --fix` with config from master (Miroslav Bajtoš)
|
||||
|
||||
* Test coverages for hashed password (Amir Jafarian)
|
||||
|
||||
* Fix `forceId` check for `replaceByIds` PR#896 (Amir Jafarian)
|
||||
|
||||
* test: extract hook-monitor helper (Miroslav Bajtoš)
|
||||
|
||||
* test: extract uid-generator helper (Miroslav Bajtoš)
|
||||
|
||||
* test: extract context-test-helpers (Miroslav Bajtoš)
|
||||
|
||||
* Define `patch` aliases (Amir Jafarian)
|
||||
|
||||
|
||||
2016-04-07, Version 2.46.0
|
||||
==========================
|
||||
|
||||
* Insert copyright headers (Miroslav Bajtoš)
|
||||
|
||||
* Relicense as MIT only (Miroslav Bajtoš)
|
||||
|
||||
* Fix Mongo compatibility issue (Amir Jafarian)
|
||||
|
||||
* Add automigrate to setup tables for replace test cases (Amir Jafarian)
|
||||
|
||||
* Remove next tag (2.x) (Amir Jafarian)
|
||||
|
||||
* Allow test folder to be published (Amir Jafarian)
|
||||
|
||||
* Fix tests for mysql (Amir Jafarian)
|
||||
|
||||
* Add forgotten unit test (Miroslav Bajtoš)
|
||||
|
||||
* Improve error message on connector init error (Miroslav Bajtoš)
|
||||
|
||||
* Update describe-operation-hooks (Miroslav Bajtoš)
|
||||
|
||||
* Fix missing connector error msg for db2, cloudant for 2.x (Candy)
|
||||
|
||||
* Implementtaion of replace (Amir Jafarian)
|
||||
|
||||
|
||||
2016-02-22, Version 2.45.2
|
||||
==========================
|
||||
|
||||
* Fix missing connector error msg for db2, cloudant for 2.x (Candy)
|
||||
|
||||
|
||||
2016-02-15, Version 2.45.1
|
||||
==========================
|
||||
|
||||
* Fix conversion for `updateAttributes` (Amir Jafarian)
|
||||
|
||||
|
||||
2016-02-02, Version 2.45.0
|
||||
==========================
|
||||
|
||||
* Refactor `updateAttributes` (Amir Jafarian)
|
||||
|
||||
* Enhance "persisted" hook in DAO.updateAttributes (Miroslav Bajtoš)
|
||||
|
||||
* Add unit test to verify fix for #754 (Tom Kirkpatrick)
|
||||
|
||||
* Implement `findOrCreate` for memory connector (Amir Jafarian)
|
||||
|
||||
* Fix a bug when validation is off for findOrCreate (Amir Jafarian)
|
||||
|
||||
* Fix broken code fencings in the docs (Farid Nouri Neshat)
|
||||
|
||||
* Revert "Correct syntax for should and more" (Simon Ho)
|
||||
|
||||
* Fix test for shouldjs 8.0.2 upgrade (Simon Ho)
|
||||
|
||||
* Upgrade shouldjs to 8.0.2 (Simon Ho)
|
||||
|
||||
* Correct syntax for should and more (Amir Jafarian)
|
||||
|
||||
|
||||
2015-12-13, Version 2.44.0
|
||||
==========================
|
||||
|
||||
|
@ -1455,8 +1785,6 @@
|
|||
2014-06-24, Version 2.0.0-beta2
|
||||
===============================
|
||||
|
||||
* 2.0.0-beta2 (Miroslav Bajtoš)
|
||||
|
||||
* validations: support non-V8 browsers (Miroslav Bajtoš)
|
||||
|
||||
* Work around for Date default (Raymond Feng)
|
||||
|
@ -2074,12 +2402,12 @@
|
|||
* Update LDL doc for the strict mode (Raymond Feng)
|
||||
|
||||
|
||||
2013-09-12, Version strongloopsuite-1.0.0-4
|
||||
2013-09-12, Version strongloopsuite-1.0.0-5
|
||||
===========================================
|
||||
|
||||
|
||||
|
||||
2013-09-12, Version strongloopsuite-1.0.0-5
|
||||
2013-09-12, Version strongloopsuite-1.0.0-4
|
||||
===========================================
|
||||
|
||||
* Allow connector to report failure during initialization (Raymond Feng)
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
Copyright (c) IBM Corp. 2011,2016. All Rights Reserved.
|
||||
Node module: loopback-datasource-juggler
|
||||
This project is licensed under the MIT License, full text below.
|
||||
|
||||
--------
|
||||
|
||||
MIT license
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
|
@ -1,9 +0,0 @@
|
|||
Copyright (c) 2013-2015 StrongLoop, Inc.
|
||||
|
||||
loopback-datasource-juggler uses a dual license model.
|
||||
|
||||
You may use this library under the terms of the [MIT License][],
|
||||
or under the terms of the [StrongLoop Subscription Agreement][].
|
||||
|
||||
[MIT License]: http://opensource.org/licenses/MIT
|
||||
[StrongLoop Subscription Agreement]: http://strongloop.com/license
|
43
Makefile
43
Makefile
|
@ -1,43 +0,0 @@
|
|||
TESTER = ./node_modules/.bin/mocha
|
||||
OPTS = --growl
|
||||
TESTS = test/*.test.js
|
||||
|
||||
default: help
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(CURDIR)/node_modules
|
||||
|
||||
.PHONY: help
|
||||
help:
|
||||
@echo 'Usage: make [target]'
|
||||
@echo 'Targets:'
|
||||
@echo ' clean Delete `node_modules`'
|
||||
@echo ' help Print help (this message)'
|
||||
@echo ' refresh Delete `node_modules` and run `npm install`'
|
||||
@echo ' test Run tests in silent mode'
|
||||
@echo ' test-verbose Run tests in verbose mode'
|
||||
@echo ' testing Run tests continuously'
|
||||
|
||||
.PHONY: refresh
|
||||
refresh: clean
|
||||
npm install
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
NO_DEPRECATION=loopback-datasource-juggler $(TESTER) $(OPTS) $(TESTS)
|
||||
|
||||
.PHONY: test-verbose
|
||||
test-verbose:
|
||||
$(TESTER) $(OPTS) --reporter spec $(TESTS)
|
||||
|
||||
.PHONY: testing
|
||||
testing:
|
||||
$(TESTER) $(OPTS) --watch $(TESTS)
|
||||
|
||||
# Deprecated targets
|
||||
|
||||
.PHONY: about-testing
|
||||
about-testing:
|
||||
@echo 'DEPRECATED: Use `make help` instead'
|
||||
make help
|
|
@ -18,5 +18,3 @@ Also install the appropriated connector, for example for mongodb:
|
|||
npm install loopback-connector-mongodb
|
||||
|
||||
See [StrongLoop Documentation](http://docs.strongloop.com/) for more information.
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var DataSource = require('../../loopback-datasource-juggler').DataSource;
|
||||
var ModelBuilder = require('../../loopback-datasource-juggler').ModelBuilder;
|
||||
var introspectType = require('../lib/introspection')(ModelBuilder);
|
||||
|
@ -12,29 +18,29 @@ var application = {
|
|||
name: 'MyApp1',
|
||||
description: 'My first app',
|
||||
pushSettings: [
|
||||
{ "platform": "apns",
|
||||
"apns": {
|
||||
"pushOptions": {
|
||||
"gateway": "gateway.sandbox.push.apple.com",
|
||||
"cert": "credentials/apns_cert_dev.pem",
|
||||
"key": "credentials/apns_key_dev.pem"
|
||||
{'platform': 'apns',
|
||||
'apns': {
|
||||
'pushOptions': {
|
||||
'gateway': 'gateway.sandbox.push.apple.com',
|
||||
'cert': 'credentials/apns_cert_dev.pem',
|
||||
'key': 'credentials/apns_key_dev.pem',
|
||||
},
|
||||
|
||||
"feedbackOptions": {
|
||||
"gateway": "feedback.sandbox.push.apple.com",
|
||||
"cert": "credentials/apns_cert_dev.pem",
|
||||
"key": "credentials/apns_key_dev.pem",
|
||||
"batchFeedback": true,
|
||||
"interval": 300
|
||||
}
|
||||
}}
|
||||
]}
|
||||
'feedbackOptions': {
|
||||
'gateway': 'feedback.sandbox.push.apple.com',
|
||||
'cert': 'credentials/apns_cert_dev.pem',
|
||||
'key': 'credentials/apns_key_dev.pem',
|
||||
'batchFeedback': true,
|
||||
'interval': 300,
|
||||
},
|
||||
}},
|
||||
]};
|
||||
|
||||
console.log(new Application(application).toObject());
|
||||
|
||||
Application.create(application, function (err, app1) {
|
||||
Application.create(application, function(err, app1) {
|
||||
console.log('Created: ', app1.toObject());
|
||||
Application.findById(app1.id, function (err, app2) {
|
||||
Application.findById(app1.id, function(err, app2) {
|
||||
console.log('Found: ', app2.toObject());
|
||||
});
|
||||
});
|
||||
|
@ -50,14 +56,14 @@ var user = {
|
|||
city: 'San Jose',
|
||||
state: 'CA',
|
||||
zipcode: '95131',
|
||||
country: 'US'
|
||||
country: 'US',
|
||||
},
|
||||
friends: ['John', 'Mary'],
|
||||
emails: [
|
||||
{label: 'work', id: 'x@sample.com'},
|
||||
{label: 'home', id: 'x@home.com'}
|
||||
{label: 'home', id: 'x@home.com'},
|
||||
],
|
||||
tags: []
|
||||
tags: [],
|
||||
};
|
||||
|
||||
// Introspect the JSON document to generate a schema
|
||||
|
@ -71,11 +77,9 @@ var obj = new User(user);
|
|||
|
||||
console.log(obj.toObject());
|
||||
|
||||
User.create(user, function (err, u1) {
|
||||
User.create(user, function(err, u1) {
|
||||
console.log('Created: ', u1.toObject());
|
||||
User.findById(u1.id, function (err, u2) {
|
||||
User.findById(u1.id, function(err, u2) {
|
||||
console.log('Found: ', u2.toObject());
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -1,14 +1,20 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var ModelBuilder = require('../../loopback-datasource-juggler').ModelBuilder;
|
||||
var modelBuilder = new ModelBuilder();
|
||||
// define models
|
||||
var Post = modelBuilder.define('Post', {
|
||||
title: { type: String, length: 255 },
|
||||
content: { type: ModelBuilder.Text },
|
||||
date: { type: Date, default: function () {
|
||||
title: {type: String, length: 255},
|
||||
content: {type: ModelBuilder.Text},
|
||||
date: {type: Date, default: function() {
|
||||
return new Date();
|
||||
} },
|
||||
timestamp: { type: Number, default: Date.now },
|
||||
published: { type: Boolean, default: false, index: true }
|
||||
}},
|
||||
timestamp: {type: Number, default: Date.now},
|
||||
published: {type: Boolean, default: false, index: true},
|
||||
});
|
||||
|
||||
// simpler way to describe model
|
||||
|
@ -17,13 +23,13 @@ var User = modelBuilder.define('User', {
|
|||
bio: ModelBuilder.Text,
|
||||
approved: Boolean,
|
||||
joinedAt: Date,
|
||||
age: Number
|
||||
age: Number,
|
||||
});
|
||||
|
||||
var Group = modelBuilder.define('Group', {group: String});
|
||||
|
||||
// define any custom method
|
||||
User.prototype.getNameAndAge = function () {
|
||||
User.prototype.getNameAndAge = function() {
|
||||
return this.name + ', ' + this.age;
|
||||
};
|
||||
|
||||
|
@ -36,7 +42,3 @@ console.log(modelBuilder.definitions);
|
|||
User.mixin(Group);
|
||||
var user = new User({name: 'Ray', group: 'Admin'});
|
||||
console.log(user);
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,16 +1,22 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var DataSource = require('../../loopback-datasource-juggler').DataSource;
|
||||
var ModelBuilder = require('../../loopback-datasource-juggler').ModelBuilder;
|
||||
var ds = new DataSource('memory');
|
||||
|
||||
// define models
|
||||
var Post = ds.define('Post', {
|
||||
title: { type: String, length: 255 },
|
||||
content: { type: DataSource.Text },
|
||||
date: { type: Date, default: function () {
|
||||
title: {type: String, length: 255},
|
||||
content: {type: DataSource.Text},
|
||||
date: {type: Date, default: function() {
|
||||
return new Date;
|
||||
} },
|
||||
timestamp: { type: Number, default: Date.now },
|
||||
published: { type: Boolean, default: false, index: true }
|
||||
}},
|
||||
timestamp: {type: Number, default: Date.now},
|
||||
published: {type: Boolean, default: false, index: true},
|
||||
});
|
||||
|
||||
// simplier way to describe model
|
||||
|
@ -19,13 +25,13 @@ var User = ds.define('User', {
|
|||
bio: DataSource.Text,
|
||||
approved: Boolean,
|
||||
joinedAt: Date,
|
||||
age: Number
|
||||
age: Number,
|
||||
});
|
||||
|
||||
var Group = ds.define('Group', {name: String});
|
||||
|
||||
// define any custom method
|
||||
User.prototype.getNameAndAge = function () {
|
||||
User.prototype.getNameAndAge = function() {
|
||||
return this.name + ', ' + this.age;
|
||||
};
|
||||
|
||||
|
@ -52,19 +58,19 @@ Post.belongsTo(User, {as: 'author', foreignKey: 'userId'});
|
|||
User.hasAndBelongsToMany('groups');
|
||||
|
||||
var user2 = new User({name: 'Smith', age: 14});
|
||||
user2.save(function (err) {
|
||||
user2.save(function(err) {
|
||||
console.log(user2);
|
||||
var post = user2.posts.build({title: 'Hello world'});
|
||||
post.save(function (err, data) {
|
||||
post.save(function(err, data) {
|
||||
console.log(err ? err : data);
|
||||
});
|
||||
});
|
||||
|
||||
Post.findOne({where: {published: false}, order: 'date DESC'}, function (err, data) {
|
||||
Post.findOne({where: {published: false}, order: 'date DESC'}, function(err, data) {
|
||||
console.log(data);
|
||||
});
|
||||
|
||||
User.create({name: 'Jeff', age: 12}, function (err, data) {
|
||||
User.create({name: 'Jeff', age: 12}, function(err, data) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return;
|
||||
|
@ -74,12 +80,12 @@ User.create({name: 'Jeff', age: 12}, function (err, data) {
|
|||
console.log(post);
|
||||
});
|
||||
|
||||
User.create({name: 'Ray'}, function (err, data) {
|
||||
User.create({name: 'Ray'}, function(err, data) {
|
||||
console.log(data);
|
||||
});
|
||||
|
||||
User.scope('minors', {where: {age: {lte: 16}}, include: 'posts'});
|
||||
User.minors(function (err, kids) {
|
||||
User.minors(function(err, kids) {
|
||||
console.log('Kids: ', kids);
|
||||
});
|
||||
|
||||
|
@ -87,10 +93,10 @@ var Article = ds.define('Article', {title: String});
|
|||
var Tag = ds.define('Tag', {name: String});
|
||||
Article.hasAndBelongsToMany('tags');
|
||||
|
||||
Article.create(function (e, article) {
|
||||
article.tags.create({name: 'popular'}, function (err, data) {
|
||||
Article.findOne(function (e, article) {
|
||||
article.tags(function (e, tags) {
|
||||
Article.create(function(e, article) {
|
||||
article.tags.create({name: 'popular'}, function(err, data) {
|
||||
Article.findOne(function(e, article) {
|
||||
article.tags(function(e, tags) {
|
||||
console.log(tags);
|
||||
});
|
||||
});
|
||||
|
@ -100,8 +106,8 @@ Article.create(function (e, article) {
|
|||
// should be able to attach a data source to an existing model
|
||||
var modelBuilder = new ModelBuilder();
|
||||
|
||||
Color = modelBuilder.define('Color', {
|
||||
name: String
|
||||
var Color = modelBuilder.define('Color', {
|
||||
name: String,
|
||||
});
|
||||
|
||||
// attach
|
||||
|
@ -111,7 +117,7 @@ Color.create({name: 'red'});
|
|||
Color.create({name: 'green'});
|
||||
Color.create({name: 'blue'});
|
||||
|
||||
Color.all(function (err, colors) {
|
||||
Color.all(function(err, colors) {
|
||||
console.log(colors);
|
||||
});
|
||||
|
||||
|
|
|
@ -1,32 +1,36 @@
|
|||
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var jdb = require('../index');
|
||||
|
||||
var User, Post, Passport, City, Street, Building;
|
||||
var nbSchemaRequests = 0;
|
||||
|
||||
setup(function () {
|
||||
|
||||
Passport.find({include: 'owner'}, function (err, passports) {
|
||||
setup(function() {
|
||||
Passport.find({include: 'owner'}, function(err, passports) {
|
||||
console.log('passports.owner', passports);
|
||||
});
|
||||
|
||||
User.find({include: 'posts'}, function (err, users) {
|
||||
User.find({include: 'posts'}, function(err, users) {
|
||||
console.log('users.posts', users);
|
||||
});
|
||||
|
||||
Passport.find({include: {owner: 'posts'}}, function (err, passports) {
|
||||
Passport.find({include: {owner: 'posts'}}, function(err, passports) {
|
||||
console.log('passports.owner.posts', passports);
|
||||
});
|
||||
|
||||
Passport.find({
|
||||
include: {owner: {posts: 'author'}}
|
||||
}, function (err, passports) {
|
||||
include: {owner: {posts: 'author'}},
|
||||
}, function(err, passports) {
|
||||
console.log('passports.owner.posts.author', passports);
|
||||
});
|
||||
|
||||
User.find({include: ['posts', 'passports']}, function (err, users) {
|
||||
User.find({include: ['posts', 'passports']}, function(err, users) {
|
||||
console.log('users.passports && users.posts', users);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function setup(done) {
|
||||
|
@ -36,13 +40,13 @@ function setup(done) {
|
|||
Building = db.define('Building');
|
||||
User = db.define('User', {
|
||||
name: String,
|
||||
age: Number
|
||||
age: Number,
|
||||
});
|
||||
Passport = db.define('Passport', {
|
||||
number: String
|
||||
number: String,
|
||||
});
|
||||
Post = db.define('Post', {
|
||||
title: String
|
||||
title: String,
|
||||
});
|
||||
|
||||
Passport.belongsTo('owner', {model: User});
|
||||
|
@ -50,7 +54,7 @@ function setup(done) {
|
|||
User.hasMany('posts', {foreignKey: 'userId'});
|
||||
Post.belongsTo('author', {model: User, foreignKey: 'userId'});
|
||||
|
||||
db.automigrate(function () {
|
||||
db.automigrate(function() {
|
||||
var createdUsers = [];
|
||||
var createdPassports = [];
|
||||
var createdPosts = [];
|
||||
|
@ -63,9 +67,9 @@ function setup(done) {
|
|||
{name: 'User B', age: 22},
|
||||
{name: 'User C', age: 23},
|
||||
{name: 'User D', age: 24},
|
||||
{name: 'User E', age: 25}
|
||||
{name: 'User E', age: 25},
|
||||
],
|
||||
function (items) {
|
||||
function(items) {
|
||||
createdUsers = items;
|
||||
createPassports();
|
||||
}
|
||||
|
@ -78,9 +82,9 @@ function setup(done) {
|
|||
[
|
||||
{number: '1', ownerId: createdUsers[0].id},
|
||||
{number: '2', ownerId: createdUsers[1].id},
|
||||
{number: '3'}
|
||||
{number: '3'},
|
||||
],
|
||||
function (items) {
|
||||
function(items) {
|
||||
createdPassports = items;
|
||||
createPosts();
|
||||
}
|
||||
|
@ -95,21 +99,20 @@ function setup(done) {
|
|||
{title: 'Post B', userId: createdUsers[0].id},
|
||||
{title: 'Post C', userId: createdUsers[0].id},
|
||||
{title: 'Post D', userId: createdUsers[1].id},
|
||||
{title: 'Post E'}
|
||||
{title: 'Post E'},
|
||||
],
|
||||
function (items) {
|
||||
function(items) {
|
||||
createdPosts = items;
|
||||
done();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function clearAndCreate(model, data, callback) {
|
||||
var createdItems = [];
|
||||
model.destroyAll(function () {
|
||||
model.destroyAll(function() {
|
||||
nextItem(null, null);
|
||||
});
|
||||
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var path = require('path'),
|
||||
fs = require('fs'),
|
||||
DataSource = require('../lib/datasource').DataSource;
|
||||
|
@ -17,7 +23,6 @@ function loadSchemasSync(schemaFile, dataSource) {
|
|||
var schemas = JSON.parse(fs.readFileSync(schemaFile));
|
||||
|
||||
return dataSource.buildModels(schemas);
|
||||
|
||||
}
|
||||
|
||||
var models = loadSchemasSync(path.join(__dirname, 'jdb-schemas.json'));
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var ModelBuilder = require('../../loopback-datasource-juggler').ModelBuilder;
|
||||
var modelBuilder = new ModelBuilder();
|
||||
|
||||
|
@ -13,20 +19,27 @@ var User = modelBuilder.define('User', {
|
|||
city: String,
|
||||
state: String,
|
||||
zipCode: String,
|
||||
country: String
|
||||
country: String,
|
||||
},
|
||||
emails: [
|
||||
{
|
||||
label: String,
|
||||
email: String
|
||||
}
|
||||
email: String,
|
||||
},
|
||||
],
|
||||
friends: [String]
|
||||
friends: [String],
|
||||
});
|
||||
|
||||
var user = new User({name: 'Joe', age: 20, address: {street: '123 Main St', 'city': 'San Jose', state: 'CA'},
|
||||
var user = new User({
|
||||
name: 'Joe',
|
||||
age: 20,
|
||||
address: {
|
||||
street: '123 Main St',
|
||||
city: 'San Jose',
|
||||
state: 'CA',
|
||||
},
|
||||
emails: [
|
||||
{label: 'work', email: 'xyz@sample.com'}
|
||||
{label: 'work', email: 'xyz@sample.com'},
|
||||
],
|
||||
friends: ['John', 'Mary']});
|
||||
console.log(user);
|
||||
|
|
|
@ -1,34 +1,39 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var DataSource = require('../index').DataSource;
|
||||
var ds = new DataSource('memory');
|
||||
|
||||
var Order = ds.createModel('Order', {
|
||||
items: [String],
|
||||
orderDate: Date,
|
||||
qty: Number
|
||||
qty: Number,
|
||||
});
|
||||
|
||||
var Customer = ds.createModel('Customer', {
|
||||
name: String
|
||||
name: String,
|
||||
});
|
||||
|
||||
Order.belongsTo(Customer);
|
||||
|
||||
var order1, order2, order3;
|
||||
|
||||
Customer.create({name: 'John'}, function (err, customer) {
|
||||
Order.create({customerId: customer.id, orderDate: new Date(), items: ['Book']}, function (err, order) {
|
||||
Customer.create({name: 'John'}, function(err, customer) {
|
||||
Order.create({customerId: customer.id, orderDate: new Date(), items: ['Book']}, function(err, order) {
|
||||
order1 = order;
|
||||
order.customer(console.log);
|
||||
order.customer(true, console.log);
|
||||
|
||||
Customer.create({name: 'Mary'}, function (err, customer2) {
|
||||
Customer.create({name: 'Mary'}, function(err, customer2) {
|
||||
order.customer(customer2);
|
||||
order.customer(console.log);
|
||||
});
|
||||
});
|
||||
|
||||
Order.create({orderDate: new Date(), items: ['Phone']}, function (err, order) {
|
||||
|
||||
Order.create({orderDate: new Date(), items: ['Phone']}, function(err, order) {
|
||||
order.customer.create({name: 'Smith'}, function(err, customer2) {
|
||||
console.log(order, customer2);
|
||||
order.save(function(err, order) {
|
||||
|
@ -43,13 +48,13 @@ Customer.create({name: 'John'}, function (err, customer) {
|
|||
|
||||
Customer.hasMany(Order, {as: 'orders', foreignKey: 'customerId'});
|
||||
|
||||
Customer.create({name: 'Ray'}, function (err, customer) {
|
||||
Order.create({customerId: customer.id, qty: 3, orderDate: new Date()}, function (err, order) {
|
||||
Customer.create({name: 'Ray'}, function(err, customer) {
|
||||
Order.create({customerId: customer.id, qty: 3, orderDate: new Date()}, function(err, order) {
|
||||
order3 = order;
|
||||
customer.orders(console.log);
|
||||
customer.orders.create({orderDate: new Date(), qty: 4}, function (err, order) {
|
||||
customer.orders.create({orderDate: new Date(), qty: 4}, function(err, order) {
|
||||
console.log(order);
|
||||
Customer.include([customer], 'orders', function (err, results) {
|
||||
Customer.include([customer], 'orders', function(err, results) {
|
||||
console.log('Results: ', results);
|
||||
});
|
||||
customer.orders({where: {qty: 4}}, function(err, results) {
|
||||
|
@ -62,17 +67,17 @@ Customer.create({name: 'Ray'}, function (err, customer) {
|
|||
});
|
||||
|
||||
var Physician = ds.createModel('Physician', {
|
||||
name: String
|
||||
name: String,
|
||||
});
|
||||
|
||||
var Patient = ds.createModel('Patient', {
|
||||
name: String
|
||||
name: String,
|
||||
});
|
||||
|
||||
var Appointment = ds.createModel('Appointment', {
|
||||
physicianId: Number,
|
||||
patientId: Number,
|
||||
appointmentDate: Date
|
||||
appointmentDate: Date,
|
||||
});
|
||||
|
||||
Appointment.belongsTo(Patient);
|
||||
|
@ -81,49 +86,64 @@ Appointment.belongsTo(Physician);
|
|||
Physician.hasMany(Patient, {through: Appointment});
|
||||
Patient.hasMany(Physician, {through: Appointment});
|
||||
|
||||
Physician.create({name: 'Dr John'}, function (err, physician1) {
|
||||
Physician.create({name: 'Dr Smith'}, function (err, physician2) {
|
||||
Patient.create({name: 'Mary'}, function (err, patient1) {
|
||||
Patient.create({name: 'Ben'}, function (err, patient2) {
|
||||
Appointment.create({appointmentDate: new Date(), physicianId: physician1.id, patientId: patient1.id},
|
||||
function (err, appt1) {
|
||||
Appointment.create({appointmentDate: new Date(), physicianId: physician1.id, patientId: patient2.id},
|
||||
function (err, appt2) {
|
||||
physician1.patients(console.log);
|
||||
physician1.patients({where: {name: 'Mary'}}, console.log);
|
||||
patient1.physicians(console.log);
|
||||
Physician.create({name: 'Dr John'}, function(err, physician1) {
|
||||
Physician.create({name: 'Dr Smith'}, function(err, physician2) {
|
||||
Patient.create({name: 'Mary'}, function(err, patient1) {
|
||||
Patient.create({name: 'Ben'}, function(err, patient2) {
|
||||
Appointment.create({
|
||||
appointmentDate: new Date(),
|
||||
physicianId: physician1.id,
|
||||
patientId: patient1.id,
|
||||
}, function(err, appt1) {
|
||||
Appointment.create({
|
||||
appointmentDate: new Date(),
|
||||
physicianId: physician1.id,
|
||||
patientId: patient2.id,
|
||||
}, function(err, appt2) {
|
||||
physician1.patients(console.log);
|
||||
physician1.patients({where: {name: 'Mary'}}, console.log);
|
||||
patient1.physicians(console.log);
|
||||
|
||||
// Build an appointment?
|
||||
var patient3 = patient1.physicians.build({name: 'Dr X'});
|
||||
console.log('Physician 3: ', patient3, patient3.constructor.modelName);
|
||||
// Build an appointment?
|
||||
var patient3 = patient1.physicians.build({name: 'Dr X'});
|
||||
console.log(
|
||||
'Physician 3: ',
|
||||
patient3,
|
||||
patient3.constructor.modelName
|
||||
);
|
||||
|
||||
// Create a physician?
|
||||
patient1.physicians.create({name: 'Dr X'}, function(err, patient4) {
|
||||
console.log('Physician 4: ', patient4, patient4.constructor.modelName);
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
// Create a physician?
|
||||
patient1.physicians.create(
|
||||
{name: 'Dr X'},
|
||||
function(err, patient4) {
|
||||
console.log(
|
||||
'Physician 4: ',
|
||||
patient4,
|
||||
patient4.constructor.modelName
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
var Assembly = ds.createModel('Assembly', {
|
||||
name: String
|
||||
name: String,
|
||||
});
|
||||
|
||||
var Part = ds.createModel('Part', {
|
||||
partNumber: String
|
||||
partNumber: String,
|
||||
});
|
||||
|
||||
Assembly.hasAndBelongsToMany(Part);
|
||||
Part.hasAndBelongsToMany(Assembly);
|
||||
|
||||
Assembly.create({name: 'car'}, function (err, assembly) {
|
||||
Part.create({partNumber: 'engine'}, function (err, part) {
|
||||
assembly.parts.add(part, function (err) {
|
||||
Assembly.create({name: 'car'}, function(err, assembly) {
|
||||
Part.create({partNumber: 'engine'}, function(err, part) {
|
||||
assembly.parts.add(part, function(err) {
|
||||
assembly.parts(function(err, parts) {
|
||||
console.log('Parts: ', parts);
|
||||
});
|
||||
|
@ -141,7 +161,6 @@ Assembly.create({name: 'car'}, function (err, assembly) {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
|
15
index.js
15
index.js
|
@ -1,3 +1,12 @@
|
|||
// Copyright IBM Corp. 2011,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var SG = require('strong-globalize');
|
||||
SG.SetRootDir(__dirname);
|
||||
|
||||
exports.ModelBuilder = exports.LDL = require('./lib/model-builder.js').ModelBuilder;
|
||||
exports.DataSource = exports.Schema = require('./lib/datasource.js').DataSource;
|
||||
exports.ModelBaseClass = require('./lib/model.js');
|
||||
|
@ -5,12 +14,14 @@ exports.GeoPoint = require('./lib/geo.js').GeoPoint;
|
|||
exports.ValidationError = require('./lib/validations.js').ValidationError;
|
||||
|
||||
Object.defineProperty(exports, 'version', {
|
||||
get: function() {return require('./package.json').version;}
|
||||
get: function() { return require('./package.json').version; },
|
||||
});
|
||||
|
||||
var commonTest = './test/common_test';
|
||||
Object.defineProperty(exports, 'test', {
|
||||
get: function() {return require(commonTest);}
|
||||
get: function() { return require(commonTest); },
|
||||
});
|
||||
|
||||
exports.Transaction = require('loopback-connector').Transaction;
|
||||
|
||||
exports.KeyValueAccessObject = require('./lib/kvao');
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
{
|
||||
"0bd753a8944ad0af85a939bb25273887": "Unbekannter Schlüssel {0} darf nicht ablaufen",
|
||||
"bec226891a505828bfc76c5cfd73b336": "TTL für unbekannten Schlüssel {0} kann nicht abgerufen werden",
|
||||
"4c78325cedbb826db3a05bf5df0e8546": "Sie müssen beim Ersetzen eine {{id}} angeben!",
|
||||
"a0cf0e09c26df14283223e84e6a10f00": "Attribute konnten nicht aktualisiert werden. {{Object}} mit {{id}} {0} ist nicht vorhanden!",
|
||||
"e54d944c2a2c85a23caa86027ae307cf": "Modelle, die nicht an diese Datenquelle angehängt sind, können nicht migriert werden: {0}",
|
||||
"e6161ae8459c79d810e2aa9d21282a39": "Sie müssen beim Aktualisieren von Attributen eine {{id}} angeben!",
|
||||
"fca4d12faff1035d9d0438d73432571b": "Doppelter Eintrag für {0}.{1}",
|
||||
"09483e03b91c8bd58732a74b3ef1ec13": "Ungültiges Datum: {0}",
|
||||
"0b16d3ffc42f91b4b9a4b3b50c41c838": "Die Reihenfolge {0} ist nicht gültig",
|
||||
"0e88a84c6bc2638fbcc5d3ea95181f99": "Unbekannte Eigenschaft: {0}",
|
||||
"21095484501dbff31af6556fa6039182": "Der {{offset/skip}}-Parameter {0} ist nicht gültig",
|
||||
"416dfbb7b823f51c9f3800be81060b41": "Keine Instanz mit {{id}} {0} für {1} gefunden",
|
||||
"4e31b1edd10dadb724d83387de0b5062": "Der {{limit}}-Parameter {0} ist nicht gültig",
|
||||
"5ec8efeb715a2c34b440f2d76e2cf87d": " {0}",
|
||||
"62a2d80c405b7fec5f547c448ab1b6ff": "Die {{order}} {0} hat eine ungültige Richtung",
|
||||
"63f503acabdc4c7588aab741b8466862": "Die Eigenschaft {0} weist die ungültige Klausel {1} auf",
|
||||
"67c2bf43b5281ab929617423ea8a6f3e": "Der Konnektor {0} unterstützt die Operation {{replaceById}} nicht. Hierbei handelt es sich nicht um einen Fehler in LoopBack. Wenden Sie sich an die Ersteller des Konnektors, vorzugsweise über GitHub-Probleme.",
|
||||
"6c3234937d69763fc7f6bcafccc59bbc": "{{Model::deleteById}} erfordert das Argument {{id}}",
|
||||
"6eb6fd4fbd73394000bc25f5776fd20c": "{{Model::exists}} erfordert das Argument {{id}}",
|
||||
"7bbbdece4eea90e42aa5c0bce295e503": "{{Model::findById}} erfordert das Argument {{id}}",
|
||||
"9da58ab4555ac50f4999883de6470d7d": "Der Operator {0} weist ungültige Klauseln {1} auf",
|
||||
"a829dee089c912e68c18920ba015400c": "WARNUNG: Eigenschaft {{id}} darf für Modell {2} in Operationshook {{'loaded'}} nicht von {0} in {1} geändert werden",
|
||||
"a984a076c59e451948b2bcf7a393d860": "WARNUNG: Eigenschaft {{id}} darf für Modell {2} in Operationshook {{'before save'}} nicht von {0} in {1} geändert werden",
|
||||
"baf2c8b0c5a574b8a894e9b6304fece1": "Bei der where-Klausel {0} handelt es sich nicht um ein {{object}}",
|
||||
"db03083e9a768388fdbee865249ac67a": "Validierungsfehler in {{updateOrCreate()}} werden ignoriert:",
|
||||
"e4434de4bb8f5a3cd1d416e4d80d7e0b": "Unbekannte \"{0}\"-{{id}} \"{1}\".",
|
||||
"e54f118a75e15e132f16b985274eb46d": "Beim Abfragefilter {0} handelt es sich nicht um ein {{object}}",
|
||||
"f6e8c96c93b9c7687d6c172b3695e898": "{{id}}-Eigenschaft ({0}) kann nicht von {1} in {2} aktualisiert werden",
|
||||
"0be2d39d225b1d8b2a0f92ad5c65c9ac": "Kein Modell für {{polymorphic}} {0} angegeben: {1}",
|
||||
"2f4af31c144bbfab1bbf479866acd820": "\nWARNUNG: {{LoopBack}}-Konnektor \"{0}\" ist als keines der folgenden Module installiert:\n\n {1}\n\nFühren Sie zur Behebung Folgendes aus:\n\n {{npm install {2} --save}}\n",
|
||||
"6111399276924ffa3bc9a410cdfcb2e5": "Kein {{id}}-Name {0}",
|
||||
"75518263527c423b8a12f908a2730b0f": "{{className}} ist erforderlich",
|
||||
"791ab3031a73ede03f7d6299a85e8289": "Zeitlimitüberschreitung bei Verbindungsherstellung nach {0} ms",
|
||||
"7b277018e43d41bc445731092b91547d": "Nicht verbunden",
|
||||
"a2487abefef4259c2131d96cdb8543b1": "Verbindungsfehler: {0}\nNach der nächsten Anforderung findet ein Neuversuch statt.",
|
||||
"b15b20280211ad258d92947f05b6e4a5": "Der Konnektor wurde nicht initialisiert.",
|
||||
"e0e9504e137a3c3339144b51ed76fef2": "Konnektor ist nicht ordnungsgemäß definiert: Er sollte ein {{connector}}-Member von dataSource erstellen",
|
||||
"ec42dca074f1818c447f7ad16e2d01af": "{0} wird vom zugeordneten Konnektor nicht angegeben",
|
||||
"ba0fd8106eb54de4d003a844206431fd": "Modellhook \"{0}\" ist veraltet, verwenden Sie stattdessen Operationshooks. {{http://docs.strongloop.com/display/LB/Operation+hooks}}",
|
||||
"280f4550f90e133118955ec6f6f72830": "Diskriminatortyp {0} angegeben, aber es ist kein Modell mit diesem Namen vorhanden",
|
||||
"38dbf42c29a4645238cc3d632e88ebc9": "{{Relation.modelTo}} ist für Beziehung {0} nicht definiert und ist keine {{polymorphic}}",
|
||||
"eb56c2b0c30cf006e2df00a549ec9c2c": "Beziehung \"{0}\" ist nicht definiert für {1} modell",
|
||||
"938401ea4ce48159efa9be1d4a5e8bab": "Elemente müssen ein Array sein: {0}",
|
||||
"f41bd91dc0f000a79c0bf842f1b7fdf9": "konnte Liste nicht aus JSON-Zeichenfolge erstellen: {0}",
|
||||
"514985b2327f061ffb1c932f6b909979": "Modell {0} ist nicht definiert.",
|
||||
"cc09e361de7b0f3dc1687515c5713885": "Eigenschaftsnamen, die einen Punkt enthalten, werden nicht unterstützt. Modell: {0}, Eigenschaft: {1}",
|
||||
"da02dd6c53d4148320eeb31718a7aebe": "Ungültiger Typ für Eigenschaft {0}",
|
||||
"ddf0aa14803f1c84f4a97f3803f7471c": "Klassenname erforderlich",
|
||||
"1853f9414bc61ed196952f5c81e41802": "Eigenschaftsnamen, die einen Punkt enthalten, werden nicht unterstützt. Modell: {0}, dynamische Eigenschaft: {1}",
|
||||
"bdb11cc1c780c9ccac33c316cfdc9d82": "Typ nicht definiert für Eigenschaft {0}.{1}",
|
||||
"cd930369e86cdd222f7bd117c6f9fa94": "Unbekannter Standardwertprovider {0}",
|
||||
"0c0b867aca0973ba26e887d3337cc4ec": "{{Polymorphic}}-Modell nicht gefunden: '{0}' nicht festgelegt",
|
||||
"2f062cbecdf24245731bddc77714c814": "\"{0}\"-Beziehung für {1} konnte nicht gefunden werden",
|
||||
"3cde8cc9bca22c67278b202ab0720106": "Keine Instanz mit ID {0} für {1} gefunden",
|
||||
"6502a117987610380b9068ef98b1b0ee": "Kein Datensatz gefunden in {0} für ({1}.{2} ,{3}.{4})",
|
||||
"6fcc2ff0db7a4f490f5e0ce9e24691f3": "{{HasOne}}-Beziehung kann nicht mehr als eine Instanz von {0} erstellen",
|
||||
"7e9530c0399289be0ee601a604be71ff": "{{BelongsTo}}-Beziehung {0} ist leer",
|
||||
"7faa840eb6ce11250a141deb42a6c489": "Unbekannter {{scope}} für Beziehung: {0}",
|
||||
"89afd3a9249f5a8d3edda07d84ca049d": "{{Polymorphic}}-Modell nicht gefunden: '{0}'",
|
||||
"a004f310d315e592843776fab964eaeb": "{{Polymorphic}}-Beziehungen erfordern ein through-Modell",
|
||||
"a25e41a39c60c4702e55d0c3936576a1": "Schlüssel stimmen nicht überein: {0}.{1}: {2}, {3}.{4}: {5}",
|
||||
"a327355560d495454fba2c1aad6bdf09": "Unbekannte Bereichsmethode: {0}",
|
||||
"e08ab0e1ab55f26c357061447b635905": "Keine Beziehung gefunden in {0} für ({1}.{2} ,{3}.{4})",
|
||||
"e55937649d8d7a11706b8cec22d02eae": "{{HasOne}}-Beziehung {0} ist leer",
|
||||
"2c4904377a87fdab502118719cc0d266": "{{Transaction}} wird nicht unterstützt",
|
||||
"ecb7aa804bf54c682999d20d6436104c": "Die {{transaction}} ist nicht aktiv: {0}",
|
||||
"89bf6d92731fe7bd2146ce8d0bec205c": "Ungültiges Argument, muss eine Zeichenfolge, ein {{regex}}-Literalwert oder ein {{RegExp}}-Objekt sein",
|
||||
"8c5ab01638c1ac1d58168c6346a8481a": "Ungültige {{regex}}-Flags: {0}",
|
||||
"a6c18a7f4390cd3d59a2a7a047ae2aab": "Führen Sie den Befehl \"{{npm install loopback-datasource-juggler}} {0}\" aus ",
|
||||
"b138294f132edfe1eb2a8211150c7238": "Unerwartetes 'nicht definiert' in Abfrage",
|
||||
"8a39126103a157f501affa070367a1b0": "Die Instanz {0} ist nicht gültig. Details: {1}."
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
{
|
||||
"0bd753a8944ad0af85a939bb25273887": "Cannot expire unknown key {0}",
|
||||
"bec226891a505828bfc76c5cfd73b336": "Cannot get TTL for unknown key {0}",
|
||||
"4c78325cedbb826db3a05bf5df0e8546": "You must provide an {{id}} when replacing!",
|
||||
"a0cf0e09c26df14283223e84e6a10f00": "Could not update attributes. {{Object}} with {{id}} {0} does not exist!",
|
||||
"e54d944c2a2c85a23caa86027ae307cf": "Cannot migrate models not attached to this datasource: {0}",
|
||||
"e6161ae8459c79d810e2aa9d21282a39": "You must provide an {{id}} when updating attributes!",
|
||||
"fca4d12faff1035d9d0438d73432571b": "Duplicate entry for {0}.{1}",
|
||||
"09483e03b91c8bd58732a74b3ef1ec13": "Invalid date: {0}",
|
||||
"0b16d3ffc42f91b4b9a4b3b50c41c838": "The order {0} is not valid",
|
||||
"0e88a84c6bc2638fbcc5d3ea95181f99": "Unknown property: {0}",
|
||||
"21095484501dbff31af6556fa6039182": "The {{offset/skip}} parameter {0} is not valid",
|
||||
"416dfbb7b823f51c9f3800be81060b41": "No instance with {{id}} {0} found for {1}",
|
||||
"4e31b1edd10dadb724d83387de0b5062": "The {{limit}} parameter {0} is not valid",
|
||||
"5ec8efeb715a2c34b440f2d76e2cf87d": " {0}",
|
||||
"62a2d80c405b7fec5f547c448ab1b6ff": "The {{order}} {0} has invalid direction",
|
||||
"63f503acabdc4c7588aab741b8466862": "The {0} property has invalid clause {1}",
|
||||
"67c2bf43b5281ab929617423ea8a6f3e": "The connector {0} does not support {{replaceById}} operation. This is not a bug in LoopBack. Please contact the authors of the connector, preferably via GitHub issues.",
|
||||
"6c3234937d69763fc7f6bcafccc59bbc": "{{Model::deleteById}} requires the {{id}} argument",
|
||||
"6eb6fd4fbd73394000bc25f5776fd20c": "{{Model::exists}} requires the {{id}} argument",
|
||||
"7bbbdece4eea90e42aa5c0bce295e503": "{{Model::findById}} requires the {{id}} argument",
|
||||
"9da58ab4555ac50f4999883de6470d7d": "The {0} operator has invalid clauses {1}",
|
||||
"a829dee089c912e68c18920ba015400c": "WARNING: {{id}} property cannot be changed from {0} to {1} for model:{2} in {{'loaded'}} operation hook",
|
||||
"a984a076c59e451948b2bcf7a393d860": "WARNING: {{id}} property cannot be changed from {0} to {1} for model:{2} in {{'before save'}} operation hook",
|
||||
"baf2c8b0c5a574b8a894e9b6304fece1": "The where clause {0} is not an {{object}}",
|
||||
"db03083e9a768388fdbee865249ac67a": "Ignoring validation errors in {{updateOrCreate()}}:",
|
||||
"e4434de4bb8f5a3cd1d416e4d80d7e0b": "Unknown \"{0}\" {{id}} \"{1}\".",
|
||||
"e54f118a75e15e132f16b985274eb46d": "The query filter {0} is not an {{object}}",
|
||||
"f6e8c96c93b9c7687d6c172b3695e898": "{{id}} property ({0}) cannot be updated from {1} to {2}",
|
||||
"0be2d39d225b1d8b2a0f92ad5c65c9ac": "No model specified for {{polymorphic}} {0}: {1}",
|
||||
"2f4af31c144bbfab1bbf479866acd820": "\nWARNING: {{LoopBack}} connector \"{0}\" is not installed as any of the following modules:\n\n {1}\n\nTo fix, run:\n\n {{npm install {2} --save}}\n",
|
||||
"6111399276924ffa3bc9a410cdfcb2e5": "No {{id}} name {0}",
|
||||
"75518263527c423b8a12f908a2730b0f": "{{className}} is required",
|
||||
"791ab3031a73ede03f7d6299a85e8289": "Timeout in connecting after {0} ms",
|
||||
"7b277018e43d41bc445731092b91547d": "Not connected",
|
||||
"a2487abefef4259c2131d96cdb8543b1": "Connection fails: {0}\nIt will be retried for the next request.",
|
||||
"b15b20280211ad258d92947f05b6e4a5": "The connector has not been initialized.",
|
||||
"e0e9504e137a3c3339144b51ed76fef2": "Connector is not defined correctly: it should create `{{connector}}` member of dataSource",
|
||||
"ec42dca074f1818c447f7ad16e2d01af": "{0} is not provided by the attached connector",
|
||||
"ba0fd8106eb54de4d003a844206431fd": "Model hook \"{0}\" is deprecated, use Operation hooks instead. {{http://docs.strongloop.com/display/LB/Operation+hooks}}",
|
||||
"280f4550f90e133118955ec6f6f72830": "Discriminator type {0} specified but no model exists with such name",
|
||||
"38dbf42c29a4645238cc3d632e88ebc9": "{{Relation.modelTo}} is not defined for relation {0} and is no {{polymorphic}}",
|
||||
"eb56c2b0c30cf006e2df00a549ec9c2c": "Relation \"{0}\" is not defined for {1} model",
|
||||
"938401ea4ce48159efa9be1d4a5e8bab": "Items must be an array: {0}",
|
||||
"f41bd91dc0f000a79c0bf842f1b7fdf9": "could not create List from JSON string: {0}",
|
||||
"514985b2327f061ffb1c932f6b909979": "Model {0} is not defined.",
|
||||
"cc09e361de7b0f3dc1687515c5713885": "Property names containing a dot are not supported. Model: {0}, property: {1}",
|
||||
"da02dd6c53d4148320eeb31718a7aebe": "Invalid type for property {0}",
|
||||
"ddf0aa14803f1c84f4a97f3803f7471c": "Class name required",
|
||||
"1853f9414bc61ed196952f5c81e41802": "Property names containing a dot are not supported. Model: {0}, dynamic property: {1}",
|
||||
"bdb11cc1c780c9ccac33c316cfdc9d82": "Type not defined for property {0}.{1}",
|
||||
"cd930369e86cdd222f7bd117c6f9fa94": "Unknown default value provider {0}",
|
||||
"0c0b867aca0973ba26e887d3337cc4ec": "{{Polymorphic}} model not found: `{0}` not set",
|
||||
"2f062cbecdf24245731bddc77714c814": "Could not find \"{0}\" relation for {1}",
|
||||
"3cde8cc9bca22c67278b202ab0720106": "No instance with id {0} found for {1}",
|
||||
"6502a117987610380b9068ef98b1b0ee": "No record found in {0} for ({1}.{2} ,{3}.{4})",
|
||||
"6fcc2ff0db7a4f490f5e0ce9e24691f3": "{{HasOne}} relation cannot create more than one instance of {0}",
|
||||
"7e9530c0399289be0ee601a604be71ff": "{{BelongsTo}} relation {0} is empty",
|
||||
"7faa840eb6ce11250a141deb42a6c489": "Unknown relation {{scope}}: {0}",
|
||||
"89afd3a9249f5a8d3edda07d84ca049d": "{{Polymorphic}} model not found: `{0}`",
|
||||
"a004f310d315e592843776fab964eaeb": "{{Polymorphic}} relations need a through model",
|
||||
"a25e41a39c60c4702e55d0c3936576a1": "Key mismatch: {0}.{1}: {2}, {3}.{4}: {5}",
|
||||
"a327355560d495454fba2c1aad6bdf09": "Unknown scope method: {0}",
|
||||
"e08ab0e1ab55f26c357061447b635905": "No relation found in {0} for ({1}.{2},{3}.{4})",
|
||||
"e55937649d8d7a11706b8cec22d02eae": "{{HasOne}} relation {0} is empty",
|
||||
"2c4904377a87fdab502118719cc0d266": "{{Transaction}} is not supported",
|
||||
"ecb7aa804bf54c682999d20d6436104c": "The {{transaction}} is not active: {0}",
|
||||
"89bf6d92731fe7bd2146ce8d0bec205c": "Invalid argument, must be a string, {{regex}} literal, or {{RegExp}} object",
|
||||
"8c5ab01638c1ac1d58168c6346a8481a": "Invalid {{regex}} flags: {0}",
|
||||
"a6c18a7f4390cd3d59a2a7a047ae2aab": "Run \"{{npm install loopback-datasource-juggler}} {0}\" command ",
|
||||
"b138294f132edfe1eb2a8211150c7238": "Unexpected `undefined` in query",
|
||||
"8a39126103a157f501affa070367a1b0": "The {0} instance is not valid. Details: {1}."
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
{
|
||||
"0bd753a8944ad0af85a939bb25273887": "La clave desconocida {0} no puede caducar",
|
||||
"bec226891a505828bfc76c5cfd73b336": "No se puede obtener TTL para la clave desconocida {0}",
|
||||
"4c78325cedbb826db3a05bf5df0e8546": "Debe proporcionar un {{id}} al sustituir.",
|
||||
"a0cf0e09c26df14283223e84e6a10f00": "No se han podido actualizar atributos. {{Object}} con {{id}} {0} no existe.",
|
||||
"e54d944c2a2c85a23caa86027ae307cf": "No se pueden migrar modelos no conectados a este origen de datos: {0}",
|
||||
"e6161ae8459c79d810e2aa9d21282a39": "Debe proporcionar un {{id}} al actualizar atributos.",
|
||||
"fca4d12faff1035d9d0438d73432571b": "Entrada duplicada para {0}.{1}",
|
||||
"09483e03b91c8bd58732a74b3ef1ec13": "Fecha no válida: {0}",
|
||||
"0b16d3ffc42f91b4b9a4b3b50c41c838": "El orden {0} no es válido",
|
||||
"0e88a84c6bc2638fbcc5d3ea95181f99": "Propiedad desconocida: {0}",
|
||||
"21095484501dbff31af6556fa6039182": "El parámetro de {{offset/skip}} {0} no es válido",
|
||||
"416dfbb7b823f51c9f3800be81060b41": "No se ha encontrado ninguna instancia con el {{id}} {0} para {1}",
|
||||
"4e31b1edd10dadb724d83387de0b5062": "El parámetro de {{limit}} {0} no es válido",
|
||||
"5ec8efeb715a2c34b440f2d76e2cf87d": " {0}",
|
||||
"62a2d80c405b7fec5f547c448ab1b6ff": "El {{order}} {0} tiene una dirección no válida",
|
||||
"63f503acabdc4c7588aab741b8466862": "La propiedad {0} tiene una cláusula {1} no válida",
|
||||
"67c2bf43b5281ab929617423ea8a6f3e": "El conector {0} no admite la operación {{replaceById}}. Esto no es un error en LoopBack. Póngase en contacto con los autores del conector, preferiblemente a través de cuestiones GitHub.",
|
||||
"6c3234937d69763fc7f6bcafccc59bbc": "{{Model::deleteById}} requiere el argumento {{id}}",
|
||||
"6eb6fd4fbd73394000bc25f5776fd20c": "{{Model::exists}} requiere el argumento {{id}}",
|
||||
"7bbbdece4eea90e42aa5c0bce295e503": "{{Model::findById}} requiere el argumento {{id}}",
|
||||
"9da58ab4555ac50f4999883de6470d7d": "El operador {0} contiene cláusulas {1} no válidas",
|
||||
"a829dee089c912e68c18920ba015400c": "AVISO: la propiedad {{id}} no puede cambiarse de {0} a {1} para el modelo:{2} en el gancho de operación {{'loaded'}}",
|
||||
"a984a076c59e451948b2bcf7a393d860": "AVISO: la propiedad {{id}} no puede cambiarse de {0} a {1} para el modelo:{2} en el gancho de operación {{'before save'}}",
|
||||
"baf2c8b0c5a574b8a894e9b6304fece1": "La cláusula where {0} no es un {{object}}",
|
||||
"db03083e9a768388fdbee865249ac67a": "Se ignoran los errores de validación en {{updateOrCreate()}}:",
|
||||
"e4434de4bb8f5a3cd1d416e4d80d7e0b": "{{id}} de \"{0}\" desconocido \"{1}\".",
|
||||
"e54f118a75e15e132f16b985274eb46d": "El filtro de consultas {0} no es un {{object}}",
|
||||
"f6e8c96c93b9c7687d6c172b3695e898": "La propiedad de {{id}} ({0}) no puede actualizarse de {1} a {2}",
|
||||
"0be2d39d225b1d8b2a0f92ad5c65c9ac": "No se ha especificado ningún modelo para {{polymorphic}} {0}: {1}",
|
||||
"2f4af31c144bbfab1bbf479866acd820": "\nAVISO: el conector {{LoopBack}} \"{0}\" no está instalado como ninguno de los módulos siguientes:\n\n {1}\n\nPara solucionarlo, ejecute:\n\n {{npm install {2} --save}}\n",
|
||||
"6111399276924ffa3bc9a410cdfcb2e5": "No hay ningún nombre de {{id}} {0}",
|
||||
"75518263527c423b8a12f908a2730b0f": "{{className}} es obligatorio",
|
||||
"791ab3031a73ede03f7d6299a85e8289": "Tiempo de espera agotado al conectarse después de {0} ms",
|
||||
"7b277018e43d41bc445731092b91547d": "No conectado",
|
||||
"a2487abefef4259c2131d96cdb8543b1": "La conexión falla: {0}\nSe reintentará en la siguiente solicitud.",
|
||||
"b15b20280211ad258d92947f05b6e4a5": "El conector no se ha inicializado.",
|
||||
"e0e9504e137a3c3339144b51ed76fef2": "El conector no está definido correctamente: debe crear el miembro `{{connector}}` de dataSource",
|
||||
"ec42dca074f1818c447f7ad16e2d01af": "El conector asociado no ha proporcionado {0}",
|
||||
"ba0fd8106eb54de4d003a844206431fd": "El gancho de modelo \"{0}\" está en desuso, utilice ganchos de operación en su lugar. {{http://docs.strongloop.com/display/LB/Operation+hooks}}",
|
||||
"280f4550f90e133118955ec6f6f72830": "Se ha especificado el tipo de discriminador {0}, pero no existe ningún modelo con ese nombre",
|
||||
"38dbf42c29a4645238cc3d632e88ebc9": "{{Relation.modelTo}} no se ha definido para la relación {0} y no es {{polymorphic}}",
|
||||
"eb56c2b0c30cf006e2df00a549ec9c2c": "La relación \"{0}\" no está definida para el modelo {1}",
|
||||
"938401ea4ce48159efa9be1d4a5e8bab": "Items debe ser una matriz: {0}",
|
||||
"f41bd91dc0f000a79c0bf842f1b7fdf9": "no se ha podido crear la lista a partir de la serie JSON: {0}",
|
||||
"514985b2327f061ffb1c932f6b909979": "El modelo {0} no se ha definido.",
|
||||
"cc09e361de7b0f3dc1687515c5713885": "Los nombres de propiedad que contienen un punto no están soportados. Modelo: {0}, propiedad: {1}",
|
||||
"da02dd6c53d4148320eeb31718a7aebe": "Tipo no válido para la propiedad {0}",
|
||||
"ddf0aa14803f1c84f4a97f3803f7471c": "Nombre de clase necesario",
|
||||
"1853f9414bc61ed196952f5c81e41802": "Los nombres de propiedad que contienen un punto no están soportados. Modelo: {0}, propiedad dinámica: {1}",
|
||||
"bdb11cc1c780c9ccac33c316cfdc9d82": "Tipo no definido para la propiedad {0}.{1}",
|
||||
"cd930369e86cdd222f7bd117c6f9fa94": "Proveedor de valor predeterminado desconocido {0}",
|
||||
"0c0b867aca0973ba26e887d3337cc4ec": "Modelo {{Polymorphic}} no encontrado: `{0}` no establecido",
|
||||
"2f062cbecdf24245731bddc77714c814": "No se ha encontrado la relación \"{0}\" para {1}",
|
||||
"3cde8cc9bca22c67278b202ab0720106": "No se ha encontrado ninguna instancia con el ID {0} para {1}",
|
||||
"6502a117987610380b9068ef98b1b0ee": "No se ha encontrado ningún registro en {0} para ({1}.{2} ,{3}.{4})",
|
||||
"6fcc2ff0db7a4f490f5e0ce9e24691f3": "La relación {{HasOne}} no puede crear más de una instancia de {0}",
|
||||
"7e9530c0399289be0ee601a604be71ff": "la relación {{BelongsTo}} {0} está vacía",
|
||||
"7faa840eb6ce11250a141deb42a6c489": "Relación desconocida {{scope}}: {0}",
|
||||
"89afd3a9249f5a8d3edda07d84ca049d": "Modelo {{Polymorphic}} no encontrado: `{0}`",
|
||||
"a004f310d315e592843776fab964eaeb": "Las relaciones {{Polymorphic}} necesitan un modelo definido",
|
||||
"a25e41a39c60c4702e55d0c3936576a1": "Discrepancia de claves: {0}.{1}: {2}, {3}.{4}: {5}",
|
||||
"a327355560d495454fba2c1aad6bdf09": "Método de ámbito desconocido: {0}",
|
||||
"e08ab0e1ab55f26c357061447b635905": "No se ha encontrado ninguna relación en {0} para ({1}.{2},{3}.{4})",
|
||||
"e55937649d8d7a11706b8cec22d02eae": "la relación {{HasOne}} {0} está vacía",
|
||||
"2c4904377a87fdab502118719cc0d266": "{{Transaction}} no está soportada.",
|
||||
"ecb7aa804bf54c682999d20d6436104c": "La {{transaction}} no está activa: {0}",
|
||||
"89bf6d92731fe7bd2146ce8d0bec205c": "Argumento no válido, debe ser una serie, literal de {{regex}} u objeto {{RegExp}}",
|
||||
"8c5ab01638c1ac1d58168c6346a8481a": "Distintivos de {{regex}} no válidos: {0}",
|
||||
"a6c18a7f4390cd3d59a2a7a047ae2aab": "Ejecute el mandato \"{{npm install loopback-datasource-juggler}} {0}\" ",
|
||||
"b138294f132edfe1eb2a8211150c7238": "`undefined` inesperado en la consulta",
|
||||
"8a39126103a157f501affa070367a1b0": "La instancia {0} no es válida. Detalles: {1}."
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
{
|
||||
"0bd753a8944ad0af85a939bb25273887": "Impossible de faire expirer la clé inconnue {0}",
|
||||
"bec226891a505828bfc76c5cfd73b336": "Impossible d'obtenir TTL pour la clé inconnue {0}",
|
||||
"4c78325cedbb826db3a05bf5df0e8546": "Vous devez fournir un {{id}} lors du remplacement !",
|
||||
"a0cf0e09c26df14283223e84e6a10f00": "Impossible de mettre à jour les attributs. {{Object}} avec {{id}} {0} n'existe pas !",
|
||||
"e54d944c2a2c85a23caa86027ae307cf": "Impossible de migrer les modèles non associés à cette source de données : {0}",
|
||||
"e6161ae8459c79d810e2aa9d21282a39": "Vous devez fournir un {{id}} lors de la mise à jour des attributs !",
|
||||
"fca4d12faff1035d9d0438d73432571b": "Entrée en double pour {0}.{1}",
|
||||
"09483e03b91c8bd58732a74b3ef1ec13": "Date non valide : {0}",
|
||||
"0b16d3ffc42f91b4b9a4b3b50c41c838": "L'ordre {0} n'est pas valide",
|
||||
"0e88a84c6bc2638fbcc5d3ea95181f99": "Propriété inconnue : {0}",
|
||||
"21095484501dbff31af6556fa6039182": "Le paramètre {{offset/skip}} {0} n'est pas valide",
|
||||
"416dfbb7b823f51c9f3800be81060b41": "Aucune instance avec {{id}} {0} trouvée pour {1}",
|
||||
"4e31b1edd10dadb724d83387de0b5062": "Le paramètre {{limit}} {0} n'est pas valide",
|
||||
"5ec8efeb715a2c34b440f2d76e2cf87d": " {0}",
|
||||
"62a2d80c405b7fec5f547c448ab1b6ff": "{{order}} {0} a une direction non valide",
|
||||
"63f503acabdc4c7588aab741b8466862": "La propriété {0} a la clause non valide {1}",
|
||||
"67c2bf43b5281ab929617423ea8a6f3e": "Le connecteur {0} ne prend pas en charge l'opération {{replaceById}}. IL ne s'agit pas d'un bogue dans LoopBack. Prenez contact avec les auteurs du connecteur, de préférence via les incidents GitHub.",
|
||||
"6c3234937d69763fc7f6bcafccc59bbc": "{{Model::deleteById}} requiert l'argument {{id}}",
|
||||
"6eb6fd4fbd73394000bc25f5776fd20c": "{{Model::exists}} requiert l'argument {{id}}",
|
||||
"7bbbdece4eea90e42aa5c0bce295e503": "{{Model::findById}} requiert l'argument {{id}}",
|
||||
"9da58ab4555ac50f4999883de6470d7d": "L'opérateur {0} a les clauses non valides {1}",
|
||||
"a829dee089c912e68c18920ba015400c": "AVERTISSEMENT : la propriété {{id}} ne peut pas être modifiée de {0} en {1} pour le modèle :{2} dans le point d'ancrage d'opération {{'loaded'}}",
|
||||
"a984a076c59e451948b2bcf7a393d860": "AVERTISSEMENT : la propriété {{id}} ne peut pas être modifiée de {0} en {1} pour le modèle :{2} dans le point d'ancrage d'opération {{'before save'}}",
|
||||
"baf2c8b0c5a574b8a894e9b6304fece1": "La clause where {0} n'est pas un {{object}}",
|
||||
"db03083e9a768388fdbee865249ac67a": "Erreurs de validation ignorées dans {{updateOrCreate()}} :",
|
||||
"e4434de4bb8f5a3cd1d416e4d80d7e0b": "\"{0}\" {{id}} \"{1}\" inconnu.",
|
||||
"e54f118a75e15e132f16b985274eb46d": "Le filtre de requête {0} n'est pas un {{object}}",
|
||||
"f6e8c96c93b9c7687d6c172b3695e898": "La propriété {{id}} ({0}) ne peut pas être mise à jour à partir de {1} vers {2}",
|
||||
"0be2d39d225b1d8b2a0f92ad5c65c9ac": "Aucun modèle spécifié pour {{polymorphic}} {0} : {1}",
|
||||
"2f4af31c144bbfab1bbf479866acd820": "\nAVERTISSEMENT : Le connecteur {{LoopBack}} \"{0}\" n'est pas installé, tout comme les modules suivants :\n\n {1}\n\nPour corriger le problème, exécutez :\n\n {{npm install {2} --save}}\n",
|
||||
"6111399276924ffa3bc9a410cdfcb2e5": "Aucun nom {{id}} {0}",
|
||||
"75518263527c423b8a12f908a2730b0f": "{{className}} est obligatoire",
|
||||
"791ab3031a73ede03f7d6299a85e8289": "Expiration du délai de connexion après {0} ms",
|
||||
"7b277018e43d41bc445731092b91547d": "Non connecté",
|
||||
"a2487abefef4259c2131d96cdb8543b1": "Echec de la connexion : {0}\nUn nouvel essai sera effectué pour la demande suivante.",
|
||||
"b15b20280211ad258d92947f05b6e4a5": "Le connecteur n'a pas été initialisé.",
|
||||
"e0e9504e137a3c3339144b51ed76fef2": "Le connecteur n'est pas défini correctement ; il devrait créer le membre `{{connector}}` de la source de données",
|
||||
"ec42dca074f1818c447f7ad16e2d01af": "{0} n'est pas fourni par le connecteur associé",
|
||||
"ba0fd8106eb54de4d003a844206431fd": "Le point d'ancrage de modèle \"{0}\" est obsolète ; utilisez à la place les points d'ancrage d'opération. {{http://docs.strongloop.com/display/LB/Operation+hooks}}",
|
||||
"280f4550f90e133118955ec6f6f72830": "Le type de discriminateur {0} est indiqué mais il n'existe pas de modèle de ce nom",
|
||||
"38dbf42c29a4645238cc3d632e88ebc9": "{{Relation.modelTo}} n'est pas défini pour la relation {0} et il n'est pas {{polymorphic}}",
|
||||
"eb56c2b0c30cf006e2df00a549ec9c2c": "La relation \"{0}\" n'est pas définie pour le modèle {1}",
|
||||
"938401ea4ce48159efa9be1d4a5e8bab": "Les éléments doivent être un tableau : {0}",
|
||||
"f41bd91dc0f000a79c0bf842f1b7fdf9": "impossible de créer la liste à partir de la chaîne JSON : {0}",
|
||||
"514985b2327f061ffb1c932f6b909979": "Le modèle {0} n'est pas défini.",
|
||||
"cc09e361de7b0f3dc1687515c5713885": "Les noms de propriété contentant un point ne sont pas pris en charge. Modèle : {0}, propriété : {1}",
|
||||
"da02dd6c53d4148320eeb31718a7aebe": "Type non valide pour la propriété {0}",
|
||||
"ddf0aa14803f1c84f4a97f3803f7471c": "Nom de classe obligatoire",
|
||||
"1853f9414bc61ed196952f5c81e41802": "Les noms de propriété contentant un point ne sont pas pris en charge. Modèle : {0}, propriété dynamique : {1}",
|
||||
"bdb11cc1c780c9ccac33c316cfdc9d82": "Type non défini pour la propriété {0}.{1}",
|
||||
"cd930369e86cdd222f7bd117c6f9fa94": "Fournisseur de valeur par défaut inconnu {0}",
|
||||
"0c0b867aca0973ba26e887d3337cc4ec": "Modèle {{Polymorphic}} non trouvé : `{0}` non défini",
|
||||
"2f062cbecdf24245731bddc77714c814": "Relation \"{0}\" introuvable pour {1}",
|
||||
"3cde8cc9bca22c67278b202ab0720106": "Aucune instance avec l'id {0} trouvée pour {1}",
|
||||
"6502a117987610380b9068ef98b1b0ee": "Aucun enregistrement trouvé dans {0} pour ({1}.{2} ,{3}.{4})",
|
||||
"6fcc2ff0db7a4f490f5e0ce9e24691f3": "La relation {{HasOne}} ne peut pas créer plus d'une instance de {0}",
|
||||
"7e9530c0399289be0ee601a604be71ff": "La relation {{BelongsTo}} {0} est vide",
|
||||
"7faa840eb6ce11250a141deb42a6c489": "Relation inconnue {{scope}} : {0}",
|
||||
"89afd3a9249f5a8d3edda07d84ca049d": "Modèle {{Polymorphic}} introuvable : `{0}`",
|
||||
"a004f310d315e592843776fab964eaeb": "Les relations {{Polymorphic}} ont besoin d'un modèle exhaustif",
|
||||
"a25e41a39c60c4702e55d0c3936576a1": "Non-concordance de clé : {0}.{1}: {2}, {3}.{4}: {5}",
|
||||
"a327355560d495454fba2c1aad6bdf09": "Méthode scope inconnue : {0}",
|
||||
"e08ab0e1ab55f26c357061447b635905": "Aucune relation trouvée dans {0} pour ({1}.{2},{3}.{4})",
|
||||
"e55937649d8d7a11706b8cec22d02eae": "La relation {{HasOne}} {0} est vide",
|
||||
"2c4904377a87fdab502118719cc0d266": "{{Transaction}} n'est pas pris en charge",
|
||||
"ecb7aa804bf54c682999d20d6436104c": "{{transaction}} n'est pas actif : {0}",
|
||||
"89bf6d92731fe7bd2146ce8d0bec205c": "Argument non valide ; doit être une chaîne, un littéral {{regex}} ou un objet {{RegExp}}",
|
||||
"8c5ab01638c1ac1d58168c6346a8481a": "Indicateurs {{regex}} non valides : {0}",
|
||||
"a6c18a7f4390cd3d59a2a7a047ae2aab": "Exécuter la commande \"{{npm install loopback-datasource-juggler}} {0}\" ",
|
||||
"b138294f132edfe1eb2a8211150c7238": "`undefined` inattendu dans la requête",
|
||||
"8a39126103a157f501affa070367a1b0": "L'instance {0} n'est pas valide. Détails : {1}."
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
{
|
||||
"0bd753a8944ad0af85a939bb25273887": "Impossibile fare scadere la chiave sconosciuta {0}",
|
||||
"bec226891a505828bfc76c5cfd73b336": "Impossibile acquisire TTL per la chiave sconosciuta {0}",
|
||||
"4c78325cedbb826db3a05bf5df0e8546": "È necessario fornire un {{id}} durante la sostituzione.",
|
||||
"a0cf0e09c26df14283223e84e6a10f00": "Impossibile aggiornare gli attributi. {{Object}} con {{id}} {0} non esiste.",
|
||||
"e54d944c2a2c85a23caa86027ae307cf": "Impossibile migrare i modelli non allegati a questa origine dati: {0}",
|
||||
"e6161ae8459c79d810e2aa9d21282a39": "È necessario fornire un {{id}} durante l'aggiornamento degli attributi.",
|
||||
"fca4d12faff1035d9d0438d73432571b": "Voce duplicata per {0}.{1}",
|
||||
"09483e03b91c8bd58732a74b3ef1ec13": "Data non valida: {0}",
|
||||
"0b16d3ffc42f91b4b9a4b3b50c41c838": "L'ordine {0} non è valido",
|
||||
"0e88a84c6bc2638fbcc5d3ea95181f99": "Proprietà sconosciuta: {0}",
|
||||
"21095484501dbff31af6556fa6039182": "Il parametro {{offset/skip}} {0} non è valido",
|
||||
"416dfbb7b823f51c9f3800be81060b41": "Nessuna istanza con {{id}} {0} trovata per {1}",
|
||||
"4e31b1edd10dadb724d83387de0b5062": "Il parametro {{limit}} {0} non è valido",
|
||||
"5ec8efeb715a2c34b440f2d76e2cf87d": " {0}",
|
||||
"62a2d80c405b7fec5f547c448ab1b6ff": "{{order}} {0} ha una direzione non valida",
|
||||
"63f503acabdc4c7588aab741b8466862": "La proprietà {0} ha una clausola non valida {1}",
|
||||
"67c2bf43b5281ab929617423ea8a6f3e": "Il connettore {0} non supporta l'operazione {{replaceById}}. Questo non è un bug in LoopBack. Contattare gli autori del connettore, preferibilmente mediante GitHub.",
|
||||
"6c3234937d69763fc7f6bcafccc59bbc": "{{Model::deleteById}} richiede l'argomento {{id}}",
|
||||
"6eb6fd4fbd73394000bc25f5776fd20c": "{{Model::exists}} richiede l'argomento {{id}}",
|
||||
"7bbbdece4eea90e42aa5c0bce295e503": "{{Model::findById}} richiede l'argomento {{id}}",
|
||||
"9da58ab4555ac50f4999883de6470d7d": "L'operatore {0} ha clausole non valide {1}",
|
||||
"a829dee089c912e68c18920ba015400c": "AVVERTENZA: impossibile modificare la proprietà {{id}} da {0} a {1} per il modello:{2} nell'hook operazione {{'loaded'}}",
|
||||
"a984a076c59e451948b2bcf7a393d860": "AVVERTENZA: impossibile modificare la proprietà {{id}} da {0} a {1} per il modello:{2} nell'hook operazione {{'before save'}}",
|
||||
"baf2c8b0c5a574b8a894e9b6304fece1": "La clausola where {0} non è un {{object}}",
|
||||
"db03083e9a768388fdbee865249ac67a": "Errore di convalida in {{updateOrCreate()}} ignorati:",
|
||||
"e4434de4bb8f5a3cd1d416e4d80d7e0b": "{{id}} \"{0}\" sconosciuto \"{1}\".",
|
||||
"e54f118a75e15e132f16b985274eb46d": "Il filtro della query {0} non è un {{object}}",
|
||||
"f6e8c96c93b9c7687d6c172b3695e898": "Impossibile aggiornare la proprietà {{id}} ({0}) da {1} a {2}",
|
||||
"0be2d39d225b1d8b2a0f92ad5c65c9ac": "Nessun modello specificato per {{polymorphic}} {0}: {1}",
|
||||
"2f4af31c144bbfab1bbf479866acd820": "\nAVVERTENZA: il connettore {{LoopBack}} \"{0}\" non è installato come nessuno dei seguenti moduli:\n\n {1}\n\nPer correggere, eseguire:\n\n {{npm install {2} --save}}\n",
|
||||
"6111399276924ffa3bc9a410cdfcb2e5": "Nessun nome {{id}} {0}",
|
||||
"75518263527c423b8a12f908a2730b0f": "{{className}} è obbligatorio",
|
||||
"791ab3031a73ede03f7d6299a85e8289": "Timeout nella connessione dopo {0} ms",
|
||||
"7b277018e43d41bc445731092b91547d": "Non connesso",
|
||||
"a2487abefef4259c2131d96cdb8543b1": "Errore della connessione: {0}\nVerrà eseguito un nuovo tentativo per la richiesta successiva.",
|
||||
"b15b20280211ad258d92947f05b6e4a5": "Il connettore non è stato inizializzato.",
|
||||
"e0e9504e137a3c3339144b51ed76fef2": "Il connettore non è definito correttamente: deve creare il membro `{{connector}}` di dataSource",
|
||||
"ec42dca074f1818c447f7ad16e2d01af": "{0} non fornito dal connettore collegato",
|
||||
"ba0fd8106eb54de4d003a844206431fd": "L'hook del modello \"{0}\" è obsoleto, utilizzare gli hook dell'operazione. {{http://docs.strongloop.com/display/LB/Operation+hooks}}",
|
||||
"280f4550f90e133118955ec6f6f72830": "È stato specificato il tipo di discriminatore {0} ma non esiste alcun modello con tale nome",
|
||||
"38dbf42c29a4645238cc3d632e88ebc9": "{{Relation.modelTo}} non è definito per la relazione {0} e non è {{polymorphic}}",
|
||||
"eb56c2b0c30cf006e2df00a549ec9c2c": "Relazione \"{0}\" non definita per il modello {1}",
|
||||
"938401ea4ce48159efa9be1d4a5e8bab": "Gli elementi devono essere un array: {0}",
|
||||
"f41bd91dc0f000a79c0bf842f1b7fdf9": "impossibile creare un elenco dalla stringa JSON: {0}",
|
||||
"514985b2327f061ffb1c932f6b909979": "Il modello {0} non è definito.",
|
||||
"cc09e361de7b0f3dc1687515c5713885": "I nomi delle proprietà che contengono un punto non sono supportati. Modello: {0}, proprietà: {1}",
|
||||
"da02dd6c53d4148320eeb31718a7aebe": "Tipo non valido per la proprietà {0}",
|
||||
"ddf0aa14803f1c84f4a97f3803f7471c": "Nome della classe obbligatorio",
|
||||
"1853f9414bc61ed196952f5c81e41802": "I nomi delle proprietà che contengono un punto non sono supportati. Modello: {0}, proprietà dinamica: {1}",
|
||||
"bdb11cc1c780c9ccac33c316cfdc9d82": "Tipo non definito per la proprietà {0}.{1}",
|
||||
"cd930369e86cdd222f7bd117c6f9fa94": "Provider del valore predefinito sconosciuto {0}",
|
||||
"0c0b867aca0973ba26e887d3337cc4ec": "Modello {{Polymorphic}} non trovato: `{0}` non impostato",
|
||||
"2f062cbecdf24245731bddc77714c814": "Impossibile trovare la relazione \"{0}\" per {1}",
|
||||
"3cde8cc9bca22c67278b202ab0720106": "Nessuna istanza con ID {0} trovata per {1}",
|
||||
"6502a117987610380b9068ef98b1b0ee": "Nessun record trovato in {0} per ({1}.{2} ,{3}.{4})",
|
||||
"6fcc2ff0db7a4f490f5e0ce9e24691f3": "La relazione {{HasOne}} non può creare più di una istanza di {0}",
|
||||
"7e9530c0399289be0ee601a604be71ff": "La relazione {{BelongsTo}} {0} è vuota",
|
||||
"7faa840eb6ce11250a141deb42a6c489": "Relazione sconosciuta {{scope}}: {0}",
|
||||
"89afd3a9249f5a8d3edda07d84ca049d": "Modello {{Polymorphic}} non trovato: `{0}`",
|
||||
"a004f310d315e592843776fab964eaeb": "Le relazioni {{Polymorphic}} richiedono un modello di passaggio",
|
||||
"a25e41a39c60c4702e55d0c3936576a1": "Mancata corrispondenza della chiave: {0}.{1}: {2}, {3}.{4}: {5}",
|
||||
"a327355560d495454fba2c1aad6bdf09": "Metodo dell'ambito sconosciuto: {0}",
|
||||
"e08ab0e1ab55f26c357061447b635905": "Nessuna relazione trovata in {0} per ({1}.{2},{3}.{4})",
|
||||
"e55937649d8d7a11706b8cec22d02eae": "La relazione {{HasOne}} {0} è vuota",
|
||||
"2c4904377a87fdab502118719cc0d266": "{{Transaction}} non supportata",
|
||||
"ecb7aa804bf54c682999d20d6436104c": "La {{transaction}} non è attiva: {0}",
|
||||
"89bf6d92731fe7bd2146ce8d0bec205c": "Argomento non valido, deve essere una stringa, un valore letterale {{regex}} o un oggetto {{RegExp}}",
|
||||
"8c5ab01638c1ac1d58168c6346a8481a": "Indicatori {{regex}} non validi: {0}",
|
||||
"a6c18a7f4390cd3d59a2a7a047ae2aab": "Eseguire il comando \"{{npm install loopback-datasource-juggler}} {0}\" ",
|
||||
"b138294f132edfe1eb2a8211150c7238": "Elemento `undefined` non previsto nella query",
|
||||
"8a39126103a157f501affa070367a1b0": "L'istanza {0} non è valida. Dettagli: {1}."
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
{
|
||||
"0bd753a8944ad0af85a939bb25273887": "不明のキー {0} を期限切れにすることができません",
|
||||
"bec226891a505828bfc76c5cfd73b336": "不明のキー {0} の TTL を取得できません",
|
||||
"4c78325cedbb826db3a05bf5df0e8546": "置換するときは {{id}} を指定する必要があります。",
|
||||
"a0cf0e09c26df14283223e84e6a10f00": "属性を更新できませんでした。 {{id}} {0} の {{Object}} は存在しません。",
|
||||
"e54d944c2a2c85a23caa86027ae307cf": "このデータ・ソースに付加されていないモデルはマイグレーションできません: {0}",
|
||||
"e6161ae8459c79d810e2aa9d21282a39": "属性を更新するときは {{id}} を指定する必要があります。",
|
||||
"fca4d12faff1035d9d0438d73432571b": "{0}.{1} のエントリーが重複しています",
|
||||
"09483e03b91c8bd58732a74b3ef1ec13": "無効な日付: {0}",
|
||||
"0b16d3ffc42f91b4b9a4b3b50c41c838": "順序 {0} が無効です",
|
||||
"0e88a84c6bc2638fbcc5d3ea95181f99": "不明なプロパティー: {0}",
|
||||
"21095484501dbff31af6556fa6039182": "{{offset/skip}} パラメーター {0} は無効です",
|
||||
"416dfbb7b823f51c9f3800be81060b41": "{1} に関する {{id}} {0} のインスタンスが見つかりません",
|
||||
"4e31b1edd10dadb724d83387de0b5062": "{{limit}} パラメーター {0} は無効です",
|
||||
"5ec8efeb715a2c34b440f2d76e2cf87d": " {0}",
|
||||
"62a2d80c405b7fec5f547c448ab1b6ff": "{{order}} {0} の方向が無効です",
|
||||
"63f503acabdc4c7588aab741b8466862": "{0} プロパティーには無効な節 {1} があります",
|
||||
"67c2bf43b5281ab929617423ea8a6f3e": "コネクター {0} では {{replaceById}} 操作はサポートされません。 これは LoopBack のバグではありません。 コネクターの作成者に (なるべく GitHub Issue を通して) 問い合わせてください。",
|
||||
"6c3234937d69763fc7f6bcafccc59bbc": "{{Model::deleteById}} には {{id}} 引数が必要です",
|
||||
"6eb6fd4fbd73394000bc25f5776fd20c": "{{Model::exists}} には {{id}} 引数が必要です",
|
||||
"7bbbdece4eea90e42aa5c0bce295e503": "{{Model::findById}} には {{id}} 引数が必要です",
|
||||
"9da58ab4555ac50f4999883de6470d7d": "{0} 演算子には無効な節 {1} があります",
|
||||
"a829dee089c912e68c18920ba015400c": "警告: {{'loaded'}} 操作フックでモデル {2} の {{id}} プロパティーを {0} から {1} に変更することはできません",
|
||||
"a984a076c59e451948b2bcf7a393d860": "警告: {{'before save'}} 操作フックでモデル {2} の {{id}} プロパティーを {0} から {1} に変更することはできません",
|
||||
"baf2c8b0c5a574b8a894e9b6304fece1": "where 節 {0} が {{object}} ではありません",
|
||||
"db03083e9a768388fdbee865249ac67a": "{{updateOrCreate()}} での妥当性検査エラーを無視します:",
|
||||
"e4434de4bb8f5a3cd1d416e4d80d7e0b": "\"{0}\" {{id}} \"{1}\" が不明です。",
|
||||
"e54f118a75e15e132f16b985274eb46d": "照会フィルター {0} が {{object}} ではありません",
|
||||
"f6e8c96c93b9c7687d6c172b3695e898": "{{id}} プロパティー ({0}) を {1} から {2} に更新できません",
|
||||
"0be2d39d225b1d8b2a0f92ad5c65c9ac": "{{polymorphic}} {0}: {1} にモデルが指定されていません",
|
||||
"2f4af31c144bbfab1bbf479866acd820": "\n警告: {{LoopBack}} コネクター \"{0}\" は次のいずれのモジュールとしてもインストールされていません:\n\n {1}\n\n修正するには、以下を実行します。\n\n {{npm install {2} --save}}\n",
|
||||
"6111399276924ffa3bc9a410cdfcb2e5": "{{id}} 名 {0} がありません",
|
||||
"75518263527c423b8a12f908a2730b0f": "{{className}} は必須です",
|
||||
"791ab3031a73ede03f7d6299a85e8289": "接続は {0} ミリ秒後にタイムアウトになります",
|
||||
"7b277018e43d41bc445731092b91547d": "未接続",
|
||||
"a2487abefef4259c2131d96cdb8543b1": "接続失敗: {0}\n次の要求で再試行されます。",
|
||||
"b15b20280211ad258d92947f05b6e4a5": "コネクターが初期化されていません。",
|
||||
"e0e9504e137a3c3339144b51ed76fef2": "コネクターが正しく定義されていません: dataSource の `{{connector}}` メンバーを作成する必要があります",
|
||||
"ec42dca074f1818c447f7ad16e2d01af": "{0} は付加されたコネクターによって提供されません",
|
||||
"ba0fd8106eb54de4d003a844206431fd": "モデル・フック \"{0}\" は非推奨です。代わりに操作フックを使用してください。 {{http://docs.strongloop.com/display/LB/Operation+hooks}}",
|
||||
"280f4550f90e133118955ec6f6f72830": "判別プログラム・タイプ {0} が指定されていますが、このような名前のモデルは存在しません",
|
||||
"38dbf42c29a4645238cc3d632e88ebc9": "{{Relation.modelTo}} は関係 {0} に定義されておらず、{{polymorphic}} ではありません",
|
||||
"eb56c2b0c30cf006e2df00a549ec9c2c": "関係 \"{0}\" は {1} モデルに定義されていません",
|
||||
"938401ea4ce48159efa9be1d4a5e8bab": "項目は配列でなければなりません: {0}",
|
||||
"f41bd91dc0f000a79c0bf842f1b7fdf9": "JSON ストリングからリストを作成できませんでした: {0}",
|
||||
"514985b2327f061ffb1c932f6b909979": "モデル {0} が定義されていません。",
|
||||
"cc09e361de7b0f3dc1687515c5713885": "ドットが含まれたプロパティー名はサポートされていません。 モデル: {0}、プロパティー: {1}",
|
||||
"da02dd6c53d4148320eeb31718a7aebe": "プロパティー {0} のタイプが無効です",
|
||||
"ddf0aa14803f1c84f4a97f3803f7471c": "クラス名は必須です",
|
||||
"1853f9414bc61ed196952f5c81e41802": "ドットが含まれたプロパティー名はサポートされていません。 モデル: {0}、動的プロパティー: {1}",
|
||||
"bdb11cc1c780c9ccac33c316cfdc9d82": "プロパティー {0}.{1} にタイプが定義されていません",
|
||||
"cd930369e86cdd222f7bd117c6f9fa94": "不明なデフォルト値プロバイダー {0}",
|
||||
"0c0b867aca0973ba26e887d3337cc4ec": "{{Polymorphic}} モデルが見つかりません: `{0}` が設定されていません",
|
||||
"2f062cbecdf24245731bddc77714c814": "{1} の \"{0}\" 関係が見つかりませんでした",
|
||||
"3cde8cc9bca22c67278b202ab0720106": "{1} に関する ID {0} のインスタンスが見つかりません",
|
||||
"6502a117987610380b9068ef98b1b0ee": "({1}.{2}、{3}.{4}) に関して {0} でレコードが見つかりません",
|
||||
"6fcc2ff0db7a4f490f5e0ce9e24691f3": "{{HasOne}} 関係では {0} のインスタンスを複数作成することはできません",
|
||||
"7e9530c0399289be0ee601a604be71ff": "{{BelongsTo}} 関係 {0} が空です",
|
||||
"7faa840eb6ce11250a141deb42a6c489": "不明な関係 {{scope}}: {0}",
|
||||
"89afd3a9249f5a8d3edda07d84ca049d": "{{Polymorphic}} モデルが見つかりません: `{0}`",
|
||||
"a004f310d315e592843776fab964eaeb": "{{Polymorphic}} 関係にはスルー・モデルが必要です",
|
||||
"a25e41a39c60c4702e55d0c3936576a1": "キーの不一致: {0}.{1}: {2}、{3}.{4}: {5}",
|
||||
"a327355560d495454fba2c1aad6bdf09": "不明なスコープ・メソッド: {0}",
|
||||
"e08ab0e1ab55f26c357061447b635905": "({1}.{2}、{3}.{4}) に関して {0} で関係が見つかりません",
|
||||
"e55937649d8d7a11706b8cec22d02eae": "{{HasOne}} 関係 {0} が空です",
|
||||
"2c4904377a87fdab502118719cc0d266": "{{Transaction}} はサポートされていません",
|
||||
"ecb7aa804bf54c682999d20d6436104c": "{{transaction}} がアクティブではありません: {0}",
|
||||
"89bf6d92731fe7bd2146ce8d0bec205c": "引数が無効です。ストリング、{{regex}} リテラル、または {{RegExp}} オブジェクトでなければなりません",
|
||||
"8c5ab01638c1ac1d58168c6346a8481a": "無効な {{regex}} フラグ: {0}",
|
||||
"a6c18a7f4390cd3d59a2a7a047ae2aab": "\"{{npm install loopback-datasource-juggler}} {0}\" コマンドを実行します ",
|
||||
"b138294f132edfe1eb2a8211150c7238": "照会内に予期しない `undefined` があります",
|
||||
"8a39126103a157f501affa070367a1b0": "{0} インスタンスは無効です。 詳細: {1}。"
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
{
|
||||
"0bd753a8944ad0af85a939bb25273887": "알 수 없는 키 {0}을(를) 만료할 수 없음",
|
||||
"bec226891a505828bfc76c5cfd73b336": "알 수 없는 키 {0}에 대한 TTL을 가져올 수 없음",
|
||||
"4c78325cedbb826db3a05bf5df0e8546": "바꾸는 경우 {{id}}을(를) 제공해야 합니다!",
|
||||
"a0cf0e09c26df14283223e84e6a10f00": "속성을 업데이트할 수 없습니다. {{id}} {0}의 {{Object}}이(가) 없습니다!",
|
||||
"e54d944c2a2c85a23caa86027ae307cf": "이 데이터 소스에 첨부되지 않은 모델은 마이그레이션할 수 없음: {0}",
|
||||
"e6161ae8459c79d810e2aa9d21282a39": "속성을 업데이트하는 경우 {{id}}을(를) 제공해야 합니다!",
|
||||
"fca4d12faff1035d9d0438d73432571b": "{0}.{1}의 중복 항목",
|
||||
"09483e03b91c8bd58732a74b3ef1ec13": "올바르지 않은 날짜: {0}",
|
||||
"0b16d3ffc42f91b4b9a4b3b50c41c838": "{0} 순서가 올바르지 않음",
|
||||
"0e88a84c6bc2638fbcc5d3ea95181f99": "알 수 없는 특성: {0}",
|
||||
"21095484501dbff31af6556fa6039182": "{{offset/skip}} 매개변수 {0}이(가) 올바르지 않음",
|
||||
"416dfbb7b823f51c9f3800be81060b41": "{1}에 대해 {{id}} {0}의 인스턴스를 찾을 수 없음",
|
||||
"4e31b1edd10dadb724d83387de0b5062": "{{limit}} 매개변수 {0}이(가) 올바르지 않음",
|
||||
"5ec8efeb715a2c34b440f2d76e2cf87d": " {0}",
|
||||
"62a2d80c405b7fec5f547c448ab1b6ff": "{{order}} {0}에 올바르지 않은 방향이 있음",
|
||||
"63f503acabdc4c7588aab741b8466862": "{0} 특성에 올바르지 않은 절 {1}이(가) 있음",
|
||||
"67c2bf43b5281ab929617423ea8a6f3e": "커넥터 {0}에서 {{replaceById}} 오퍼레이션을 지원하지 않습니다. 이는 LoopBack의 버그가 아닙니다. 커넥터 작성자에게 문의하십시오. GitHub 발행을 사용하는 것이 좋습니다. ",
|
||||
"6c3234937d69763fc7f6bcafccc59bbc": "{{Model::deleteById}}에 {{id}} 인수가 필요함",
|
||||
"6eb6fd4fbd73394000bc25f5776fd20c": "{{Model::exists}}에 {{id}} 인수가 필요함",
|
||||
"7bbbdece4eea90e42aa5c0bce295e503": "{{Model::findById}}에 {{id}} 인수가 필요함",
|
||||
"9da58ab4555ac50f4999883de6470d7d": "{0} 연산자에 올바르지 않은 절 {1}이(가) 있음",
|
||||
"a829dee089c912e68c18920ba015400c": "경고: {{'loaded'}} 오퍼레이션 후크에서 모델:{2}에 대해 {{id}} 특성을 {0}에서 {1}(으)로 변경할 수 없습니다. ",
|
||||
"a984a076c59e451948b2bcf7a393d860": "경고: {{'before save'}} 오퍼레이션 후크에서 모델:{2}에 대해 {{id}} 특성을 {0}에서 {1}(으)로 변경할 수 없습니다. ",
|
||||
"baf2c8b0c5a574b8a894e9b6304fece1": "where 절 {0}이(가) {{object}}이(가) 아님",
|
||||
"db03083e9a768388fdbee865249ac67a": "{{updateOrCreate()}}에서 유효성 검증 오류 무시:",
|
||||
"e4434de4bb8f5a3cd1d416e4d80d7e0b": "알 수 없는 \"{0}\" {{id}} \"{1}\".",
|
||||
"e54f118a75e15e132f16b985274eb46d": "조회 필터 {0}이(가) {{object}}가 아님",
|
||||
"f6e8c96c93b9c7687d6c172b3695e898": "{{id}} 특성({0})을 {1}에서 {2}(으)로 업데이트할 수 없음",
|
||||
"0be2d39d225b1d8b2a0f92ad5c65c9ac": "{{polymorphic}} {0}에 지정된 모델이 없음: {1}",
|
||||
"2f4af31c144bbfab1bbf479866acd820": "\n경고: {{LoopBack}} 커넥터 \"{0}\"이(가) 다음 모듈로 설치되어 있지 않음:\n\n {1}\n\n이를 수정하려면 다음을 실행하십시오. \n\n {{npm install {2} --save}}\n",
|
||||
"6111399276924ffa3bc9a410cdfcb2e5": "{{id}} 이름 {0}이(가) 아님",
|
||||
"75518263527c423b8a12f908a2730b0f": "{{className}}은(는) 필수입니다.",
|
||||
"791ab3031a73ede03f7d6299a85e8289": "{0}밀리초 후 연결 제한시간 초과",
|
||||
"7b277018e43d41bc445731092b91547d": "연결되지 않음",
|
||||
"a2487abefef4259c2131d96cdb8543b1": "연결 실패: {0}\n다음 요청에서 재시도됩니다.",
|
||||
"b15b20280211ad258d92947f05b6e4a5": "커넥터가 초기화되지 않았습니다.",
|
||||
"e0e9504e137a3c3339144b51ed76fef2": "커넥터가 제대로 정의되지 않음: 데이터 소스의 `{{connector}}` 멤버를 작성해야 합니다. ",
|
||||
"ec42dca074f1818c447f7ad16e2d01af": "첨부된 커넥터에서 {0}을(를) 제공하지 않음",
|
||||
"ba0fd8106eb54de4d003a844206431fd": "모델 후크 \"{0}\"이(가) 더 이상 사용되지 않습니다. 오퍼레이션 후크가 대신 사용됩니다. {{http://docs.strongloop.com/display/LB/Operation+hooks}}",
|
||||
"280f4550f90e133118955ec6f6f72830": "식별자 유형 {0}이(가) 지정되었지만 해당 이름의 모델이 없습니다.",
|
||||
"38dbf42c29a4645238cc3d632e88ebc9": "관계 {0}에 대해 {{Relation.modelTo}}이(가) 정의되지 않았으며 {{polymorphic}}이(가) 아닙니다. ",
|
||||
"eb56c2b0c30cf006e2df00a549ec9c2c": "{1} 모델에 대해 관계 \"{0}\"이(가) 정의되지 않음",
|
||||
"938401ea4ce48159efa9be1d4a5e8bab": "항목이 배열이어야 함: {0}",
|
||||
"f41bd91dc0f000a79c0bf842f1b7fdf9": "JSON 문자열에서 목록을 작성할 수 없음: {0}",
|
||||
"514985b2327f061ffb1c932f6b909979": "{0} 모델이 정의되지 않았습니다.",
|
||||
"cc09e361de7b0f3dc1687515c5713885": "점이 포함된 특성 이름은 지원되지 않습니다. 모델: {0}, 특성: {1}",
|
||||
"da02dd6c53d4148320eeb31718a7aebe": "특성 {0}에 대한 올바르지 않은 유형",
|
||||
"ddf0aa14803f1c84f4a97f3803f7471c": "클래스 이름 필수",
|
||||
"1853f9414bc61ed196952f5c81e41802": "점이 포함된 특성 이름은 지원되지 않습니다. 모델: {0}, 동적 특성: {1}",
|
||||
"bdb11cc1c780c9ccac33c316cfdc9d82": "특성 {0}.{1}에 유형이 정의되지 않음",
|
||||
"cd930369e86cdd222f7bd117c6f9fa94": "알 수 없는 기본값 제공자 {0}",
|
||||
"0c0b867aca0973ba26e887d3337cc4ec": "{{Polymorphic}} 모델을 찾을 수 없음: `{0}`이(가) 설정되지 않음",
|
||||
"2f062cbecdf24245731bddc77714c814": "{1}에 대한 \"{0}\" 관계를 찾을 수 없음",
|
||||
"3cde8cc9bca22c67278b202ab0720106": "{1}에 대해 ID {0}의 인스턴스를 찾을 수 없음",
|
||||
"6502a117987610380b9068ef98b1b0ee": "{0}에서 ({1}.{2} ,{3}.{4})에 대한 레코드를 찾을 수 없음",
|
||||
"6fcc2ff0db7a4f490f5e0ce9e24691f3": "{{HasOne}} 관계에서 둘 이상의 {0} 인스턴스를 작성할 수 없음",
|
||||
"7e9530c0399289be0ee601a604be71ff": "{{BelongsTo}} 관계 {0}이(가) 비어 있음",
|
||||
"7faa840eb6ce11250a141deb42a6c489": "알 수 없는 관계 {{scope}}: {0}",
|
||||
"89afd3a9249f5a8d3edda07d84ca049d": "{{Polymorphic}} 모델을 찾을 수 없음: `{0}`",
|
||||
"a004f310d315e592843776fab964eaeb": "{{Polymorphic}} 관계에는 through 모델이 필요함",
|
||||
"a25e41a39c60c4702e55d0c3936576a1": "키 불일치: {0}.{1}: {2}, {3}.{4}: {5}",
|
||||
"a327355560d495454fba2c1aad6bdf09": "알 수 없는 범위 메소드: {0}",
|
||||
"e08ab0e1ab55f26c357061447b635905": "{0}에서 ({1}.{2} ,{3}.{4})에 대한 관계를 찾을 수 없음",
|
||||
"e55937649d8d7a11706b8cec22d02eae": "{{HasOne}} 관계 {0}이(가) 비어 있음",
|
||||
"2c4904377a87fdab502118719cc0d266": "{{Transaction}}이(가) 지원되지 않음",
|
||||
"ecb7aa804bf54c682999d20d6436104c": "{{transaction}}이(가) 활성 상태가 아님: {0}",
|
||||
"89bf6d92731fe7bd2146ce8d0bec205c": "올바르지 않은 인수가 문자열, {{regex}} 리터럴 또는 {{RegExp}} 오브젝트여야 합니다.",
|
||||
"8c5ab01638c1ac1d58168c6346a8481a": "올바르지 않은 {{regex}} 플래그: {0}",
|
||||
"a6c18a7f4390cd3d59a2a7a047ae2aab": "\"{{npm install loopback-datasource-juggler}} {0}\" 명령 실행",
|
||||
"b138294f132edfe1eb2a8211150c7238": "조회에서 예상치 못한 `undefined` 항목",
|
||||
"8a39126103a157f501affa070367a1b0": "{0} 인스턴스가 올바르지 않습니다. 세부사항: {1}."
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
{
|
||||
"0bd753a8944ad0af85a939bb25273887": "Onbekende sleutel {0} kan niet vervallen",
|
||||
"bec226891a505828bfc76c5cfd73b336": "TTL voor onbekende sleutel {0} kan niet worden opgehaald",
|
||||
"4c78325cedbb826db3a05bf5df0e8546": "U moet een {{id}} opgeven bij een vervanging.",
|
||||
"a0cf0e09c26df14283223e84e6a10f00": "De kenmerken kunnen niet worden bijgewerkt. {{Object}} met {{id}} {0} bestaat niet!",
|
||||
"e54d944c2a2c85a23caa86027ae307cf": "Kan geen modellen migreren die niet zijn gekoppeld aan deze gegevensbron: {0}",
|
||||
"e6161ae8459c79d810e2aa9d21282a39": "U moet een {{id}} opgeven bij het bijwerken van kenmerken.",
|
||||
"fca4d12faff1035d9d0438d73432571b": "Dubbel item voor {0}.{1}",
|
||||
"09483e03b91c8bd58732a74b3ef1ec13": "Ongeldige datum: {0}",
|
||||
"0b16d3ffc42f91b4b9a4b3b50c41c838": "De volgorde {0} is niet geldig",
|
||||
"0e88a84c6bc2638fbcc5d3ea95181f99": "Onbekende eigenschap: {0}",
|
||||
"21095484501dbff31af6556fa6039182": "De {{offset/skip}}-parameter {0} is niet geldig",
|
||||
"416dfbb7b823f51c9f3800be81060b41": "Geen instance met {{id}} {0} gevonden voor {1}",
|
||||
"4e31b1edd10dadb724d83387de0b5062": "De {{limit}}-parameter {0} is niet geldig",
|
||||
"5ec8efeb715a2c34b440f2d76e2cf87d": " {0}",
|
||||
"62a2d80c405b7fec5f547c448ab1b6ff": "De {{order}} {0} heeft een ongeldige richting",
|
||||
"63f503acabdc4c7588aab741b8466862": "De eigenschap {0} heeft een ongeldige clausule {1}",
|
||||
"67c2bf43b5281ab929617423ea8a6f3e": "De connector {0} biedt geen ondersteuning voor de bewerking {{replaceById}}. Dit is geen programmafout in LoopBack. Neem contact op met de auteurs van de connector, bij voorkeur via GitHub-problemen.",
|
||||
"6c3234937d69763fc7f6bcafccc59bbc": "Voor {{Model::deleteById}} is het argument {{id}} vereist",
|
||||
"6eb6fd4fbd73394000bc25f5776fd20c": "Voor {{Model::exists}} is het argument {{id}} vereist",
|
||||
"7bbbdece4eea90e42aa5c0bce295e503": "Voor {{Model::findById}} is het argument {{id}} vereist",
|
||||
"9da58ab4555ac50f4999883de6470d7d": "De operator {0} heeft ongeldige clausules {1}",
|
||||
"a829dee089c912e68c18920ba015400c": "Waarschuwing: Eigenschap {{id}} kan niet worden gewijzigd van {0} in {1} voor model:{2} in operation hook {{'loaded'}}",
|
||||
"a984a076c59e451948b2bcf7a393d860": "Waarschuwing: Eigenschap {{id}} kan niet worden gewijzigd van {0} in {1} voor model:{2} in operation hook {{'before save'}}",
|
||||
"baf2c8b0c5a574b8a894e9b6304fece1": "De WHERE-clausule {0} is geen {{object}}",
|
||||
"db03083e9a768388fdbee865249ac67a": "Validatiefouten in {{updateOrCreate()}} worden genegeerd:",
|
||||
"e4434de4bb8f5a3cd1d416e4d80d7e0b": "Onbekend \"{0}\" {{id}} \"{1}\".",
|
||||
"e54f118a75e15e132f16b985274eb46d": "Het queryfilter {0} is geen {{object}}",
|
||||
"f6e8c96c93b9c7687d6c172b3695e898": "{{id}}-eigenschap ({0}) kan niet worden bijgewerkt van {1} in {2}",
|
||||
"0be2d39d225b1d8b2a0f92ad5c65c9ac": "Geen model opgegeven voor {{polymorphic}} {0}: {1}",
|
||||
"2f4af31c144bbfab1bbf479866acd820": "\nWaarschuwing: {{LoopBack}}-connector \"{0}\" is niet geïnstalleerd als een van de volgende modules:\n\n {1}\n\nU lost dit op door het uitvoeren van:\n\n {{npm install {2} --save}}\n",
|
||||
"6111399276924ffa3bc9a410cdfcb2e5": "Geen {{id}}-naam {0}",
|
||||
"75518263527c423b8a12f908a2730b0f": "{{className}} is verplicht",
|
||||
"791ab3031a73ede03f7d6299a85e8289": "Timeout voor het maken van verbinding na {0} ms",
|
||||
"7b277018e43d41bc445731092b91547d": "Geen verbinding",
|
||||
"a2487abefef4259c2131d96cdb8543b1": "Verbinding mislukt: {0}\nVerbindingspoging wordt herhaald bij volgende opdracht.",
|
||||
"b15b20280211ad258d92947f05b6e4a5": "De connector is niet geïnitialiseerd.",
|
||||
"e0e9504e137a3c3339144b51ed76fef2": "Connector is niet juist gedefinieerd: moet '{{connector}}'-lid van gegevensbron maken",
|
||||
"ec42dca074f1818c447f7ad16e2d01af": "{0} is niet opgegeven door gekoppelde connector",
|
||||
"ba0fd8106eb54de4d003a844206431fd": "Model hook \"{0}\" is gedeprecieerd; gebruik in plaats daarvan operation hooks. {{http://docs.strongloop.com/display/LB/Operation+hooks}}",
|
||||
"280f4550f90e133118955ec6f6f72830": "Discriminatortype {0} opgegeven, maar er bestaat geen model met deze naam",
|
||||
"38dbf42c29a4645238cc3d632e88ebc9": "{{Relation.modelTo}} is niet gedefinieerd voor relatie {0} en is geen {{polymorphic}}",
|
||||
"eb56c2b0c30cf006e2df00a549ec9c2c": "Relatie \"{0}\" is niet gedefinieerd voor model {1}",
|
||||
"938401ea4ce48159efa9be1d4a5e8bab": "Items moeten een array zijn: {0}",
|
||||
"f41bd91dc0f000a79c0bf842f1b7fdf9": "kan geen lijst maken op basis van JSON-reeks: {0}",
|
||||
"514985b2327f061ffb1c932f6b909979": "Model {0} is niet gedefinieerd.",
|
||||
"cc09e361de7b0f3dc1687515c5713885": "Eigenschapnamen met een punt worden niet ondersteund. Model: {0}, eigenschap: {1}",
|
||||
"da02dd6c53d4148320eeb31718a7aebe": "Ongeldig type voor eigenschap {0}",
|
||||
"ddf0aa14803f1c84f4a97f3803f7471c": "Klassennaam vereist",
|
||||
"1853f9414bc61ed196952f5c81e41802": "Eigenschapnamen met een punt worden niet ondersteund. Model: {0}, dynamische eigenschap: {1}",
|
||||
"bdb11cc1c780c9ccac33c316cfdc9d82": "Type niet gedefinieerd voor eigenschap {0}.{1}",
|
||||
"cd930369e86cdd222f7bd117c6f9fa94": "Onbekende standaardwaarde voor provider {0}",
|
||||
"0c0b867aca0973ba26e887d3337cc4ec": "Model {{Polymorphic}} is niet gevonden: '{0}' niet ingesteld",
|
||||
"2f062cbecdf24245731bddc77714c814": "Kan \"{0}\"-relatie voor {1} niet vinden",
|
||||
"3cde8cc9bca22c67278b202ab0720106": "Geen instance met ID {0} gevonden voor {1}",
|
||||
"6502a117987610380b9068ef98b1b0ee": "Geen record gevonden in {0} voor ({1}.{2} ,{3}.{4})",
|
||||
"6fcc2ff0db7a4f490f5e0ce9e24691f3": "{{HasOne}}-relatie kan niet resulteren in meer dan één instance van {0}",
|
||||
"7e9530c0399289be0ee601a604be71ff": "{{BelongsTo}}-relatie {0} is leeg",
|
||||
"7faa840eb6ce11250a141deb42a6c489": "Onbekende relatie {{scope}}: {0}",
|
||||
"89afd3a9249f5a8d3edda07d84ca049d": "{{Polymorphic}}-model is niet gevonden: '{0}'",
|
||||
"a004f310d315e592843776fab964eaeb": "{{Polymorphic}}-relaties hebben een doorvoermodel nodig",
|
||||
"a25e41a39c60c4702e55d0c3936576a1": "Niet-overeenkomende sleutels: {0}.{1}: {2}, {3}.{4}: {5}",
|
||||
"a327355560d495454fba2c1aad6bdf09": "Onbekende methode voor bereik: {0}",
|
||||
"e08ab0e1ab55f26c357061447b635905": "Geen relatie gevonden in {0} voor ({1}.{2},{3}.{4})",
|
||||
"e55937649d8d7a11706b8cec22d02eae": "{{HasOne}}-relatie {0} is leeg",
|
||||
"2c4904377a87fdab502118719cc0d266": "{{Transaction}} wordt niet ondersteund",
|
||||
"ecb7aa804bf54c682999d20d6436104c": "De {{transaction}} is niet actief: {0}",
|
||||
"89bf6d92731fe7bd2146ce8d0bec205c": "Ongeldig argument, moet een tekenreeks, {{regex}}-literaal of {{RegExp}}-object zijn",
|
||||
"8c5ab01638c1ac1d58168c6346a8481a": "Ongeldige {{regex}}-vlaggen: {0}",
|
||||
"a6c18a7f4390cd3d59a2a7a047ae2aab": "Voer de opdracht \"{{npm install loopback-datasource-juggler}} {0}\" uit",
|
||||
"b138294f132edfe1eb2a8211150c7238": "Onverwacht item 'undefined' in query",
|
||||
"8a39126103a157f501affa070367a1b0": "De instance {0} is niet geldig. Details: {1}."
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
{
|
||||
"0bd753a8944ad0af85a939bb25273887": "Não é possível expirar chave desconhecida {0}",
|
||||
"bec226891a505828bfc76c5cfd73b336": "Não é possível obter TTL para chave desconhecida {0}",
|
||||
"4c78325cedbb826db3a05bf5df0e8546": "Deve-se fornecer um {{id}} ao substituir!",
|
||||
"a0cf0e09c26df14283223e84e6a10f00": "Não foi possível atualizar atributos. {{Object}} com {{id}} {0} não existe!",
|
||||
"e54d944c2a2c85a23caa86027ae307cf": "Não é possível migrar modelos não conectados a esta origem de dados: {0}",
|
||||
"e6161ae8459c79d810e2aa9d21282a39": "Deve-se fornecer um {{id}} ao atualizar atributos!",
|
||||
"fca4d12faff1035d9d0438d73432571b": "Entrada duplicada para {0}.{1}",
|
||||
"09483e03b91c8bd58732a74b3ef1ec13": "Data inválida: {0}",
|
||||
"0b16d3ffc42f91b4b9a4b3b50c41c838": "A ordem {0} não é válida",
|
||||
"0e88a84c6bc2638fbcc5d3ea95181f99": "Propriedade desconhecida: {0}",
|
||||
"21095484501dbff31af6556fa6039182": "O parâmetro {{offset/skip}} {0} não é válido",
|
||||
"416dfbb7b823f51c9f3800be81060b41": "Nenhuma instância com {{id}} {0} localizada para {1}",
|
||||
"4e31b1edd10dadb724d83387de0b5062": "O parâmetro {0} de {{limit}} não é válido",
|
||||
"5ec8efeb715a2c34b440f2d76e2cf87d": " {0}",
|
||||
"62a2d80c405b7fec5f547c448ab1b6ff": "A {{order}} {0} possui direção inválida",
|
||||
"63f503acabdc4c7588aab741b8466862": "A propriedade {0} possui cláusula inválida {1}",
|
||||
"67c2bf43b5281ab929617423ea8a6f3e": "O conector {0} não suporta operação {{replaceById}}. Este não é um erro no LoopBack. Entre em contato com os autores do conector, de preferência via problemas do GitHub.",
|
||||
"6c3234937d69763fc7f6bcafccc59bbc": "{{Model::deleteById}} requer o argumento {{id}}",
|
||||
"6eb6fd4fbd73394000bc25f5776fd20c": "{{Model::exists}} requer o argumento {{id}}",
|
||||
"7bbbdece4eea90e42aa5c0bce295e503": "{{Model::findById}} requer o argumento {{id}}",
|
||||
"9da58ab4555ac50f4999883de6470d7d": "O operador {0} possui cláusulas {1} inválidas",
|
||||
"a829dee089c912e68c18920ba015400c": "AVISO: a propriedade {{id}} não pode ser mudada de {0} para {1} para o modelo:{2} no gancho de operação {{'loaded'}}",
|
||||
"a984a076c59e451948b2bcf7a393d860": "AVISO: a propriedade {{id}} não pode ser mudada de {0} para {1} para o modelo:{2} no gancho de operação {{'before save'}}",
|
||||
"baf2c8b0c5a574b8a894e9b6304fece1": "A cláusula where {0} não é um {{object}}",
|
||||
"db03083e9a768388fdbee865249ac67a": "Ignorando erros de validação em {{updateOrCreate()}}:",
|
||||
"e4434de4bb8f5a3cd1d416e4d80d7e0b": "\"{0}\" {{id}} \"{1}\" desconhecido.",
|
||||
"e54f118a75e15e132f16b985274eb46d": "O filtro de consulta {0} não é um {{object}}",
|
||||
"f6e8c96c93b9c7687d6c172b3695e898": "A propriedade de {{id}} ({0}) não pode ser atualizada de {1} para {2}",
|
||||
"0be2d39d225b1d8b2a0f92ad5c65c9ac": "Nenhum modelo especificado para {{polymorphic}} {0}: {1}",
|
||||
"2f4af31c144bbfab1bbf479866acd820": "\nAVISO: conector {{LoopBack}} \"{0}\" não foi instalado como qualquer um dos módulos a seguir:\n\n {1}\n\nPara corrigir, execute:\n\n {{npm install {2} --save}}\n",
|
||||
"6111399276924ffa3bc9a410cdfcb2e5": "Nenhum nome de {{id}} {0}",
|
||||
"75518263527c423b8a12f908a2730b0f": "{{className}} é obrigatório",
|
||||
"791ab3031a73ede03f7d6299a85e8289": "Tempo limite na conexão após {0} ms",
|
||||
"7b277018e43d41bc445731092b91547d": "Não está conectado",
|
||||
"a2487abefef4259c2131d96cdb8543b1": "Falha de conexão: {0}\nEla será tentada novamente para a próxima solicitação.",
|
||||
"b15b20280211ad258d92947f05b6e4a5": "O conector não foi inicializado.",
|
||||
"e0e9504e137a3c3339144b51ed76fef2": "O conector não foi definido corretamente: ele deve criar um membro de `{{connector}}` igual a dataSource",
|
||||
"ec42dca074f1818c447f7ad16e2d01af": "{0} não é fornecido pelo conector conectado",
|
||||
"ba0fd8106eb54de4d003a844206431fd": "O gancho de modelo \"{0}\" está descontinuado, use ganchos de Operação no lugar. {{http://docs.strongloop.com/display/LB/Operation+hooks}}",
|
||||
"280f4550f90e133118955ec6f6f72830": "Tipo de discriminador {0} especificado, mas não existe nenhum modelo com esse nome",
|
||||
"38dbf42c29a4645238cc3d632e88ebc9": "{{Relation.modelTo}} não foi definido para a relação {0} e não é {{polymorphic}}",
|
||||
"eb56c2b0c30cf006e2df00a549ec9c2c": "A relação \"{0}\" não foi definida para o modelo {1}",
|
||||
"938401ea4ce48159efa9be1d4a5e8bab": "Itens devem ser uma matriz: {0}",
|
||||
"f41bd91dc0f000a79c0bf842f1b7fdf9": "não foi possível criar Lista a partir da sequência JSON: {0}",
|
||||
"514985b2327f061ffb1c932f6b909979": "O modelo {0} não está definido.",
|
||||
"cc09e361de7b0f3dc1687515c5713885": "Os nomes da propriedade contendo um ponto não são suportados. Modelo: {0}, propriedade: {1}",
|
||||
"da02dd6c53d4148320eeb31718a7aebe": "Tipo inválido para a propriedade {0}",
|
||||
"ddf0aa14803f1c84f4a97f3803f7471c": "Nome de classe necessário",
|
||||
"1853f9414bc61ed196952f5c81e41802": "Os nomes da propriedade contendo um ponto não são suportados. Modelo: {0}, propriedade dinâmica: {1}",
|
||||
"bdb11cc1c780c9ccac33c316cfdc9d82": "Tipo não definido para a propriedade {0}.{1}",
|
||||
"cd930369e86cdd222f7bd117c6f9fa94": "Provedor do valor padrão {0} desconhecido",
|
||||
"0c0b867aca0973ba26e887d3337cc4ec": "Modelo de {{Polymorphic}} não localizado: `{0}` não configurado",
|
||||
"2f062cbecdf24245731bddc77714c814": "Não foi possível localizar relação de \"{0}\" para {1}",
|
||||
"3cde8cc9bca22c67278b202ab0720106": "Nenhuma instância com ID {0} localizada para {1}",
|
||||
"6502a117987610380b9068ef98b1b0ee": "Nenhum registro localizado em {0} para ({1}.{2} ,{3}.{4})",
|
||||
"6fcc2ff0db7a4f490f5e0ce9e24691f3": "A relação {{HasOne}} não pode criar mais de uma instância de {0}",
|
||||
"7e9530c0399289be0ee601a604be71ff": "Relação {{BelongsTo}} {0} está vazia",
|
||||
"7faa840eb6ce11250a141deb42a6c489": "{{scope}} da relação desconhecido: {0}",
|
||||
"89afd3a9249f5a8d3edda07d84ca049d": "Modelo de {{Polymorphic}} não localizado: `{0}`",
|
||||
"a004f310d315e592843776fab964eaeb": "Relações de {{Polymorphic}} precisam de um modelo completo",
|
||||
"a25e41a39c60c4702e55d0c3936576a1": "Incompatibilidade de chave: {0}.{1}: {2}, {3}.{4}: {5}",
|
||||
"a327355560d495454fba2c1aad6bdf09": "Método de escopo desconhecido: {0}",
|
||||
"e08ab0e1ab55f26c357061447b635905": "Nenhuma relação localizada em {0} para ({1}.{2},{3}.{4})",
|
||||
"e55937649d8d7a11706b8cec22d02eae": "Relação {{HasOne}} {0} está vazia",
|
||||
"2c4904377a87fdab502118719cc0d266": "{{Transaction}} não é suportada",
|
||||
"ecb7aa804bf54c682999d20d6436104c": "A {{transaction}} não está ativa: {0}",
|
||||
"89bf6d92731fe7bd2146ce8d0bec205c": "Argumento inválido, deve ser uma sequência, literal {{regex}} ou objeto {{RegExp}}",
|
||||
"8c5ab01638c1ac1d58168c6346a8481a": "Sinalizações de {{regex}} inválidas: {0}",
|
||||
"a6c18a7f4390cd3d59a2a7a047ae2aab": "Execute o comando \"{{npm install loopback-datasource-juggler}} {0}\" ",
|
||||
"b138294f132edfe1eb2a8211150c7238": "`Indefinido` inesperado na consulta",
|
||||
"8a39126103a157f501affa070367a1b0": "A instância de {0} não é válida. Detalhes: {1}."
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
{
|
||||
"0bd753a8944ad0af85a939bb25273887": "Bilinmeyen {0} anahtarı süre bitimine uğratılamaz",
|
||||
"bec226891a505828bfc76c5cfd73b336": "Bilinmeyen {0} anahtarı için TTL alınamıyor",
|
||||
"4c78325cedbb826db3a05bf5df0e8546": "Değiştirirken bir {{id}} belirtmelisiniz!",
|
||||
"a0cf0e09c26df14283223e84e6a10f00": "Öznitelikler güncellenemedi. Tanıtıcısı {{id}} olan {0} {{Object}} nesnesi yok!",
|
||||
"e54d944c2a2c85a23caa86027ae307cf": "Bu veri kaynağına eklenmemiş modeller geçirilemez: {0}",
|
||||
"e6161ae8459c79d810e2aa9d21282a39": "Öznitelikleri güncellerken bir {{id}} belirtmelisiniz!",
|
||||
"fca4d12faff1035d9d0438d73432571b": "Bu öğeyle ilgili yinelenen giriş: {0}.{1}",
|
||||
"09483e03b91c8bd58732a74b3ef1ec13": "Geçersiz tarih: {0}",
|
||||
"0b16d3ffc42f91b4b9a4b3b50c41c838": "{0} sırası geçerli değil",
|
||||
"0e88a84c6bc2638fbcc5d3ea95181f99": "Bilinmeyen özellik: {0}",
|
||||
"21095484501dbff31af6556fa6039182": "{{offset/skip}} parametresi {0} geçerli değil",
|
||||
"416dfbb7b823f51c9f3800be81060b41": "{1} için {{id}} {0} tanıtıcılı bir eşgörünüm bulunamadı",
|
||||
"4e31b1edd10dadb724d83387de0b5062": "{{limit}} parametresi {0} geçerli değil",
|
||||
"5ec8efeb715a2c34b440f2d76e2cf87d": " {0}",
|
||||
"62a2d80c405b7fec5f547c448ab1b6ff": "{{order}} {0} sırasının yönü geçersiz",
|
||||
"63f503acabdc4c7588aab741b8466862": "{0} özelliğinde geçersiz {1} yantümcesi var",
|
||||
"67c2bf43b5281ab929617423ea8a6f3e": "{0} bağlayıcısı {{replaceById}} işlemini desteklemiyor. Bu LoopBack'deki bir hata değil. Lütfen, mümkünse GitHub sorunlarıyla birlikte, bağlayıcının yazarlarına başvurun.",
|
||||
"6c3234937d69763fc7f6bcafccc59bbc": "{{Model::deleteById}}, {{id}} bağımsız değişkenini gerektirir",
|
||||
"6eb6fd4fbd73394000bc25f5776fd20c": "{{Model::exists}}, {{id}} bağımsız değişkenini gerektirir",
|
||||
"7bbbdece4eea90e42aa5c0bce295e503": "{{Model::findById}}, {{id}} bağımsız değişkenini gerektirir",
|
||||
"9da58ab4555ac50f4999883de6470d7d": "{0} işlecinde geçersiz {1} yantümceleri var",
|
||||
"a829dee089c912e68c18920ba015400c": "UYARI: {{id}} özelliği, {{'loaded'}} işlem çengelinde {2} modeli için {0} değerinden {1} değerine çevrilemiyor",
|
||||
"a984a076c59e451948b2bcf7a393d860": "UYARI: {{id}} özelliği, {{'before save'}} işlem çengelinde {2} modeli için {0} değerinden {1} değerine çevrilemiyor",
|
||||
"baf2c8b0c5a574b8a894e9b6304fece1": "Where yantümcesi {0} bir {{object}} değil",
|
||||
"db03083e9a768388fdbee865249ac67a": "{{updateOrCreate()}} işlemindeki doğrulama hataları yoksayılıyor:",
|
||||
"e4434de4bb8f5a3cd1d416e4d80d7e0b": "Bilinmeyen \"{0}\" {{id}} \"{1}\".",
|
||||
"e54f118a75e15e132f16b985274eb46d": "Sorgu süzgeci {0} bir {{object}} değil",
|
||||
"f6e8c96c93b9c7687d6c172b3695e898": "{{id}} özelliği ({0}), {1} değerinden {2} değerine güncellenemiyor",
|
||||
"0be2d39d225b1d8b2a0f92ad5c65c9ac": "{{polymorphic}} {0} için model belirtilmedi: {1}",
|
||||
"2f4af31c144bbfab1bbf479866acd820": "\nUYARI: {{LoopBack}} bağlayıcısı \"{0}\" şu modüllerden biri olarak kurulmadı:\n\n {1}\n\nDüzeltmek için şu komutu çalıştırın:\n\n {{npm install {2} --save}}\n",
|
||||
"6111399276924ffa3bc9a410cdfcb2e5": "{{id}} adı {0} yok",
|
||||
"75518263527c423b8a12f908a2730b0f": "{{className}} zorunludur",
|
||||
"791ab3031a73ede03f7d6299a85e8289": "{0} milisaniyeden sonra bağlantıda zaman aşımı oluştu",
|
||||
"7b277018e43d41bc445731092b91547d": "Bağlı değil",
|
||||
"a2487abefef4259c2131d96cdb8543b1": "Bağlantı başarısız oldu: {0}\nSonraki istek için yeniden denenecek.",
|
||||
"b15b20280211ad258d92947f05b6e4a5": "Bağlayıcı başlatılmamış.",
|
||||
"e0e9504e137a3c3339144b51ed76fef2": "Bağlayıcı doğru tanımlanmadı: Veri kaynağının `{{connector}}` üyesini yaratmalıdır",
|
||||
"ec42dca074f1818c447f7ad16e2d01af": "Eklenen bağlayıcı tarafından {0} sağlanmadı",
|
||||
"ba0fd8106eb54de4d003a844206431fd": "\"{0}\" model çengeli kullanım dışı bırakıldı, onun yerine işlem çengellerini kullanın. {{http://docs.strongloop.com/display/LB/Operation+hooks}}",
|
||||
"280f4550f90e133118955ec6f6f72830": "{0} ayrımsayıcı tipi belirtildi, ancak bu adı taşıyan bir model yok",
|
||||
"38dbf42c29a4645238cc3d632e88ebc9": "{{Relation.modelTo}}, {0} ilişkisi için tanımlanmadı ve {{polymorphic}} değil",
|
||||
"eb56c2b0c30cf006e2df00a549ec9c2c": "{1} modeli için \"{0}\" ilişkisi tanımlanmadı",
|
||||
"938401ea4ce48159efa9be1d4a5e8bab": "Öğeler bir dizi olmalıdır: {0}",
|
||||
"f41bd91dc0f000a79c0bf842f1b7fdf9": "JSON dizgisinden liste yaratılamadı: {0}",
|
||||
"514985b2327f061ffb1c932f6b909979": "{0} modeli tanımlanmadı",
|
||||
"cc09e361de7b0f3dc1687515c5713885": "Nokta içeren özellik adları desteklenmez. Model: {0}, özellik: {1}",
|
||||
"da02dd6c53d4148320eeb31718a7aebe": "{0} özelliği için geçersiz tip",
|
||||
"ddf0aa14803f1c84f4a97f3803f7471c": "Sınıf adı zorunludur",
|
||||
"1853f9414bc61ed196952f5c81e41802": "Nokta içeren özellik adları desteklenmez. Model: {0}, dinamik özellik: {1}",
|
||||
"bdb11cc1c780c9ccac33c316cfdc9d82": "Bu özellik için tip tanımlanmadı: {0}.{1}",
|
||||
"cd930369e86cdd222f7bd117c6f9fa94": "Bilinmeyen varsayılan değer sağlayıcısı {0}",
|
||||
"0c0b867aca0973ba26e887d3337cc4ec": "{{Polymorphic}} model bulunamadı: `{0}` ayarlı değil",
|
||||
"2f062cbecdf24245731bddc77714c814": "{1} için \"{0}\" bulunamadı",
|
||||
"3cde8cc9bca22c67278b202ab0720106": "{1} için {0} tanıtıcılı bir eşgörünüm bulunamadı",
|
||||
"6502a117987610380b9068ef98b1b0ee": "{0} içinde şu öğe için kayıt bulunamadı: ({1}.{2} ,{3}.{4})",
|
||||
"6fcc2ff0db7a4f490f5e0ce9e24691f3": "{{HasOne}} ilişkisi birden çok {0} eşgörünümü yaratamaz",
|
||||
"7e9530c0399289be0ee601a604be71ff": "{{BelongsTo}} ilişkisi {0} boş",
|
||||
"7faa840eb6ce11250a141deb42a6c489": "Bilinmeyen ilişki {{scope}}: {0}",
|
||||
"89afd3a9249f5a8d3edda07d84ca049d": "{{Polymorphic}} model bulunamadı: `{0}`",
|
||||
"a004f310d315e592843776fab964eaeb": "{{Polymorphic}} ilişkileri için aracı model gerekir",
|
||||
"a25e41a39c60c4702e55d0c3936576a1": "Anahtar uyuşmazlığı: {0}.{1}: {2}, {3}.{4}: {5}",
|
||||
"a327355560d495454fba2c1aad6bdf09": "Bilinmeyen kapsam yöntemi: {0}",
|
||||
"e08ab0e1ab55f26c357061447b635905": "{0} içinde şu öğe için ilişki bulunamadı: ({1}.{2},{3}.{4})",
|
||||
"e55937649d8d7a11706b8cec22d02eae": "{{HasOne}} ilişkisi {0} boş",
|
||||
"2c4904377a87fdab502118719cc0d266": "{{Transaction}} desteklenmiyor",
|
||||
"ecb7aa804bf54c682999d20d6436104c": "{{transaction}} etkin değil: {0}",
|
||||
"89bf6d92731fe7bd2146ce8d0bec205c": "Bağımsız değişken geçersiz; bir dizgi, {{regex}} hazır bilgisi ya da {{RegExp}} nesnesi olmalıdır",
|
||||
"8c5ab01638c1ac1d58168c6346a8481a": "Geçersiz {{regex}} işaretleri: {0}",
|
||||
"a6c18a7f4390cd3d59a2a7a047ae2aab": "\"{{npm install loopback-datasource-juggler}} {0}\" komutunu çalıştırın ",
|
||||
"b138294f132edfe1eb2a8211150c7238": "Sorguda beklenmeyen `undefined`",
|
||||
"8a39126103a157f501affa070367a1b0": "{0} eşgörünümü geçerli değil. Ayrıntılar: {1}."
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
{
|
||||
"0bd753a8944ad0af85a939bb25273887": "无法使未知键 {0} 到期",
|
||||
"bec226891a505828bfc76c5cfd73b336": "无法获取未知键 {0} 的 TTL",
|
||||
"4c78325cedbb826db3a05bf5df0e8546": "在替换时必须提供 {{id}}!",
|
||||
"a0cf0e09c26df14283223e84e6a10f00": "无法更新属性。包含 {{id}} {0} 的 {{Object}} 不存在!",
|
||||
"e54d944c2a2c85a23caa86027ae307cf": "无法迁移未附加到此数据源的模型:{0}",
|
||||
"e6161ae8459c79d810e2aa9d21282a39": "在更新属性时必须提供 {{id}}!",
|
||||
"fca4d12faff1035d9d0438d73432571b": "{0} 的重复条目。{1}",
|
||||
"09483e03b91c8bd58732a74b3ef1ec13": "无效日期:{0}",
|
||||
"0b16d3ffc42f91b4b9a4b3b50c41c838": "顺序 {0} 无效",
|
||||
"0e88a84c6bc2638fbcc5d3ea95181f99": "未知的属性:{0}",
|
||||
"21095484501dbff31af6556fa6039182": "{{offset/skip}} 参数 {0} 无效",
|
||||
"416dfbb7b823f51c9f3800be81060b41": "对于 {1},找不到具有 {{id}} {0} 的实例",
|
||||
"4e31b1edd10dadb724d83387de0b5062": "{{limit}} 参数 {0} 无效",
|
||||
"5ec8efeb715a2c34b440f2d76e2cf87d": " {0}",
|
||||
"62a2d80c405b7fec5f547c448ab1b6ff": "{{order}} {0} 具有无效的方向",
|
||||
"63f503acabdc4c7588aab741b8466862": "{0} 属性具有无效的子句 {1}",
|
||||
"67c2bf43b5281ab929617423ea8a6f3e": "连接器 {0} 不支持 {{replaceById}} 操作。这不是 LoopBack 中的错误。请联系连接器的作者,首选通过 GitHub 提交问题。",
|
||||
"6c3234937d69763fc7f6bcafccc59bbc": "{{Model::deleteById}} 需要 {{id}} 自变量",
|
||||
"6eb6fd4fbd73394000bc25f5776fd20c": "{{Model::exists}} 需要 {{id}} 自变量",
|
||||
"7bbbdece4eea90e42aa5c0bce295e503": "{{Model::findById}} 需要 {{id}} 自变量",
|
||||
"9da58ab4555ac50f4999883de6470d7d": "{0} 运算符具有无效的子句 {1}",
|
||||
"a829dee089c912e68c18920ba015400c": "警告:对于以下模型,{{id}} 属性无法从 {0} 更改为 {1}:{{'loaded'}} 操作挂钩中的 {2}",
|
||||
"a984a076c59e451948b2bcf7a393d860": "警告:对于以下模型,{{id}} 属性无法从 {0} 更改为 {1}:{{'before save'}} 操作挂钩中的 {2}",
|
||||
"baf2c8b0c5a574b8a894e9b6304fece1": "Where 子句 {0} 不是 {{object}}",
|
||||
"db03083e9a768388fdbee865249ac67a": "正在忽略 {{updateOrCreate()}} 中的验证错误:",
|
||||
"e4434de4bb8f5a3cd1d416e4d80d7e0b": "未知的“{0}”{{id}}“{1}”。",
|
||||
"e54f118a75e15e132f16b985274eb46d": "查询过滤器 {0} 不是 {{object}}",
|
||||
"f6e8c96c93b9c7687d6c172b3695e898": "{{id}} 属性 ({0}) 无法从 {1} 更新为 {2}",
|
||||
"0be2d39d225b1d8b2a0f92ad5c65c9ac": "未针对 {{polymorphic}} {0} 指定模型:{1}",
|
||||
"2f4af31c144bbfab1bbf479866acd820": "\n警告:未作为以下任何模块安装 {{LoopBack}} 连接器“{0}”\n\n {1}\n\n要修正,请运行:\n\n {{npm install {2} --save}}\n",
|
||||
"6111399276924ffa3bc9a410cdfcb2e5": "无 {{id}} 名称 {0}",
|
||||
"75518263527c423b8a12f908a2730b0f": "{{className}} 是必需的",
|
||||
"791ab3031a73ede03f7d6299a85e8289": "在 {0} 毫秒后连接超时",
|
||||
"7b277018e43d41bc445731092b91547d": "未连接",
|
||||
"a2487abefef4259c2131d96cdb8543b1": "连接失败:{0}\n将在下一次请求时重试。",
|
||||
"b15b20280211ad258d92947f05b6e4a5": "连接器尚未进行初始化。",
|
||||
"e0e9504e137a3c3339144b51ed76fef2": "连接器定义不正确:应创建 dataSource 的“{{connector}}”成员",
|
||||
"ec42dca074f1818c447f7ad16e2d01af": "连接的连接器未提供 {0}",
|
||||
"ba0fd8106eb54de4d003a844206431fd": "不推荐使用模型挂钩“{0}”,请改用操作挂钩。{{http://docs.strongloop.com/display/LB/Operation+hooks}}",
|
||||
"280f4550f90e133118955ec6f6f72830": "已指定鉴别器类型 {0},但是不存在具有此类名称的模型",
|
||||
"38dbf42c29a4645238cc3d632e88ebc9": "未针对关系 {0} 定义 {{Relation.modelTo}},并且不是 {{polymorphic}}",
|
||||
"eb56c2b0c30cf006e2df00a549ec9c2c": "未针对 {1} 模型定义关系“{0}”",
|
||||
"938401ea4ce48159efa9be1d4a5e8bab": "项必须是数组:{0}",
|
||||
"f41bd91dc0f000a79c0bf842f1b7fdf9": "无法从 JSON 字符串创建列表:{0}",
|
||||
"514985b2327f061ffb1c932f6b909979": "未定义模型 {0}。",
|
||||
"cc09e361de7b0f3dc1687515c5713885": "不支持包含点的属性名称。模型:{0},属性:{1}",
|
||||
"da02dd6c53d4148320eeb31718a7aebe": "属性 {0} 的类型无效",
|
||||
"ddf0aa14803f1c84f4a97f3803f7471c": "类名是必需的",
|
||||
"1853f9414bc61ed196952f5c81e41802": "不支持包含点的属性名称。模型:{0},动态属性:{1}",
|
||||
"bdb11cc1c780c9ccac33c316cfdc9d82": "未针对属性 {0} 定义类型。{1}",
|
||||
"cd930369e86cdd222f7bd117c6f9fa94": "未知的缺省值提供程序 {0}",
|
||||
"0c0b867aca0973ba26e887d3337cc4ec": "找不到 {{Polymorphic}} 模型:未设置“{0}”",
|
||||
"2f062cbecdf24245731bddc77714c814": "无法找到 {1} 的“{0}”关系",
|
||||
"3cde8cc9bca22c67278b202ab0720106": "对于 {1},找不到具有标识 {0} 的实例",
|
||||
"6502a117987610380b9068ef98b1b0ee": "在 {0} 中找不到以下项的记录:({1}. {2},{3}.{4})",
|
||||
"6fcc2ff0db7a4f490f5e0ce9e24691f3": "{{HasOne}} 关系无法创建 {0} 的多个实例",
|
||||
"7e9530c0399289be0ee601a604be71ff": "{{BelongsTo}} 关系 {0} 为空",
|
||||
"7faa840eb6ce11250a141deb42a6c489": "未知的关系 {{scope}}:{0}",
|
||||
"89afd3a9249f5a8d3edda07d84ca049d": "找不到 {{Polymorphic}} 模型:“{0}”",
|
||||
"a004f310d315e592843776fab964eaeb": "{{Polymorphic}} 关系需要直通模型",
|
||||
"a25e41a39c60c4702e55d0c3936576a1": "键不匹配:{0}.{1}:{2},{3}.{4}:{5}",
|
||||
"a327355560d495454fba2c1aad6bdf09": "未知的作用域方法:{0}",
|
||||
"e08ab0e1ab55f26c357061447b635905": "在 {0} 中找不到以下项的关系:({1}. {2},{3}.{4})",
|
||||
"e55937649d8d7a11706b8cec22d02eae": "{{HasOne}} 关系 {0} 为空",
|
||||
"2c4904377a87fdab502118719cc0d266": "不支持 {{Transaction}}",
|
||||
"ecb7aa804bf54c682999d20d6436104c": "{{transaction}} 不活动:{0}",
|
||||
"89bf6d92731fe7bd2146ce8d0bec205c": "无效的自变量,必须是字符串、{{regex}} 字面值或 {{RegExp}} 对象",
|
||||
"8c5ab01638c1ac1d58168c6346a8481a": "无效的 {{regex}} 标志:{0}",
|
||||
"a6c18a7f4390cd3d59a2a7a047ae2aab": "运行“{{npm install loopback-datasource-juggler}} {0}”命令",
|
||||
"b138294f132edfe1eb2a8211150c7238": "查询中存在意外的“未定义”",
|
||||
"8a39126103a157f501affa070367a1b0": "{0} 实例无效。详细信息:{1}。"
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
{
|
||||
"0bd753a8944ad0af85a939bb25273887": "無法使不明索引鍵 {0} 到期",
|
||||
"bec226891a505828bfc76c5cfd73b336": "無法取得不明索引鍵 {0} 的 TTL",
|
||||
"4c78325cedbb826db3a05bf5df0e8546": "更換時必須提供 {{id}}!",
|
||||
"a0cf0e09c26df14283223e84e6a10f00": "無法更新屬性。{{id}} 為 {0} 的 {{Object}} 不存在!",
|
||||
"e54d944c2a2c85a23caa86027ae307cf": "無法移轉未連接至這個資料來源的模型:{0}",
|
||||
"e6161ae8459c79d810e2aa9d21282a39": "更新屬性時必須提供 {{id}}!",
|
||||
"fca4d12faff1035d9d0438d73432571b": "{0}.{1} 的項目重複",
|
||||
"09483e03b91c8bd58732a74b3ef1ec13": "無效日期:{0}",
|
||||
"0b16d3ffc42f91b4b9a4b3b50c41c838": "順序 {0} 無效",
|
||||
"0e88a84c6bc2638fbcc5d3ea95181f99": "不明內容:{0}",
|
||||
"21095484501dbff31af6556fa6039182": "{{offset/skip}} 參數 {0} 無效",
|
||||
"416dfbb7b823f51c9f3800be81060b41": "對於 {1},找不到 {{id}} 為 {0} 的實例",
|
||||
"4e31b1edd10dadb724d83387de0b5062": "{{limit}} 參數 {0} 無效",
|
||||
"5ec8efeb715a2c34b440f2d76e2cf87d": " {0}",
|
||||
"62a2d80c405b7fec5f547c448ab1b6ff": "{{order}} {0} 的方向無效",
|
||||
"63f503acabdc4c7588aab741b8466862": "{0} 內容的子句 {1} 無效",
|
||||
"67c2bf43b5281ab929617423ea8a6f3e": "連接器 {0} 不支援 {{replaceById}} 作業。這不是 LoopBack 的錯誤。請聯絡連接器的作者,建議透過 GitHub 議題。",
|
||||
"6c3234937d69763fc7f6bcafccc59bbc": "{{Model::deleteById}} 需要 {{id}} 引數",
|
||||
"6eb6fd4fbd73394000bc25f5776fd20c": "{{Model::exists}} 需要 {{id}} 引數",
|
||||
"7bbbdece4eea90e42aa5c0bce295e503": "{{Model::findById}} 需要 {{id}} 引數",
|
||||
"9da58ab4555ac50f4999883de6470d7d": "{0} 運算子的子句 {1} 無效",
|
||||
"a829dee089c912e68c18920ba015400c": "警告:在 {{'loaded'}} 作業連結鉤中,無法將 model:{2} 的 {{id}} 內容從 {0} 變更為 {1}",
|
||||
"a984a076c59e451948b2bcf7a393d860": "警告:在 {{'before save'}} 作業連結鉤中,無法將 model:{2} 的 {{id}} 內容從 {0} 變更為 {1}",
|
||||
"baf2c8b0c5a574b8a894e9b6304fece1": "where 子句 {0} 不是 {{object}}",
|
||||
"db03083e9a768388fdbee865249ac67a": "忽略 {{updateOrCreate()}} 中的驗證錯誤:",
|
||||
"e4434de4bb8f5a3cd1d416e4d80d7e0b": "\"{0}\" {{id}} \"{1}\" 不明。",
|
||||
"e54f118a75e15e132f16b985274eb46d": "查詢過濾器 {0} 不是 {{object}}",
|
||||
"f6e8c96c93b9c7687d6c172b3695e898": "無法將 {{id}} 內容 ({0}) 從 {1} 更新為 {2}",
|
||||
"0be2d39d225b1d8b2a0f92ad5c65c9ac": "未指定 {{polymorphic}} {0} 的模型:{1}",
|
||||
"2f4af31c144bbfab1bbf479866acd820": "\n警告:{{LoopBack}} 連接器 \"{0}\" 未安裝為下列任一模組:\n\n {1}\n\n若要修正,請執行:\n\n {{npm install {2} --save}}\n",
|
||||
"6111399276924ffa3bc9a410cdfcb2e5": "沒有 {{id}} 名稱 {0}",
|
||||
"75518263527c423b8a12f908a2730b0f": "需要 {{className}}",
|
||||
"791ab3031a73ede03f7d6299a85e8289": "連接 {0} 毫秒之後逾時",
|
||||
"7b277018e43d41bc445731092b91547d": "未連接",
|
||||
"a2487abefef4259c2131d96cdb8543b1": "連線失敗:{0}\n將在下一次要求時重試。",
|
||||
"b15b20280211ad258d92947f05b6e4a5": "尚未起始設定連接器。",
|
||||
"e0e9504e137a3c3339144b51ed76fef2": "未正確定義連接器:應該建立資料來源的 `{{connector}}` 成員",
|
||||
"ec42dca074f1818c447f7ad16e2d01af": "連接的連接器未提供 {0}",
|
||||
"ba0fd8106eb54de4d003a844206431fd": "模型連結鉤 \"{0}\" 已淘汰,請改用作業連結鉤。{{http://docs.strongloop.com/display/LB/Operation+hooks}}",
|
||||
"280f4550f90e133118955ec6f6f72830": "已指定鑑別器類型 {0},但不存在此名稱的模型",
|
||||
"38dbf42c29a4645238cc3d632e88ebc9": "{{Relation.modelTo}} 未定義給關係 {0},而且不是 {{polymorphic}}",
|
||||
"eb56c2b0c30cf006e2df00a549ec9c2c": "未定義 {1} 模型的關係 \"{0}\"",
|
||||
"938401ea4ce48159efa9be1d4a5e8bab": "Items 必須是陣列:{0}",
|
||||
"f41bd91dc0f000a79c0bf842f1b7fdf9": "無法從 JSON 字串建立 List:{0}",
|
||||
"514985b2327f061ffb1c932f6b909979": "模型 {0} 未定義。",
|
||||
"cc09e361de7b0f3dc1687515c5713885": "不支援含有點的內容名稱。模型:{0},內容:{1}",
|
||||
"da02dd6c53d4148320eeb31718a7aebe": "內容 {0} 的類型無效",
|
||||
"ddf0aa14803f1c84f4a97f3803f7471c": "需要類別名稱",
|
||||
"1853f9414bc61ed196952f5c81e41802": "不支援含有點的內容名稱。模型:{0},動態內容:{1}",
|
||||
"bdb11cc1c780c9ccac33c316cfdc9d82": "未定義內容 {0}.{1} 的類型",
|
||||
"cd930369e86cdd222f7bd117c6f9fa94": "預設值提供者 {0} 不明",
|
||||
"0c0b867aca0973ba26e887d3337cc4ec": "找不到 {{Polymorphic}} 模型:`{0}` 未設定",
|
||||
"2f062cbecdf24245731bddc77714c814": "找不到 {1} 的 \"{0}\" 關係",
|
||||
"3cde8cc9bca22c67278b202ab0720106": "對於 {1},找不到 id 為 {0} 的實例",
|
||||
"6502a117987610380b9068ef98b1b0ee": "在 {0} 中找不到 ({1}.{2} ,{3}.{4}) 的記錄",
|
||||
"6fcc2ff0db7a4f490f5e0ce9e24691f3": "{{HasOne}} 關係無法建立多個 {0} 實例",
|
||||
"7e9530c0399289be0ee601a604be71ff": "{{BelongsTo}} 關係 {0} 是空的",
|
||||
"7faa840eb6ce11250a141deb42a6c489": "不明關係 {{scope}}:{0}",
|
||||
"89afd3a9249f5a8d3edda07d84ca049d": "找不到 {{Polymorphic}} 模型:`{0}`",
|
||||
"a004f310d315e592843776fab964eaeb": "{{Polymorphic}} 關係需要有通過模型",
|
||||
"a25e41a39c60c4702e55d0c3936576a1": "索引鍵不符:{0}.{1}:{2},{3}.{4}:{5}",
|
||||
"a327355560d495454fba2c1aad6bdf09": "不明範圍方法:{0}",
|
||||
"e08ab0e1ab55f26c357061447b635905": "在 {0} 中找不到 ({1}.{2},{3}.{4}) 的關係",
|
||||
"e55937649d8d7a11706b8cec22d02eae": "{{HasOne}} 關係 {0} 是空的",
|
||||
"2c4904377a87fdab502118719cc0d266": "不支援 {{Transaction}}",
|
||||
"ecb7aa804bf54c682999d20d6436104c": "{{transaction}} 為非作用中:{0}",
|
||||
"89bf6d92731fe7bd2146ce8d0bec205c": "引數無效,必須是字串、{{regex}} 文字或 {{RegExp}} 物件",
|
||||
"8c5ab01638c1ac1d58168c6346a8481a": "無效 {{regex}} 旗標:{0}",
|
||||
"a6c18a7f4390cd3d59a2a7a047ae2aab": "執行 \"{{npm install loopback-datasource-juggler}} {0}\" 指令",
|
||||
"b138294f132edfe1eb2a8211150c7238": "查詢中有非預期的 `undefined`",
|
||||
"8a39126103a157f501affa070367a1b0": "{0} 實例無效。詳細資料:{1}。"
|
||||
}
|
||||
|
|
@ -1,3 +1,9 @@
|
|||
// Copyright IBM Corp. 2015,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
// A lightweight alternative to "depd" that works in the browser
|
||||
module.exports = function depd(namespace) {
|
||||
var warned = {};
|
||||
|
|
|
@ -0,0 +1,223 @@
|
|||
'use strict';
|
||||
|
||||
var g = require('strong-globalize')();
|
||||
|
||||
var assert = require('assert');
|
||||
var Connector = require('loopback-connector').Connector;
|
||||
var debug = require('debug')('loopback:connector:kv-memory');
|
||||
var minimatch = require('minimatch');
|
||||
var util = require('util');
|
||||
|
||||
exports.initialize = function initializeDataSource(dataSource, cb) {
|
||||
var settings = dataSource.settings;
|
||||
dataSource.connector = new KeyValueMemoryConnector(settings, dataSource);
|
||||
if (cb) process.nextTick(cb);
|
||||
};
|
||||
|
||||
function KeyValueMemoryConnector(settings, dataSource) {
|
||||
Connector.call(this, 'kv-memory', settings);
|
||||
|
||||
debug('Connector settings', settings);
|
||||
|
||||
this.dataSource = dataSource;
|
||||
this.DataAccessObject = dataSource.juggler.KeyValueAccessObject;
|
||||
|
||||
this._store = Object.create(null);
|
||||
|
||||
this._setupRegularCleanup();
|
||||
};
|
||||
util.inherits(KeyValueMemoryConnector, Connector);
|
||||
|
||||
KeyValueMemoryConnector.prototype._setupRegularCleanup = function() {
|
||||
// Scan the database for expired keys at a regular interval
|
||||
// in order to release memory. Note that GET operation checks
|
||||
// key expiration too, the scheduled cleanup is merely a performance
|
||||
// optimization.
|
||||
var self = this;
|
||||
var timer = this._cleanupTimer = setInterval(
|
||||
function() {
|
||||
if (self && self._removeExpiredItems) {
|
||||
self._removeExpiredItems();
|
||||
} else {
|
||||
// The datasource/connector was destroyed - cancel the timer
|
||||
clearInterval(timer);
|
||||
}
|
||||
},
|
||||
1000);
|
||||
this._cleanupTimer.unref();
|
||||
};
|
||||
|
||||
KeyValueMemoryConnector._removeExpiredItems = function() {
|
||||
debug('Running scheduled cleanup of expired items.');
|
||||
for (var modelName in this._store) {
|
||||
var modelStore = this._store[modelName];
|
||||
for (var key in modelStore) {
|
||||
if (modelStore[key].isExpired()) {
|
||||
debug('Removing expired key', key);
|
||||
delete modelStore[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
KeyValueMemoryConnector.prototype._getStoreForModel = function(modelName) {
|
||||
if (!(modelName in this._store)) {
|
||||
this._store[modelName] = Object.create(null);
|
||||
}
|
||||
return this._store[modelName];
|
||||
};
|
||||
|
||||
KeyValueMemoryConnector.prototype._removeIfExpired = function(modelName, key) {
|
||||
var store = this._getStoreForModel(modelName);
|
||||
var item = store[key];
|
||||
if (item && item.isExpired()) {
|
||||
debug('Removing expired key', key);
|
||||
delete store[key];
|
||||
item = undefined;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
KeyValueMemoryConnector.prototype.get =
|
||||
function(modelName, key, options, callback) {
|
||||
this._removeIfExpired(modelName, key);
|
||||
|
||||
var store = this._getStoreForModel(modelName);
|
||||
var item = store[key];
|
||||
var value = item ? item.value : null;
|
||||
debug('GET %j %j -> %s', modelName, key, value);
|
||||
|
||||
if (/^buffer:/.test(value)) {
|
||||
value = new Buffer(value.slice(7), 'base64');
|
||||
} else if (/^date:/.test(value)) {
|
||||
value = new Date(value.slice(5));
|
||||
} else if (value != null) {
|
||||
value = JSON.parse(value);
|
||||
}
|
||||
|
||||
process.nextTick(function() {
|
||||
callback(null, value);
|
||||
});
|
||||
};
|
||||
|
||||
KeyValueMemoryConnector.prototype.set =
|
||||
function(modelName, key, value, options, callback) {
|
||||
var store = this._getStoreForModel(modelName);
|
||||
var value;
|
||||
if (Buffer.isBuffer(value)) {
|
||||
value = 'buffer:' + value.toString('base64');
|
||||
} else if (value instanceof Date) {
|
||||
value = 'date:' + value.toISOString();
|
||||
} else {
|
||||
value = JSON.stringify(value);
|
||||
}
|
||||
|
||||
debug('SET %j %j %s %j', modelName, key, value, options);
|
||||
store[key] = new StoreItem(value, options && options.ttl);
|
||||
|
||||
process.nextTick(callback);
|
||||
};
|
||||
|
||||
KeyValueMemoryConnector.prototype.expire =
|
||||
function(modelName, key, ttl, options, callback) {
|
||||
this._removeIfExpired(modelName, key);
|
||||
|
||||
var store = this._getStoreForModel(modelName);
|
||||
|
||||
if (!(key in store)) {
|
||||
return process.nextTick(function() {
|
||||
var err = new Error(g.f('Cannot expire unknown key %j', key));
|
||||
err.statusCode = 404;
|
||||
callback(err);
|
||||
});
|
||||
}
|
||||
|
||||
debug('EXPIRE %j %j %s', modelName, key, ttl || '(never)');
|
||||
store[key].setTtl(ttl);
|
||||
process.nextTick(callback);
|
||||
};
|
||||
|
||||
KeyValueMemoryConnector.prototype.ttl =
|
||||
function(modelName, key, options, callback) {
|
||||
this._removeIfExpired(modelName, key);
|
||||
|
||||
var store = this._getStoreForModel(modelName);
|
||||
|
||||
// key is unknown
|
||||
if (!(key in store)) {
|
||||
return process.nextTick(function() {
|
||||
var err = new Error(g.f('Cannot get TTL for unknown key %j', key));
|
||||
err.statusCode = 404;
|
||||
callback(err);
|
||||
});
|
||||
}
|
||||
|
||||
var ttl = store[key].getTtl();
|
||||
debug('TTL %j %j -> %s', modelName, key, ttl);
|
||||
|
||||
process.nextTick(function() {
|
||||
callback(null, ttl);
|
||||
});
|
||||
};
|
||||
|
||||
KeyValueMemoryConnector.prototype.iterateKeys =
|
||||
function(modelName, filter, options, callback) {
|
||||
var store = this._getStoreForModel(modelName);
|
||||
var self = this;
|
||||
var checkFilter = createMatcher(filter.match);
|
||||
|
||||
var keys = Object.keys(store).filter(function(key) {
|
||||
return !self._removeIfExpired(modelName, key) && checkFilter(key);
|
||||
});
|
||||
|
||||
debug('ITERATE KEYS %j -> %s keys', modelName, keys.length);
|
||||
|
||||
var ix = 0;
|
||||
return {
|
||||
next: function(cb) {
|
||||
var value = ix < keys.length ? keys[ix++] : undefined;
|
||||
setImmediate(function() { cb(null, value); });
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
function createMatcher(pattern) {
|
||||
if (!pattern) return function matchAll() { return true; };
|
||||
|
||||
return minimatch.filter(pattern, {
|
||||
nobrace: true,
|
||||
noglobstar: true,
|
||||
dot: true,
|
||||
noext: true,
|
||||
nocomment: true,
|
||||
});
|
||||
}
|
||||
|
||||
KeyValueMemoryConnector.prototype.disconnect = function(callback) {
|
||||
if (this._cleanupTimer)
|
||||
clearInterval(this._cleanupTimer);
|
||||
this._cleanupTimer = null;
|
||||
process.nextTick(callback);
|
||||
};
|
||||
|
||||
function StoreItem(value, ttl) {
|
||||
this.value = value;
|
||||
this.setTtl(ttl);
|
||||
}
|
||||
|
||||
StoreItem.prototype.isExpired = function() {
|
||||
return this.expires && this.expires <= Date.now();
|
||||
};
|
||||
|
||||
StoreItem.prototype.setTtl = function(ttl) {
|
||||
if (ttl) {
|
||||
this.expires = Date.now() + ttl;
|
||||
} else {
|
||||
this.expires = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
StoreItem.prototype.getTtl = function() {
|
||||
return !this.expires ? undefined : this.expires - Date.now();
|
||||
};
|
|
@ -1,3 +1,10 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var g = require('strong-globalize')();
|
||||
var util = require('util');
|
||||
var Connector = require('loopback-connector').Connector;
|
||||
var geo = require('../geo');
|
||||
|
@ -44,7 +51,7 @@ Memory.prototype.getTypes = function() {
|
|||
return ['db', 'nosql', 'memory'];
|
||||
};
|
||||
|
||||
Memory.prototype.connect = function (callback) {
|
||||
Memory.prototype.connect = function(callback) {
|
||||
if (this.isTransaction) {
|
||||
this.onTransactionExec = callback;
|
||||
} else {
|
||||
|
@ -53,17 +60,17 @@ Memory.prototype.connect = function (callback) {
|
|||
};
|
||||
|
||||
function serialize(obj) {
|
||||
if(obj === null || obj === undefined) {
|
||||
if (obj === null || obj === undefined) {
|
||||
return obj;
|
||||
}
|
||||
return JSON.stringify(obj);
|
||||
}
|
||||
|
||||
function deserialize(dbObj) {
|
||||
if(dbObj === null || dbObj === undefined) {
|
||||
if (dbObj === null || dbObj === undefined) {
|
||||
return dbObj;
|
||||
}
|
||||
if(typeof dbObj === 'string') {
|
||||
if (typeof dbObj === 'string') {
|
||||
return JSON.parse(dbObj);
|
||||
} else {
|
||||
return dbObj;
|
||||
|
@ -76,12 +83,12 @@ Memory.prototype.getCollection = function(model) {
|
|||
model = modelClass.settings.memory.collection || model;
|
||||
}
|
||||
return model;
|
||||
}
|
||||
};
|
||||
|
||||
Memory.prototype.initCollection = function(model) {
|
||||
this.collection(model, {});
|
||||
this.collectionSeq(model, 1);
|
||||
}
|
||||
};
|
||||
|
||||
Memory.prototype.collection = function(model, val) {
|
||||
model = this.getCollection(model);
|
||||
|
@ -101,14 +108,14 @@ Memory.prototype.loadFromFile = function(callback) {
|
|||
var localStorage = hasLocalStorage && this.settings.localStorage;
|
||||
|
||||
if (self.settings.file) {
|
||||
fs.readFile(self.settings.file, {encoding: 'utf8', flag: 'r'}, function (err, data) {
|
||||
fs.readFile(self.settings.file, {encoding: 'utf8', flag: 'r'}, function(err, data) {
|
||||
if (err && err.code !== 'ENOENT') {
|
||||
callback && callback(err);
|
||||
} else {
|
||||
parseAndLoad(data);
|
||||
}
|
||||
});
|
||||
} else if(localStorage) {
|
||||
} else if (localStorage) {
|
||||
var data = window.localStorage.getItem(localStorage);
|
||||
data = data || '{}';
|
||||
parseAndLoad(data);
|
||||
|
@ -120,14 +127,14 @@ Memory.prototype.loadFromFile = function(callback) {
|
|||
if (data) {
|
||||
try {
|
||||
data = JSON.parse(data.toString());
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
return callback(e);
|
||||
}
|
||||
|
||||
self.ids = data.ids || {};
|
||||
self.cache = data.models || {};
|
||||
} else {
|
||||
if(!self.cache) {
|
||||
if (!self.cache) {
|
||||
self.ids = {};
|
||||
self.cache = {};
|
||||
}
|
||||
|
@ -140,22 +147,22 @@ Memory.prototype.loadFromFile = function(callback) {
|
|||
* Flush the cache into the json file if necessary
|
||||
* @param {Function} callback
|
||||
*/
|
||||
Memory.prototype.saveToFile = function (result, callback) {
|
||||
Memory.prototype.saveToFile = function(result, callback) {
|
||||
var self = this;
|
||||
var file = this.settings.file;
|
||||
var hasLocalStorage = typeof window !== 'undefined' && window.localStorage;
|
||||
var localStorage = hasLocalStorage && this.settings.localStorage;
|
||||
if (file) {
|
||||
if(!self.writeQueue) {
|
||||
if (!self.writeQueue) {
|
||||
// Create a queue for writes
|
||||
self.writeQueue = async.queue(function (task, cb) {
|
||||
self.writeQueue = async.queue(function(task, cb) {
|
||||
// Flush out the models/ids
|
||||
var data = JSON.stringify({
|
||||
ids: self.ids,
|
||||
models: self.cache
|
||||
models: self.cache,
|
||||
}, null, ' ');
|
||||
|
||||
fs.writeFile(self.settings.file, data, function (err) {
|
||||
fs.writeFile(self.settings.file, data, function(err) {
|
||||
cb(err);
|
||||
task.callback && task.callback(err, task.data);
|
||||
});
|
||||
|
@ -164,20 +171,20 @@ Memory.prototype.saveToFile = function (result, callback) {
|
|||
// Enqueue the write
|
||||
self.writeQueue.push({
|
||||
data: result,
|
||||
callback: callback
|
||||
callback: callback,
|
||||
});
|
||||
} else if (localStorage) {
|
||||
// Flush out the models/ids
|
||||
var data = JSON.stringify({
|
||||
ids: self.ids,
|
||||
models: self.cache
|
||||
models: self.cache,
|
||||
}, null, ' ');
|
||||
window.localStorage.setItem(localStorage, data);
|
||||
process.nextTick(function () {
|
||||
process.nextTick(function() {
|
||||
callback && callback(null, result);
|
||||
});
|
||||
} else {
|
||||
process.nextTick(function () {
|
||||
process.nextTick(function() {
|
||||
callback && callback(null, result);
|
||||
});
|
||||
}
|
||||
|
@ -186,10 +193,10 @@ Memory.prototype.saveToFile = function (result, callback) {
|
|||
Memory.prototype.define = function defineModel(definition) {
|
||||
this.constructor.super_.prototype.define.apply(this, [].slice.call(arguments));
|
||||
var m = definition.model.modelName;
|
||||
if(!this.collection(m)) this.initCollection(m);
|
||||
if (!this.collection(m)) this.initCollection(m);
|
||||
};
|
||||
|
||||
Memory.prototype.create = function create(model, data, options, callback) {
|
||||
Memory.prototype._createSync = function(model, data, fn) {
|
||||
// FIXME: [rfeng] We need to generate unique ids based on the id type
|
||||
// FIXME: [rfeng] We don't support composite ids yet
|
||||
var currentId = this.collectionSeq(model);
|
||||
|
@ -207,33 +214,102 @@ Memory.prototype.create = function create(model, data, options, callback) {
|
|||
var idName = this.idName(model);
|
||||
id = (props[idName] && props[idName].type && props[idName].type(id)) || id;
|
||||
this.setIdValue(model, data, id);
|
||||
if(!this.collection(model)) {
|
||||
if (!this.collection(model)) {
|
||||
this.collection(model, {});
|
||||
}
|
||||
|
||||
if (this.collection(model)[id]) {
|
||||
return process.nextTick(function() {
|
||||
callback(new Error('Duplicate entry for ' + model + '.' + idName));
|
||||
if (this.collection(model)[id])
|
||||
return fn(new Error(g.f('Duplicate entry for %s.%s', model, idName)));
|
||||
|
||||
this.collection(model)[id] = serialize(data);
|
||||
fn(null, id);
|
||||
};
|
||||
|
||||
Memory.prototype.create = function create(model, data, options, callback) {
|
||||
var self = this;
|
||||
this._createSync(model, data, function(err, id) {
|
||||
if (err) {
|
||||
return process.nextTick(function() {
|
||||
callback(err);
|
||||
});
|
||||
};
|
||||
self.saveToFile(id, callback);
|
||||
});
|
||||
};
|
||||
|
||||
Memory.prototype.updateOrCreate = function(model, data, options, callback) {
|
||||
var self = this;
|
||||
this.exists(model, self.getIdValue(model, data), options, function(err, exists) {
|
||||
if (exists) {
|
||||
self.save(model, data, options, function(err, data) {
|
||||
callback(err, data, {isNewInstance: false});
|
||||
});
|
||||
} else {
|
||||
self.create(model, data, options, function(err, id) {
|
||||
self.setIdValue(model, data, id);
|
||||
callback(err, data, {isNewInstance: true});
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Memory.prototype.patchOrCreateWithWhere =
|
||||
Memory.prototype.upsertWithWhere = function(model, where, data, options, callback) {
|
||||
var self = this;
|
||||
var primaryKey = this.idName(model);
|
||||
var filter = {where: where};
|
||||
var nodes = self._findAllSkippingIncludes(model, filter);
|
||||
if (nodes.length === 0) {
|
||||
return self._createSync(model, data, function(err, id) {
|
||||
if (err) return process.nextTick(function() { callback(err); });
|
||||
self.saveToFile(id, function(err, id) {
|
||||
self.setIdValue(model, data, id);
|
||||
callback(err, self.fromDb(model, data), {isNewInstance: true});
|
||||
});
|
||||
});
|
||||
}
|
||||
if (nodes.length === 1) {
|
||||
var primaryKeyValue = nodes[0][primaryKey];
|
||||
self.updateAttributes(model, primaryKeyValue, data, options, function(err, data) {
|
||||
callback(err, data, {isNewInstance: false});
|
||||
});
|
||||
} else {
|
||||
process.nextTick(function() {
|
||||
var error = new Error('There are multiple instances found.' +
|
||||
'Upsert Operation will not be performed!');
|
||||
error.statusCode = 400;
|
||||
callback(error);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Memory.prototype.findOrCreate = function(model, filter, data, callback) {
|
||||
var self = this;
|
||||
var nodes = self._findAllSkippingIncludes(model, filter);
|
||||
var found = nodes[0];
|
||||
|
||||
if (!found) {
|
||||
// Calling _createSync to update the collection in a sync way and to guarantee to create it in the same turn of even loop
|
||||
return self._createSync(model, data, function(err, id) {
|
||||
if (err) return callback(err);
|
||||
self.saveToFile(id, function(err, id) {
|
||||
self.setIdValue(model, data, id);
|
||||
callback(err, data, true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
this.collection(model)[id] = serialize(data);
|
||||
this.saveToFile(id, callback);
|
||||
};
|
||||
if (!filter || !filter.include) {
|
||||
return process.nextTick(function() {
|
||||
callback(null, found, false);
|
||||
});
|
||||
}
|
||||
|
||||
Memory.prototype.updateOrCreate = function (model, data, options, callback) {
|
||||
var self = this;
|
||||
this.exists(model, self.getIdValue(model, data), options, function (err, exists) {
|
||||
if (exists) {
|
||||
self.save(model, data, options, function(err, data) {
|
||||
callback(err, data, { isNewInstance: false });
|
||||
});
|
||||
} else {
|
||||
self.create(model, data, options, function (err, id) {
|
||||
self.setIdValue(model, data, id);
|
||||
callback(err, data, { isNewInstance: true });
|
||||
});
|
||||
}
|
||||
self._models[model].model.include(nodes[0], filter.include, {}, function(err, nodes) {
|
||||
process.nextTick(function() {
|
||||
if (err) return callback(err);
|
||||
callback(null, nodes[0], false);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -248,18 +324,18 @@ Memory.prototype.save = function save(model, data, options, callback) {
|
|||
}
|
||||
this.collection(model)[id] = serialize(data);
|
||||
this.saveToFile(data, function(err) {
|
||||
callback(err, self.fromDb(model, data), { isNewInstance: !modelData });
|
||||
callback(err, self.fromDb(model, data), {isNewInstance: !modelData});
|
||||
});
|
||||
};
|
||||
|
||||
Memory.prototype.exists = function exists(model, id, options, callback) {
|
||||
process.nextTick(function () {
|
||||
process.nextTick(function() {
|
||||
callback(null, this.collection(model) && this.collection(model).hasOwnProperty(id));
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Memory.prototype.find = function find(model, id, options, callback) {
|
||||
process.nextTick(function () {
|
||||
process.nextTick(function() {
|
||||
callback(null, id in this.collection(model) && this.fromDb(model, this.collection(model)[id]));
|
||||
}.bind(this));
|
||||
};
|
||||
|
@ -267,36 +343,72 @@ Memory.prototype.find = function find(model, id, options, callback) {
|
|||
Memory.prototype.destroy = function destroy(model, id, options, callback) {
|
||||
var exists = this.collection(model)[id];
|
||||
delete this.collection(model)[id];
|
||||
this.saveToFile({ count: exists ? 1 : 0 }, callback);
|
||||
this.saveToFile({count: exists ? 1 : 0}, callback);
|
||||
};
|
||||
|
||||
Memory.prototype.fromDb = function (model, data) {
|
||||
Memory.prototype.fromDb = function(model, data) {
|
||||
if (!data) return null;
|
||||
data = deserialize(data);
|
||||
var props = this._models[model].properties;
|
||||
for (var key in data) {
|
||||
var val = data[key];
|
||||
if (val === undefined || val === null) {
|
||||
continue;
|
||||
try {
|
||||
for (var key in data) {
|
||||
data[key] = this._castPropertyValue(key, data[key], props);
|
||||
}
|
||||
if (props[key]) {
|
||||
switch (props[key].type.name) {
|
||||
case 'Date':
|
||||
val = new Date(val.toString().replace(/GMT.*$/, 'GMT'));
|
||||
break;
|
||||
case 'Boolean':
|
||||
val = Boolean(val);
|
||||
break;
|
||||
case 'Number':
|
||||
val = Number(val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
data[key] = val;
|
||||
} catch (err) {
|
||||
// Modify error message and re-throw
|
||||
err.message = g.f('Unable to convert to instance of "%s": %s', model,
|
||||
err);
|
||||
throw err;
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
Memory.prototype._castPropertyValue = function(prop, val, props) {
|
||||
var self = this;
|
||||
if (val === undefined || val === null || !props[prop]) {
|
||||
return val;
|
||||
}
|
||||
|
||||
if (Array.isArray(val)) {
|
||||
return val.map(function(val) {
|
||||
return self._castPropertyValue(prop, val, props);
|
||||
});
|
||||
}
|
||||
|
||||
var isArray = Array.isArray(props[prop].type);
|
||||
var propType = isArray ? props[prop].type[0] : props[prop].type;
|
||||
if (!propType || !propType.name) {
|
||||
if (isArray)
|
||||
throw new Error(g.f(
|
||||
'Property definition "%s" did not specify any sub-types!', prop));
|
||||
else
|
||||
throw new Error(g.f(
|
||||
'Property definition "%s" was null or undefined!', prop
|
||||
));
|
||||
}
|
||||
switch (propType.name) {
|
||||
case 'Date':
|
||||
val = new Date(val.toString().replace(/GMT.*$/, 'GMT'));
|
||||
break;
|
||||
case 'Boolean':
|
||||
val = Boolean(val);
|
||||
break;
|
||||
case 'Number':
|
||||
val = Number(val);
|
||||
break;
|
||||
case 'ModelConstructor':
|
||||
for (var subProp in val) {
|
||||
if (propType.definition && propType.definition.properties)
|
||||
val[subProp] = this._castPropertyValue(subProp, val[subProp],
|
||||
propType.definition.properties);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return val;
|
||||
};
|
||||
|
||||
function getValue(obj, path) {
|
||||
if (obj == null) {
|
||||
return undefined;
|
||||
|
@ -312,9 +424,8 @@ function getValue(obj, path) {
|
|||
return val;
|
||||
}
|
||||
|
||||
Memory.prototype.all = function all(model, filter, options, callback) {
|
||||
var self = this;
|
||||
var nodes = Object.keys(this.collection(model)).map(function (key) {
|
||||
Memory.prototype._findAllSkippingIncludes = function(model, filter) {
|
||||
var nodes = Object.keys(this.collection(model)).map(function(key) {
|
||||
return this.fromDb(model, this.collection(model)[key]);
|
||||
}.bind(this));
|
||||
|
||||
|
@ -328,17 +439,17 @@ Memory.prototype.all = function all(model, filter, options, callback) {
|
|||
// do we need some sorting?
|
||||
if (filter.order) {
|
||||
var orders = filter.order;
|
||||
if (typeof filter.order === "string") {
|
||||
if (typeof filter.order === 'string') {
|
||||
orders = [filter.order];
|
||||
}
|
||||
orders.forEach(function (key, i) {
|
||||
orders.forEach(function(key, i) {
|
||||
var reverse = 1;
|
||||
var m = key.match(/\s+(A|DE)SC$/i);
|
||||
if (m) {
|
||||
key = key.replace(/\s+(A|DE)SC/i, '');
|
||||
if (m[1].toLowerCase() === 'de') reverse = -1;
|
||||
}
|
||||
orders[i] = {"key": key, "reverse": reverse};
|
||||
orders[i] = {'key': key, 'reverse': reverse};
|
||||
});
|
||||
nodes = nodes.sort(sorting.bind(orders));
|
||||
}
|
||||
|
@ -364,14 +475,7 @@ Memory.prototype.all = function all(model, filter, options, callback) {
|
|||
var limit = filter.limit || nodes.length;
|
||||
nodes = nodes.slice(skip, skip + limit);
|
||||
}
|
||||
|
||||
process.nextTick(function () {
|
||||
if (filter && filter.include) {
|
||||
self._models[model].model.include(nodes, filter.include, options, callback);
|
||||
} else {
|
||||
callback(null, nodes);
|
||||
}
|
||||
});
|
||||
return nodes;
|
||||
|
||||
function sorting(a, b) {
|
||||
var undefinedA, undefinedB;
|
||||
|
@ -393,22 +497,35 @@ Memory.prototype.all = function all(model, filter, options, callback) {
|
|||
}
|
||||
};
|
||||
|
||||
Memory.prototype.all = function all(model, filter, options, callback) {
|
||||
var self = this;
|
||||
var nodes = self._findAllSkippingIncludes(model, filter);
|
||||
|
||||
process.nextTick(function() {
|
||||
if (filter && filter.include) {
|
||||
self._models[model].model.include(nodes, filter.include, options, callback);
|
||||
} else {
|
||||
callback(null, nodes);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function applyFilter(filter) {
|
||||
var where = filter.where;
|
||||
if (typeof where === 'function') {
|
||||
return where;
|
||||
}
|
||||
var keys = Object.keys(where);
|
||||
return function (obj) {
|
||||
return function(obj) {
|
||||
return keys.every(function(key) {
|
||||
if(key === 'and' || key === 'or') {
|
||||
if(Array.isArray(where[key])) {
|
||||
if(key === 'and') {
|
||||
if (key === 'and' || key === 'or') {
|
||||
if (Array.isArray(where[key])) {
|
||||
if (key === 'and') {
|
||||
return where[key].every(function(cond) {
|
||||
return applyFilter({where: cond})(obj);
|
||||
});
|
||||
}
|
||||
if(key === 'or') {
|
||||
if (key === 'or') {
|
||||
return where[key].some(function(cond) {
|
||||
return applyFilter({where: cond})(obj);
|
||||
});
|
||||
|
@ -426,14 +543,13 @@ function applyFilter(filter) {
|
|||
if (matcher.neq !== undefined && value.length <= 0) {
|
||||
return true;
|
||||
}
|
||||
return value.some(function (v, i) {
|
||||
return value.some(function(v, i) {
|
||||
var filter = {where: {}};
|
||||
filter.where[i] = matcher;
|
||||
return applyFilter(filter)(value);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (test(where[key], value)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -442,16 +558,20 @@ function applyFilter(filter) {
|
|||
// then, we attempt to emulate mongo db matching. Helps for embedded relations
|
||||
var dotIndex = key.indexOf('.');
|
||||
var subValue = obj[key.substring(0, dotIndex)];
|
||||
if (dotIndex !== -1 && Array.isArray(subValue)) {
|
||||
if (dotIndex !== -1) {
|
||||
var subFilter = {where: {}};
|
||||
var subKey = key.substring(dotIndex+1);
|
||||
var subKey = key.substring(dotIndex + 1);
|
||||
subFilter.where[subKey] = where[key];
|
||||
return subValue.some(applyFilter(subFilter));
|
||||
if (Array.isArray(subValue)) {
|
||||
return subValue.some(applyFilter(subFilter));
|
||||
} else if (typeof subValue === 'object' && subValue !== null) {
|
||||
return applyFilter(subFilter)(subValue);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function toRegExp(pattern) {
|
||||
if (pattern instanceof RegExp) {
|
||||
|
@ -460,7 +580,7 @@ function applyFilter(filter) {
|
|||
var regex = '';
|
||||
// Escaping user input to be treated as a literal string within a regular expression
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Writing_a_Regular_Expression_Pattern
|
||||
pattern = pattern.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
|
||||
pattern = pattern.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1');
|
||||
for (var i = 0, n = pattern.length; i < n; i++) {
|
||||
var char = pattern.charAt(i);
|
||||
if (char === '\\') {
|
||||
|
@ -477,8 +597,7 @@ function applyFilter(filter) {
|
|||
regex += '\\.';
|
||||
} else if (char === '*') {
|
||||
regex += '\\*';
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
regex += char;
|
||||
}
|
||||
}
|
||||
|
@ -518,14 +637,13 @@ function applyFilter(filter) {
|
|||
return compare(example.neq, value) !== 0;
|
||||
}
|
||||
|
||||
if ('between' in example ) {
|
||||
return ( testInEquality({gte:example.between[0]}, value) &&
|
||||
testInEquality({lte:example.between[1]}, value) );
|
||||
if ('between' in example) {
|
||||
return (testInEquality({gte: example.between[0]}, value) &&
|
||||
testInEquality({lte: example.between[1]}, value));
|
||||
}
|
||||
|
||||
if (example.like || example.nlike) {
|
||||
|
||||
var like = example.like || example.nlike;
|
||||
if (example.like || example.nlike || example.ilike || example.nilike) {
|
||||
var like = example.like || example.nlike || example.ilike || example.nilike;
|
||||
if (typeof like === 'string') {
|
||||
like = toRegExp(like);
|
||||
}
|
||||
|
@ -536,6 +654,14 @@ function applyFilter(filter) {
|
|||
if (example.nlike) {
|
||||
return !new RegExp(like).test(value);
|
||||
}
|
||||
|
||||
if (example.ilike) {
|
||||
return !!new RegExp(like, 'i').test(value);
|
||||
}
|
||||
|
||||
if (example.nilike) {
|
||||
return !new RegExp(like, 'i').test(value);
|
||||
}
|
||||
}
|
||||
|
||||
if (testInEquality(example, value)) {
|
||||
|
@ -543,8 +669,8 @@ function applyFilter(filter) {
|
|||
}
|
||||
}
|
||||
// not strict equality
|
||||
return (example !== null ? example.toString() : example)
|
||||
== (value != null ? value.toString() : value);
|
||||
return (example !== null ? example.toString() : example) ==
|
||||
(value != null ? value.toString() : value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -555,7 +681,7 @@ function applyFilter(filter) {
|
|||
* @private
|
||||
*/
|
||||
function compare(val1, val2) {
|
||||
if(val1 == null || val2 == null) {
|
||||
if (val1 == null || val2 == null) {
|
||||
// Either val1 or val2 is null or undefined
|
||||
return val1 == val2 ? 0 : NaN;
|
||||
}
|
||||
|
@ -599,7 +725,7 @@ Memory.prototype.destroyAll = function destroyAll(model, where, options, callbac
|
|||
var count = 0;
|
||||
if (where) {
|
||||
filter = applyFilter({where: where});
|
||||
Object.keys(cache).forEach(function (id) {
|
||||
Object.keys(cache).forEach(function(id) {
|
||||
if (!filter || filter(this.fromDb(model, cache[id]))) {
|
||||
count++;
|
||||
delete cache[id];
|
||||
|
@ -609,7 +735,7 @@ Memory.prototype.destroyAll = function destroyAll(model, where, options, callbac
|
|||
count = Object.keys(cache).length;
|
||||
this.collection(model, {});
|
||||
}
|
||||
this.saveToFile({ count: count }, callback);
|
||||
this.saveToFile({count: count}, callback);
|
||||
};
|
||||
|
||||
Memory.prototype.count = function count(model, where, options, callback) {
|
||||
|
@ -617,12 +743,12 @@ Memory.prototype.count = function count(model, where, options, callback) {
|
|||
var data = Object.keys(cache);
|
||||
if (where) {
|
||||
var filter = {where: where};
|
||||
data = data.map(function (id) {
|
||||
data = data.map(function(id) {
|
||||
return this.fromDb(model, cache[id]);
|
||||
}.bind(this));
|
||||
data = data.filter(applyFilter(filter));
|
||||
}
|
||||
process.nextTick(function () {
|
||||
process.nextTick(function() {
|
||||
callback(null, data.length);
|
||||
});
|
||||
};
|
||||
|
@ -637,7 +763,7 @@ Memory.prototype.update =
|
|||
|
||||
var ids = Object.keys(cache);
|
||||
var count = 0;
|
||||
async.each(ids, function (id, done) {
|
||||
async.each(ids, function(id, done) {
|
||||
var inst = self.fromDb(model, cache[id]);
|
||||
if (!filter || filter(inst)) {
|
||||
count++;
|
||||
|
@ -648,7 +774,7 @@ Memory.prototype.update =
|
|||
} else {
|
||||
process.nextTick(done);
|
||||
}
|
||||
}, function (err) {
|
||||
}, function(err) {
|
||||
if (err) return cb(err);
|
||||
self.saveToFile({count: count}, cb);
|
||||
});
|
||||
|
@ -656,7 +782,7 @@ Memory.prototype.update =
|
|||
|
||||
Memory.prototype.updateAttributes = function updateAttributes(model, id, data, options, cb) {
|
||||
if (!id) {
|
||||
var err = new Error('You must provide an id when updating attributes!');
|
||||
var err = new Error(g.f('You must provide an {{id}} when updating attributes!'));
|
||||
if (cb) {
|
||||
return cb(err);
|
||||
} else {
|
||||
|
@ -675,24 +801,82 @@ Memory.prototype.updateAttributes = function updateAttributes(model, id, data, o
|
|||
if (modelData) {
|
||||
this.save(model, data, options, cb);
|
||||
} else {
|
||||
cb(new Error('Could not update attributes. Object with id ' + id + ' does not exist!'));
|
||||
cb(new Error(g.f('Could not update attributes. {{Object}} with {{id}} %s does not exist!', id)));
|
||||
}
|
||||
};
|
||||
|
||||
Memory.prototype.transaction = function () {
|
||||
Memory.prototype.replaceById = function(model, id, data, options, cb) {
|
||||
var self = this;
|
||||
if (!id) {
|
||||
var err = new Error(g.f('You must provide an {{id}} when replacing!'));
|
||||
return process.nextTick(function() { cb(err); });
|
||||
}
|
||||
// Do not modify the data object passed in arguments
|
||||
data = Object.create(data);
|
||||
this.setIdValue(model, data, id);
|
||||
var cachedModels = this.collection(model);
|
||||
var modelData = cachedModels && this.collection(model)[id];
|
||||
if (!modelData) {
|
||||
var msg = 'Could not replace. Object with id ' + id + ' does not exist!';
|
||||
return process.nextTick(function() { cb(new Error(msg)); });
|
||||
}
|
||||
|
||||
var newModelData = {};
|
||||
for (var key in data) {
|
||||
var val = data[key];
|
||||
if (typeof val === 'function') {
|
||||
continue; // Skip methods
|
||||
}
|
||||
newModelData[key] = val;
|
||||
}
|
||||
|
||||
this.collection(model)[id] = serialize(newModelData);
|
||||
this.saveToFile(newModelData, function(err) {
|
||||
cb(err, self.fromDb(model, newModelData));
|
||||
});
|
||||
};
|
||||
|
||||
Memory.prototype.replaceOrCreate = function(model, data, options, callback) {
|
||||
var self = this;
|
||||
var idName = self.idNames(model)[0];
|
||||
var idValue = self.getIdValue(model, data);
|
||||
var filter = {where: {}};
|
||||
filter.where[idName] = idValue;
|
||||
var nodes = self._findAllSkippingIncludes(model, filter);
|
||||
var found = nodes[0];
|
||||
|
||||
if (!found) {
|
||||
// Calling _createSync to update the collection in a sync way and
|
||||
// to guarantee to create it in the same turn of even loop
|
||||
return self._createSync(model, data, function(err, id) {
|
||||
if (err) return process.nextTick(function() { callback(err); });
|
||||
self.saveToFile(id, function(err, id) {
|
||||
self.setIdValue(model, data, id);
|
||||
callback(err, self.fromDb(model, data), {isNewInstance: true});
|
||||
});
|
||||
});
|
||||
}
|
||||
var id = self.getIdValue(model, data);
|
||||
self.collection(model)[id] = serialize(data);
|
||||
self.saveToFile(data, function(err) {
|
||||
callback(err, self.fromDb(model, data), {isNewInstance: false});
|
||||
});
|
||||
};
|
||||
|
||||
Memory.prototype.transaction = function() {
|
||||
return new Memory(this);
|
||||
};
|
||||
|
||||
Memory.prototype.exec = function (callback) {
|
||||
Memory.prototype.exec = function(callback) {
|
||||
this.onTransactionExec();
|
||||
setTimeout(callback, 50);
|
||||
};
|
||||
|
||||
Memory.prototype.buildNearFilter = function (filter) {
|
||||
Memory.prototype.buildNearFilter = function(filter) {
|
||||
// noop
|
||||
}
|
||||
};
|
||||
|
||||
Memory.prototype.automigrate = function (models, cb) {
|
||||
Memory.prototype.automigrate = function(models, cb) {
|
||||
var self = this;
|
||||
|
||||
if ((!cb) && ('function' === typeof models)) {
|
||||
|
@ -715,8 +899,8 @@ Memory.prototype.automigrate = function (models, cb) {
|
|||
|
||||
if (invalidModels.length) {
|
||||
return process.nextTick(function() {
|
||||
cb(new Error('Cannot migrate models not attached to this datasource: ' +
|
||||
invalidModels.join(' ')));
|
||||
cb(new Error(g.f('Cannot migrate models not attached to this datasource: %s',
|
||||
invalidModels.join(' '))));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -724,7 +908,7 @@ Memory.prototype.automigrate = function (models, cb) {
|
|||
self.initCollection(m);
|
||||
});
|
||||
if (cb) process.nextTick(cb);
|
||||
}
|
||||
};
|
||||
|
||||
function merge(base, update) {
|
||||
if (!base) {
|
||||
|
@ -732,9 +916,9 @@ function merge(base, update) {
|
|||
}
|
||||
// We cannot use Object.keys(update) if the update is an instance of the model
|
||||
// class as the properties are defined at the ModelClass.prototype level
|
||||
for(var key in update) {
|
||||
for (var key in update) {
|
||||
var val = update[key];
|
||||
if(typeof val === 'function') {
|
||||
if (typeof val === 'function') {
|
||||
continue; // Skip methods
|
||||
}
|
||||
base[key] = val;
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var g = require('strong-globalize')();
|
||||
var util = require('util');
|
||||
var Connector = require('loopback-connector').Connector;
|
||||
var utils = require('../utils');
|
||||
|
@ -42,7 +49,7 @@ Transient.prototype.getTypes = function() {
|
|||
return ['db', 'nosql', 'transient'];
|
||||
};
|
||||
|
||||
Transient.prototype.connect = function (callback) {
|
||||
Transient.prototype.connect = function(callback) {
|
||||
if (this.isTransaction) {
|
||||
this.onTransactionExec = callback;
|
||||
} else {
|
||||
|
@ -58,26 +65,26 @@ Transient.prototype.generateId = function(model, data, idName) {
|
|||
if (idType === Number) {
|
||||
return Math.floor(Math.random() * 10000); // max. 4 digits
|
||||
} else {
|
||||
return crypto.randomBytes(Math.ceil(24/2))
|
||||
return crypto.randomBytes(Math.ceil(24 / 2))
|
||||
.toString('hex') // convert to hexadecimal format
|
||||
.slice(0, 24); // return required number of characters
|
||||
}
|
||||
};
|
||||
|
||||
Transient.prototype.exists = function exists(model, id, callback) {
|
||||
process.nextTick(function () { callback(null, false); }.bind(this));
|
||||
process.nextTick(function() { callback(null, false); }.bind(this));
|
||||
};
|
||||
|
||||
Transient.prototype.find = function find(model, id, callback) {
|
||||
process.nextTick(function () { callback(null, null); }.bind(this));
|
||||
process.nextTick(function() { callback(null, null); }.bind(this));
|
||||
};
|
||||
|
||||
Transient.prototype.all = function all(model, filter, callback) {
|
||||
process.nextTick(function () { callback(null, []); });
|
||||
process.nextTick(function() { callback(null, []); });
|
||||
};
|
||||
|
||||
Transient.prototype.count = function count(model, callback, where) {
|
||||
process.nextTick(function () { callback(null, 0); });
|
||||
process.nextTick(function() { callback(null, 0); });
|
||||
};
|
||||
|
||||
Transient.prototype.create = function create(model, data, callback) {
|
||||
|
@ -99,11 +106,11 @@ Transient.prototype.update =
|
|||
Transient.prototype.updateAll = function updateAll(model, where, data, cb) {
|
||||
var count = 0;
|
||||
this.flush('update', {count: count}, cb);
|
||||
};
|
||||
};
|
||||
|
||||
Transient.prototype.updateAttributes = function updateAttributes(model, id, data, cb) {
|
||||
if (!id) {
|
||||
var err = new Error('You must provide an id when updating attributes!');
|
||||
var err = new Error(g.f('You must provide an {{id}} when updating attributes!'));
|
||||
if (cb) {
|
||||
return cb(err);
|
||||
} else {
|
||||
|
@ -131,15 +138,15 @@ Transient.prototype.destroyAll = function destroyAll(model, where, callback) {
|
|||
* Flush the cache - noop.
|
||||
* @param {Function} callback
|
||||
*/
|
||||
Transient.prototype.flush = function (action, result, callback) {
|
||||
process.nextTick(function () { callback && callback(null, result); });
|
||||
Transient.prototype.flush = function(action, result, callback) {
|
||||
process.nextTick(function() { callback && callback(null, result); });
|
||||
};
|
||||
|
||||
Transient.prototype.transaction = function () {
|
||||
Transient.prototype.transaction = function() {
|
||||
return new Transient(this);
|
||||
};
|
||||
|
||||
Transient.prototype.exec = function (callback) {
|
||||
Transient.prototype.exec = function(callback) {
|
||||
this.onTransactionExec();
|
||||
setTimeout(callback, 50);
|
||||
};
|
||||
|
|
1496
lib/dao.js
1496
lib/dao.js
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
77
lib/geo.js
77
lib/geo.js
|
@ -1,3 +1,9 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var assert = require('assert');
|
||||
|
||||
/*!
|
||||
|
@ -8,7 +14,7 @@ exports.nearFilter = function nearFilter(where) {
|
|||
var result = false;
|
||||
|
||||
if (where && typeof where === 'object') {
|
||||
Object.keys(where).forEach(function (key) {
|
||||
Object.keys(where).forEach(function(key) {
|
||||
var ex = where[key];
|
||||
|
||||
if (ex && ex.near) {
|
||||
|
@ -16,20 +22,20 @@ exports.nearFilter = function nearFilter(where) {
|
|||
near: ex.near,
|
||||
maxDistance: ex.maxDistance,
|
||||
unit: ex.unit,
|
||||
key: key
|
||||
key: key,
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* Filter a set of objects using the given `nearFilter`.
|
||||
*/
|
||||
|
||||
exports.filter = function (arr, filter) {
|
||||
exports.filter = function(arr, filter) {
|
||||
var origin = filter.near;
|
||||
var max = filter.maxDistance > 0 ? filter.maxDistance : false;
|
||||
var unit = filter.unit;
|
||||
|
@ -39,7 +45,7 @@ exports.filter = function (arr, filter) {
|
|||
var distances = {};
|
||||
var result = [];
|
||||
|
||||
arr.forEach(function (obj) {
|
||||
arr.forEach(function(obj) {
|
||||
var loc = obj[key];
|
||||
|
||||
// filter out objects without locations
|
||||
|
@ -62,7 +68,7 @@ exports.filter = function (arr, filter) {
|
|||
}
|
||||
});
|
||||
|
||||
return result.sort(function (objA, objB) {
|
||||
return result.sort(function(objA, objB) {
|
||||
var a = objA[key];
|
||||
var b = objB[key];
|
||||
|
||||
|
@ -76,31 +82,31 @@ exports.filter = function (arr, filter) {
|
|||
return 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.GeoPoint = GeoPoint;
|
||||
|
||||
/**
|
||||
/**
|
||||
* The GeoPoint object represents a physical location.
|
||||
*
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
*
|
||||
* ```js
|
||||
* var loopback = require(‘loopback’);
|
||||
* var here = new loopback.GeoPoint({lat: 10.32424, lng: 5.84978});
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* Embed a latitude / longitude point in a model.
|
||||
*
|
||||
*
|
||||
* ```js
|
||||
* var CoffeeShop = loopback.createModel('coffee-shop', {
|
||||
* location: 'GeoPoint'
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* You can query LoopBack models with a GeoPoint property and an attached data source using geo-spatial filters and
|
||||
* sorting. For example, the following code finds the three nearest coffee shops.
|
||||
*
|
||||
*
|
||||
* ```js
|
||||
* CoffeeShop.attachTo(oracle);
|
||||
* var here = new GeoPoint({lat: 10.32424, lng: 5.84978});
|
||||
|
@ -109,9 +115,9 @@ exports.GeoPoint = GeoPoint;
|
|||
* });
|
||||
* ```
|
||||
* @class GeoPoint
|
||||
* @property {Number} lat The latitude in degrees.
|
||||
* @property {Number} lng The longitude in degrees.
|
||||
*
|
||||
* @property {Number} lat The latitude in degrees.
|
||||
* @property {Number} lng The longitude in degrees.
|
||||
*
|
||||
* @options {Object} Options Object with two Number properties: lat and long.
|
||||
* @property {Number} lat The latitude point in degrees. Range: -90 to 90.
|
||||
* @property {Number} lng The longitude point in degrees. Range: -180 to 180.
|
||||
|
@ -126,23 +132,29 @@ function GeoPoint(data) {
|
|||
return new GeoPoint(data);
|
||||
}
|
||||
|
||||
if(arguments.length === 2) {
|
||||
if (arguments.length === 2) {
|
||||
data = {
|
||||
lat: arguments[0],
|
||||
lng: arguments[1]
|
||||
lng: arguments[1],
|
||||
};
|
||||
}
|
||||
|
||||
assert(Array.isArray(data) || typeof data === 'object' || typeof data === 'string', 'must provide valid geo-coordinates array [lat, lng] or object or a "lat, lng" string');
|
||||
assert(
|
||||
Array.isArray(data) ||
|
||||
typeof data === 'object' ||
|
||||
typeof data === 'string',
|
||||
'must provide valid geo-coordinates array [lat, lng] or object or a ' +
|
||||
'"lat, lng" string');
|
||||
|
||||
if (typeof data === 'string') {
|
||||
data = data.split(/,\s*/);
|
||||
assert(data.length === 2, 'must provide a string "lat,lng" creating a GeoPoint with a string');
|
||||
assert(data.length === 2, 'must provide a string "lat,lng" creating a ' +
|
||||
'GeoPoint with a string');
|
||||
}
|
||||
if (Array.isArray(data)) {
|
||||
data = {
|
||||
lat: Number(data[0]),
|
||||
lng: Number(data[1])
|
||||
lng: Number(data[1]),
|
||||
};
|
||||
} else {
|
||||
data.lng = Number(data.lng);
|
||||
|
@ -157,18 +169,18 @@ function GeoPoint(data) {
|
|||
assert(data.lat <= 90, 'lat must be <= 90');
|
||||
assert(data.lat >= -90, 'lat must be >= -90');
|
||||
|
||||
this.lat = data.lat;
|
||||
this.lat = data.lat;
|
||||
this.lng = data.lng;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the spherical distance between two GeoPoints.
|
||||
*
|
||||
*
|
||||
* @param {GeoPoint} pointA Point A
|
||||
* @param {GeoPoint} pointB Point B
|
||||
* @options {Object} options Options object with one key, 'type'. See below.
|
||||
* @property {String} type Unit of measurement, one of:
|
||||
*
|
||||
*
|
||||
* - `miles` (default)
|
||||
* - `radians`
|
||||
* - `kilometers`
|
||||
|
@ -200,16 +212,16 @@ GeoPoint.distanceBetween = function distanceBetween(a, b, options) {
|
|||
* Example:
|
||||
* ```js
|
||||
* var loopback = require(‘loopback’);
|
||||
*
|
||||
*
|
||||
* var here = new loopback.GeoPoint({lat: 10, lng: 10});
|
||||
* var there = new loopback.GeoPoint({lat: 5, lng: 5});
|
||||
*
|
||||
*
|
||||
* loopback.GeoPoint.distanceBetween(here, there, {type: 'miles'}) // 438
|
||||
* ```
|
||||
* @param {Object} point GeoPoint object to which to measure distance.
|
||||
* @options {Object} options Options object with one key, 'type'. See below.
|
||||
* @property {String} type Unit of measurement, one of:
|
||||
*
|
||||
*
|
||||
* - `miles` (default)
|
||||
* - `radians`
|
||||
* - `kilometers`
|
||||
|
@ -219,7 +231,7 @@ GeoPoint.distanceBetween = function distanceBetween(a, b, options) {
|
|||
* - `degrees`
|
||||
*/
|
||||
|
||||
GeoPoint.prototype.distanceTo = function (point, options) {
|
||||
GeoPoint.prototype.distanceTo = function(point, options) {
|
||||
return GeoPoint.distanceBetween(this, point, options);
|
||||
};
|
||||
|
||||
|
@ -227,7 +239,7 @@ GeoPoint.prototype.distanceTo = function (point, options) {
|
|||
* Simple serialization.
|
||||
*/
|
||||
|
||||
GeoPoint.prototype.toString = function () {
|
||||
GeoPoint.prototype.toString = function() {
|
||||
return this.lat + ',' + this.lng;
|
||||
};
|
||||
|
||||
|
@ -250,11 +262,10 @@ var EARTH_RADIUS = {
|
|||
miles: 3958.75,
|
||||
feet: 20902200,
|
||||
radians: 1,
|
||||
degrees: RAD2DEG
|
||||
degrees: RAD2DEG,
|
||||
};
|
||||
|
||||
function geoDistance(x1, y1, x2, y2, options) {
|
||||
|
||||
var type = (options && options.type) || 'miles';
|
||||
|
||||
// Convert to radians
|
||||
|
@ -263,7 +274,7 @@ function geoDistance(x1, y1, x2, y2, options) {
|
|||
x2 = x2 * DEG2RAD;
|
||||
y2 = y2 * DEG2RAD;
|
||||
|
||||
// use the haversine formula to calculate distance for any 2 points on a sphere.
|
||||
// use the haversine formula to calculate distance for any 2 points on a sphere.
|
||||
// ref http://en.wikipedia.org/wiki/Haversine_formula
|
||||
var haversine = function(a) {
|
||||
return Math.pow(Math.sin(a / 2.0), 2);
|
||||
|
|
21
lib/hooks.js
21
lib/hooks.js
|
@ -1,4 +1,11 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var deprecated = require('depd')('loopback-datasource-juggler');
|
||||
var g = require('strong-globalize')();
|
||||
|
||||
/*!
|
||||
* Module exports
|
||||
|
@ -31,10 +38,10 @@ Hookable.afterDestroy = null;
|
|||
// TODO: Evaluate https://github.com/bnoguchi/hooks-js/
|
||||
Hookable.prototype.trigger = function trigger(actionName, work, data, callback) {
|
||||
var capitalizedName = capitalize(actionName);
|
||||
var beforeHook = this.constructor["before" + capitalizedName]
|
||||
|| this.constructor["pre" + capitalizedName];
|
||||
var afterHook = this.constructor["after" + capitalizedName]
|
||||
|| this.constructor["post" + capitalizedName];
|
||||
var beforeHook = this.constructor['before' + capitalizedName] ||
|
||||
this.constructor['pre' + capitalizedName];
|
||||
var afterHook = this.constructor['after' + capitalizedName] ||
|
||||
this.constructor['post' + capitalizedName];
|
||||
if (actionName === 'validate') {
|
||||
beforeHook = beforeHook || this.constructor.beforeValidation;
|
||||
afterHook = afterHook || this.constructor.afterValidation;
|
||||
|
@ -52,7 +59,7 @@ Hookable.prototype.trigger = function trigger(actionName, work, data, callback)
|
|||
if (work) {
|
||||
if (beforeHook) {
|
||||
// before hook should be called on instance with two parameters: next and data
|
||||
beforeHook.call(inst, function () {
|
||||
beforeHook.call(inst, function() {
|
||||
// Check arguments to next(err, result)
|
||||
if (arguments.length) {
|
||||
return callback && callback.apply(null, arguments);
|
||||
|
@ -89,7 +96,7 @@ function deprecateHook(ctor, prefixes, capitalizedName) {
|
|||
var hookName = candidateNames.filter(function(hook) { return !!ctor[hook]; })[0];
|
||||
if (!hookName) return; // just to be sure, this should never happen
|
||||
if (ctor.modelName) hookName = ctor.modelName + '.' + hookName;
|
||||
deprecated('Model hook "' + hookName + '" is deprecated, ' +
|
||||
deprecated(g.f('Model hook "%s" is deprecated, ' +
|
||||
'use Operation hooks instead. ' +
|
||||
'http://docs.strongloop.com/display/LB/Operation+hooks');
|
||||
'{{http://docs.strongloop.com/display/LB/Operation+hooks}}', hookName));
|
||||
}
|
||||
|
|
105
lib/include.js
105
lib/include.js
|
@ -1,10 +1,18 @@
|
|||
// Copyright IBM Corp. 2013,2015. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var async = require('async');
|
||||
var g = require('strong-globalize')();
|
||||
var utils = require('./utils');
|
||||
var List = require('./list');
|
||||
var includeUtils = require('./include_utils');
|
||||
var isPlainObject = utils.isPlainObject;
|
||||
var defineCachedRelations = utils.defineCachedRelations;
|
||||
var uniq = utils.uniq;
|
||||
var idName = utils.idName;
|
||||
|
||||
/*!
|
||||
* Normalize the include to be an array
|
||||
|
@ -60,15 +68,6 @@ IncludeScope.prototype.include = function() {
|
|||
return this._include;
|
||||
};
|
||||
|
||||
/**
|
||||
* Find the idKey of a Model.
|
||||
* @param {ModelConstructor} m - Model Constructor
|
||||
* @returns {String}
|
||||
*/
|
||||
function idName(m) {
|
||||
return m.definition.idName() || 'id';
|
||||
}
|
||||
|
||||
/*!
|
||||
* Look up a model by name from the list of given models
|
||||
* @param {Object} models Models keyed by name
|
||||
|
@ -95,11 +94,11 @@ function lookupModel(models, modelName) {
|
|||
function execTasksWithInterLeave(tasks, callback) {
|
||||
//let's give others some time to process.
|
||||
//Context Switch BEFORE Heavy Computation
|
||||
process.nextTick(function () {
|
||||
process.nextTick(function() {
|
||||
//Heavy Computation
|
||||
async.parallel(tasks, function (err, info) {
|
||||
async.parallel(tasks, function(err, info) {
|
||||
//Context Switch AFTER Heavy Computation
|
||||
process.nextTick(function () {
|
||||
process.nextTick(function() {
|
||||
callback(err, info);
|
||||
});
|
||||
});
|
||||
|
@ -151,7 +150,7 @@ Inclusion.normalizeInclude = normalizeInclude;
|
|||
* @param {Function} cb Callback called when relations are loaded
|
||||
*
|
||||
*/
|
||||
Inclusion.include = function (objects, include, options, cb) {
|
||||
Inclusion.include = function(objects, include, options, cb) {
|
||||
if (typeof options === 'function' && cb === undefined) {
|
||||
cb = options;
|
||||
options = {};
|
||||
|
@ -193,16 +192,14 @@ Inclusion.include = function (objects, include, options, cb) {
|
|||
subInclude = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
relationName = include;
|
||||
subInclude = null;
|
||||
}
|
||||
|
||||
var relation = relations[relationName];
|
||||
if (!relation) {
|
||||
cb(new Error('Relation "' + relationName + '" is not defined for '
|
||||
+ self.modelName + ' model'));
|
||||
cb(new Error(g.f('Relation "%s" is not defined for %s model', relationName, self.modelName)));
|
||||
return;
|
||||
}
|
||||
var polymorphic = relation.polymorphic;
|
||||
|
@ -213,8 +210,8 @@ Inclusion.include = function (objects, include, options, cb) {
|
|||
//}
|
||||
if (!relation.modelTo) {
|
||||
if (!relation.polymorphic) {
|
||||
cb(new Error('Relation.modelTo is not defined for relation' +
|
||||
relationName + ' and is no polymorphic'));
|
||||
cb(new Error(g.f('{{Relation.modelTo}} is not defined for relation %s and is no {{polymorphic}}',
|
||||
relationName)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -231,7 +228,7 @@ Inclusion.include = function (objects, include, options, cb) {
|
|||
if (filter.fields && Array.isArray(subInclude) &&
|
||||
relation.modelTo.relations) {
|
||||
includeScope.fields = [];
|
||||
subInclude.forEach(function (name) {
|
||||
subInclude.forEach(function(name) {
|
||||
var rel = relation.modelTo.relations[name];
|
||||
if (rel && rel.type === 'belongsTo') {
|
||||
includeScope.fields.push(rel.keyFrom);
|
||||
|
@ -246,8 +243,7 @@ Inclusion.include = function (objects, include, options, cb) {
|
|||
var fields = filter.fields;
|
||||
if (Array.isArray(fields) && fields.indexOf(relation.keyTo) === -1) {
|
||||
fields.push(relation.keyTo);
|
||||
}
|
||||
else if (isPlainObject(fields) && !fields[relation.keyTo]) {
|
||||
} else if (isPlainObject(fields) && !fields[relation.keyTo]) {
|
||||
fields[relation.keyTo] = true;
|
||||
}
|
||||
|
||||
|
@ -271,13 +267,12 @@ Inclusion.include = function (objects, include, options, cb) {
|
|||
}
|
||||
|
||||
//This handles exactly hasMany. Fast and straightforward. Without parallel, each and other boilerplate.
|
||||
if(relation.type === 'hasMany' && relation.multiple && !subInclude){
|
||||
if (relation.type === 'hasMany' && relation.multiple && !subInclude) {
|
||||
return includeHasManySimple(cb);
|
||||
}
|
||||
//assuming all other relations with multiple=true as hasMany
|
||||
return includeHasMany(cb);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (polymorphic) {
|
||||
if (relation.type === 'hasOne') {
|
||||
return includePolymorphicHasOne(cb);
|
||||
|
@ -316,16 +311,20 @@ Inclusion.include = function (objects, include, options, cb) {
|
|||
//default filters are not applicable on through model. should be applied
|
||||
//on modelTo later in 2nd DB call.
|
||||
var throughFilter = {
|
||||
where: {}
|
||||
where: {},
|
||||
};
|
||||
throughFilter.where[relation.keyTo] = {
|
||||
inq: uniq(sourceIds)
|
||||
inq: uniq(sourceIds),
|
||||
};
|
||||
if (polymorphic) {
|
||||
var throughModel = polymorphic.invert ?
|
||||
relation.modelTo :
|
||||
relation.modelFrom;
|
||||
|
||||
//handle polymorphic hasMany (reverse) in which case we need to filter
|
||||
//by discriminator to filter other types
|
||||
throughFilter.where[polymorphic.discriminator] =
|
||||
relation.modelFrom.definition.name;
|
||||
throughModel.definition.name;
|
||||
}
|
||||
/**
|
||||
* 1st DB Call of 2 step process. Get through model objects first
|
||||
|
@ -362,14 +361,13 @@ Inclusion.include = function (objects, include, options, cb) {
|
|||
//Polymorphic relation does not have idKey of modelTo. Find it manually
|
||||
var modelToIdName = idName(relation.modelTo);
|
||||
filter.where[modelToIdName] = {
|
||||
inq: uniq(targetIds)
|
||||
inq: uniq(targetIds),
|
||||
};
|
||||
|
||||
//make sure that the modelToIdName is included if fields are specified
|
||||
if (Array.isArray(fields) && fields.indexOf(modelToIdName) === -1) {
|
||||
fields.push(modelToIdName);
|
||||
}
|
||||
else if (isPlainObject(fields) && !fields[modelToIdName]) {
|
||||
} else if (isPlainObject(fields) && !fields[modelToIdName]) {
|
||||
fields[modelToIdName] = true;
|
||||
}
|
||||
|
||||
|
@ -396,7 +394,7 @@ Inclusion.include = function (objects, include, options, cb) {
|
|||
function linkManyToMany(target, next) {
|
||||
var targetId = target[modelToIdName];
|
||||
var objList = targetObjsMap[targetId.toString()];
|
||||
async.each(objList, function (obj, next) {
|
||||
async.each(objList, function(obj, next) {
|
||||
if (!obj) return next();
|
||||
obj.__cachedRelations[relationName].push(target);
|
||||
processTargetObj(obj, next);
|
||||
|
@ -445,7 +443,7 @@ Inclusion.include = function (objects, include, options, cb) {
|
|||
obj.__cachedRelations[relationName] = [];
|
||||
}
|
||||
filter.where[relation.keyTo] = {
|
||||
inq: uniq(allTargetIds)
|
||||
inq: uniq(allTargetIds),
|
||||
};
|
||||
relation.applyScope(null, filter);
|
||||
/**
|
||||
|
@ -476,12 +474,11 @@ Inclusion.include = function (objects, include, options, cb) {
|
|||
async.each(targets, linkManyToMany, next);
|
||||
function linkManyToMany(target, next) {
|
||||
var objList = targetObjsMap[target[relation.keyTo].toString()];
|
||||
async.each(objList, function (obj, next) {
|
||||
async.each(objList, function(obj, next) {
|
||||
if (!obj) return next();
|
||||
obj.__cachedRelations[relationName].push(target);
|
||||
processTargetObj(obj, next);
|
||||
}, next);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -498,21 +495,21 @@ Inclusion.include = function (objects, include, options, cb) {
|
|||
var objIdMap2 = includeUtils.buildOneToOneIdentityMapWithOrigKeys(objs, relation.keyFrom);
|
||||
|
||||
filter.where[relation.keyTo] = {
|
||||
inq: uniq(objIdMap2.getKeys())
|
||||
inq: uniq(objIdMap2.getKeys()),
|
||||
};
|
||||
|
||||
relation.applyScope(null, filter);
|
||||
relation.modelTo.find(filter, options, targetFetchHandler);
|
||||
|
||||
function targetFetchHandler(err, targets) {
|
||||
if(err) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
var targetsIdMap = includeUtils.buildOneToManyIdentityMapWithOrigKeys(targets, relation.keyTo);
|
||||
includeUtils.join(objIdMap2, targetsIdMap, function(obj1, valueToMergeIn){
|
||||
includeUtils.join(objIdMap2, targetsIdMap, function(obj1, valueToMergeIn) {
|
||||
defineCachedRelations(obj1);
|
||||
obj1.__cachedRelations[relationName] = valueToMergeIn;
|
||||
processTargetObj(obj1, function(){});
|
||||
processTargetObj(obj1, function() {});
|
||||
});
|
||||
callback(err, objs);
|
||||
}
|
||||
|
@ -540,7 +537,7 @@ Inclusion.include = function (objects, include, options, cb) {
|
|||
obj.__cachedRelations[relationName] = [];
|
||||
}
|
||||
filter.where[relation.keyTo] = {
|
||||
inq: uniq(sourceIds)
|
||||
inq: uniq(sourceIds),
|
||||
};
|
||||
relation.applyScope(null, filter);
|
||||
options.partitionBy = relation.keyTo;
|
||||
|
@ -575,7 +572,7 @@ Inclusion.include = function (objects, include, options, cb) {
|
|||
function linkManyToOne(target, next) {
|
||||
//fix for bug in hasMany with referencesMany
|
||||
var targetIds = [].concat(target[relation.keyTo]);
|
||||
async.each(targetIds, function (targetId, next) {
|
||||
async.each(targetIds, function(targetId, next) {
|
||||
var obj = objIdMap[targetId.toString()];
|
||||
if (!obj) return next();
|
||||
obj.__cachedRelations[relationName].push(target);
|
||||
|
@ -643,13 +640,13 @@ Inclusion.include = function (objects, include, options, cb) {
|
|||
utils.mergeQuery(typeFilter, filter);
|
||||
var targetIds = targetIdsByType[modelType];
|
||||
typeFilter.where[relation.keyTo] = {
|
||||
inq: uniq(targetIds)
|
||||
inq: uniq(targetIds),
|
||||
};
|
||||
var Model = lookupModel(relation.modelFrom.dataSource.modelBuilder.
|
||||
models, modelType);
|
||||
if (!Model) {
|
||||
callback(new Error('Discriminator type "' + modelType +
|
||||
' specified but no model exists with such name'));
|
||||
callback(new Error(g.f('Discriminator type %s specified but no model exists with such name',
|
||||
modelType)));
|
||||
return;
|
||||
}
|
||||
relation.applyScope(null, typeFilter);
|
||||
|
@ -679,7 +676,8 @@ Inclusion.include = function (objects, include, options, cb) {
|
|||
async.each(targets, linkOneToMany, next);
|
||||
function linkOneToMany(target, next) {
|
||||
var objList = targetObjsMap[target[relation.keyTo].toString()];
|
||||
async.each(objList, function (obj, next) {
|
||||
if (!objList) return next();
|
||||
async.each(objList, function(obj, next) {
|
||||
if (!obj) return next();
|
||||
obj.__cachedRelations[relationName] = target;
|
||||
processTargetObj(obj, next);
|
||||
|
@ -692,7 +690,6 @@ Inclusion.include = function (objects, include, options, cb) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle Inclusion of Polymorphic HasOne relation
|
||||
* @param callback
|
||||
|
@ -715,7 +712,7 @@ Inclusion.include = function (objects, include, options, cb) {
|
|||
obj.__cachedRelations[relationName] = null;
|
||||
}
|
||||
filter.where[relation.keyTo] = {
|
||||
inq: uniq(sourceIds)
|
||||
inq: uniq(sourceIds),
|
||||
};
|
||||
relation.applyScope(null, filter);
|
||||
relation.modelTo.find(filter, options, targetFetchHandler);
|
||||
|
@ -782,7 +779,7 @@ Inclusion.include = function (objects, include, options, cb) {
|
|||
obj.__cachedRelations[relationName] = null;
|
||||
}
|
||||
filter.where[relation.keyTo] = {
|
||||
inq: uniq(targetIds)
|
||||
inq: uniq(targetIds),
|
||||
};
|
||||
relation.applyScope(null, filter);
|
||||
relation.modelTo.find(filter, options, targetFetchHandler);
|
||||
|
@ -810,7 +807,8 @@ Inclusion.include = function (objects, include, options, cb) {
|
|||
function linkOneToMany(target, next) {
|
||||
var targetId = target[relation.keyTo];
|
||||
var objList = objTargetIdMap[targetId.toString()];
|
||||
async.each(objList, function (obj, next) {
|
||||
if (!objList) return next();
|
||||
async.each(objList, function(obj, next) {
|
||||
if (!obj) return next();
|
||||
obj.__cachedRelations[relationName] = target;
|
||||
processTargetObj(obj, next);
|
||||
|
@ -822,7 +820,6 @@ Inclusion.include = function (objects, include, options, cb) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle Inclusion of EmbedsMany/EmbedsManyWithBelongsTo/EmbedsOne
|
||||
* Relations. Since Embedded docs are part of parents, no need to make
|
||||
|
@ -833,7 +830,7 @@ Inclusion.include = function (objects, include, options, cb) {
|
|||
* @param callback
|
||||
*/
|
||||
function includeEmbeds(callback) {
|
||||
async.each(objs, function (obj, next) {
|
||||
async.each(objs, function(obj, next) {
|
||||
processTargetObj(obj, next);
|
||||
}, callback);
|
||||
}
|
||||
|
@ -845,7 +842,6 @@ Inclusion.include = function (objects, include, options, cb) {
|
|||
* @returns {*}
|
||||
*/
|
||||
function processTargetObj(obj, callback) {
|
||||
|
||||
var isInst = obj instanceof self;
|
||||
|
||||
// Calling the relation method on the instance
|
||||
|
@ -916,11 +912,10 @@ Inclusion.include = function (objects, include, options, cb) {
|
|||
related = inst[relationName].bind(inst, undefined);
|
||||
}
|
||||
|
||||
related(options, function (err, result) {
|
||||
related(options, function(err, result) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
} else {
|
||||
|
||||
defineCachedRelations(obj);
|
||||
obj.__cachedRelations[relationName] = result;
|
||||
|
||||
|
@ -928,7 +923,5 @@ Inclusion.include = function (objects, include, options, cb) {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
// Copyright IBM Corp. 2015,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
module.exports.buildOneToOneIdentityMapWithOrigKeys = buildOneToOneIdentityMapWithOrigKeys;
|
||||
module.exports.buildOneToManyIdentityMapWithOrigKeys = buildOneToManyIdentityMapWithOrigKeys;
|
||||
module.exports.join = join;
|
||||
|
@ -13,7 +19,7 @@ module.exports.KVMap = KVMap;
|
|||
*/
|
||||
function buildOneToOneIdentityMapWithOrigKeys(objs, idName) {
|
||||
var kvMap = new KVMap();
|
||||
for(var i = 0; i < objs.length; i++) {
|
||||
for (var i = 0; i < objs.length; i++) {
|
||||
var obj = objs[i];
|
||||
var id = obj[idName];
|
||||
kvMap.set(id, obj);
|
||||
|
@ -23,7 +29,7 @@ function buildOneToOneIdentityMapWithOrigKeys(objs, idName) {
|
|||
|
||||
function buildOneToManyIdentityMapWithOrigKeys(objs, idName) {
|
||||
var kvMap = new KVMap();
|
||||
for(var i = 0; i < objs.length; i++) {
|
||||
for (var i = 0; i < objs.length; i++) {
|
||||
var obj = objs[i];
|
||||
var id = obj[idName];
|
||||
var value = kvMap.get(id) || [];
|
||||
|
@ -33,7 +39,6 @@ function buildOneToManyIdentityMapWithOrigKeys(objs, idName) {
|
|||
return kvMap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Yeah, it joins. You need three things id -> obj1 map, id -> [obj2] map and merge function.
|
||||
* This functions will take each obj1, locate all data to join in map2 and call merge function.
|
||||
|
@ -43,7 +48,7 @@ function buildOneToManyIdentityMapWithOrigKeys(objs, idName) {
|
|||
*/
|
||||
function join(oneToOneIdMap, oneToManyIdMap, mergeF) {
|
||||
var ids = oneToOneIdMap.getKeys();
|
||||
for(var i = 0; i < ids.length; i++) {
|
||||
for (var i = 0; i < ids.length; i++) {
|
||||
var id = ids[i];
|
||||
var obj = oneToOneIdMap.get(id);
|
||||
var objectsToMergeIn = oneToManyIdMap.get(id) || [];
|
||||
|
@ -51,34 +56,33 @@ function join(oneToOneIdMap, oneToManyIdMap, mergeF) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Map with arbitrary keys and values. User .set() and .get() to work with values instead of []
|
||||
* @returns {{set: Function, get: Function, remove: Function, exist: Function, getKeys: Function}}
|
||||
* @constructor
|
||||
*/
|
||||
function KVMap(){
|
||||
function KVMap() {
|
||||
var _originalKeyFieldName = 'originalKey';
|
||||
var _valueKeyFieldName = 'value';
|
||||
var _dict = {};
|
||||
var keyToString = function(key){ return key.toString() };
|
||||
var keyToString = function(key) { return key.toString(); };
|
||||
var mapImpl = {
|
||||
set: function(key, value){
|
||||
set: function(key, value) {
|
||||
var recordObj = {};
|
||||
recordObj[_originalKeyFieldName] = key;
|
||||
recordObj[_valueKeyFieldName] = value;
|
||||
_dict[keyToString(key)] = recordObj;
|
||||
return true;
|
||||
},
|
||||
get: function(key){
|
||||
get: function(key) {
|
||||
var storeObj = _dict[keyToString(key)];
|
||||
if(storeObj) {
|
||||
if (storeObj) {
|
||||
return storeObj[_valueKeyFieldName];
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
remove: function(key){
|
||||
remove: function(key) {
|
||||
delete _dict[keyToString(key)];
|
||||
return true;
|
||||
},
|
||||
|
@ -86,13 +90,13 @@ function KVMap(){
|
|||
var result = _dict.hasOwnProperty(keyToString(key));
|
||||
return result;
|
||||
},
|
||||
getKeys: function(){
|
||||
getKeys: function() {
|
||||
var result = [];
|
||||
for(var key in _dict) {
|
||||
for (var key in _dict) {
|
||||
result.push(_dict[key][_originalKeyFieldName]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
},
|
||||
|
||||
};
|
||||
return mapImpl;
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
module.exports = function getIntrospector(ModelBuilder) {
|
||||
|
||||
function introspectType(value) {
|
||||
|
||||
// Unknown type, using Any
|
||||
if (value === null || value === undefined) {
|
||||
return ModelBuilder.Any;
|
||||
|
@ -57,6 +61,4 @@ module.exports = function getIntrospector(ModelBuilder) {
|
|||
|
||||
ModelBuilder.introspect = introspectType;
|
||||
return introspectType;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
|
22
lib/jutil.js
22
lib/jutil.js
|
@ -1,3 +1,9 @@
|
|||
// Copyright IBM Corp. 2011,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
/**
|
||||
|
@ -5,18 +11,18 @@ var util = require('util');
|
|||
* @param newClass
|
||||
* @param baseClass
|
||||
*/
|
||||
exports.inherits = function (newClass, baseClass, options) {
|
||||
exports.inherits = function(newClass, baseClass, options) {
|
||||
util.inherits(newClass, baseClass);
|
||||
|
||||
options = options || {
|
||||
staticProperties: true,
|
||||
override: false
|
||||
override: false,
|
||||
};
|
||||
|
||||
if (options.staticProperties) {
|
||||
Object.keys(baseClass).forEach(function (classProp) {
|
||||
if (classProp !== 'super_' && (!newClass.hasOwnProperty(classProp)
|
||||
|| options.override)) {
|
||||
Object.keys(baseClass).forEach(function(classProp) {
|
||||
if (classProp !== 'super_' && (!newClass.hasOwnProperty(classProp) ||
|
||||
options.override)) {
|
||||
var pd = Object.getOwnPropertyDescriptor(baseClass, classProp);
|
||||
Object.defineProperty(newClass, classProp, pd);
|
||||
}
|
||||
|
@ -30,7 +36,7 @@ exports.inherits = function (newClass, baseClass, options) {
|
|||
* @param mixinClass The class to be mixed in
|
||||
* @param options
|
||||
*/
|
||||
exports.mixin = function (newClass, mixinClass, options) {
|
||||
exports.mixin = function(newClass, mixinClass, options) {
|
||||
if (Array.isArray(newClass._mixins)) {
|
||||
if (newClass._mixins.indexOf(mixinClass) !== -1) {
|
||||
return;
|
||||
|
@ -44,7 +50,7 @@ exports.mixin = function (newClass, mixinClass, options) {
|
|||
staticProperties: true,
|
||||
instanceProperties: true,
|
||||
override: false,
|
||||
proxyFunctions: false
|
||||
proxyFunctions: false,
|
||||
};
|
||||
|
||||
if (options.staticProperties === undefined) {
|
||||
|
@ -67,7 +73,7 @@ exports.mixin = function (newClass, mixinClass, options) {
|
|||
};
|
||||
|
||||
function mixInto(sourceScope, targetScope, options) {
|
||||
Object.keys(sourceScope).forEach(function (propertyName) {
|
||||
Object.keys(sourceScope).forEach(function(propertyName) {
|
||||
var targetPropertyExists = targetScope.hasOwnProperty(propertyName);
|
||||
var sourceProperty = Object.getOwnPropertyDescriptor(sourceScope, propertyName);
|
||||
var targetProperty = targetPropertyExists && Object.getOwnPropertyDescriptor(targetScope, propertyName);
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
'use strict';
|
||||
|
||||
var assert = require('assert');
|
||||
var utils = require('../utils');
|
||||
|
||||
/**
|
||||
* Set the TTL (time to live) in ms (milliseconds) for a given key. TTL is the
|
||||
* remaining time before a key-value pair is discarded from the database.
|
||||
*
|
||||
* @param {String} key Key to use when searching the database.
|
||||
* @param {Number} ttl TTL in ms to set for the key.
|
||||
* @options {Object} options
|
||||
* @callback {Function} callback
|
||||
* @param {Error} err Error object.
|
||||
* @promise
|
||||
*
|
||||
* @header KVAO.expire(key, ttl, cb)
|
||||
*/
|
||||
module.exports = function keyValueExpire(key, ttl, options, callback) {
|
||||
if (callback == undefined && typeof options === 'function') {
|
||||
callback = options;
|
||||
options = {};
|
||||
} else if (!options) {
|
||||
options = {};
|
||||
}
|
||||
|
||||
assert(typeof key === 'string' && key, 'key must be a non-empty string');
|
||||
assert(typeof ttl === 'number' && ttl > 0, 'ttl must be a positive integer');
|
||||
assert(typeof options === 'object', 'options must be an object');
|
||||
|
||||
callback = callback || utils.createPromiseCallback();
|
||||
this.getConnector().expire(this.modelName, key, ttl, options, callback);
|
||||
return callback.promise;
|
||||
};
|
|
@ -0,0 +1,34 @@
|
|||
'use strict';
|
||||
|
||||
var assert = require('assert');
|
||||
var utils = require('../utils');
|
||||
|
||||
/**
|
||||
* Return the value associated with a given key.
|
||||
*
|
||||
* @param {String} key Key to use when searching the database.
|
||||
* @options {Object} options
|
||||
* @callback {Function} callback
|
||||
* @param {Error} err Error object.
|
||||
* @param {*} result Value associated with the given key.
|
||||
* @promise
|
||||
*
|
||||
* @header KVAO.get(key, cb)
|
||||
*/
|
||||
module.exports = function keyValueGet(key, options, callback) {
|
||||
if (callback == undefined && typeof options === 'function') {
|
||||
callback = options;
|
||||
options = {};
|
||||
} else if (!options) {
|
||||
options = {};
|
||||
}
|
||||
|
||||
assert(typeof key === 'string' && key, 'key must be a non-empty string');
|
||||
|
||||
callback = callback || utils.createPromiseCallback();
|
||||
this.getConnector().get(this.modelName, key, options, function(err, result) {
|
||||
// TODO convert raw result to Model instance (?)
|
||||
callback(err, result);
|
||||
});
|
||||
return callback.promise;
|
||||
};
|
|
@ -0,0 +1,18 @@
|
|||
'use strict';
|
||||
|
||||
function KeyValueAccessObject() {
|
||||
};
|
||||
|
||||
module.exports = KeyValueAccessObject;
|
||||
|
||||
KeyValueAccessObject.get = require('./get');
|
||||
KeyValueAccessObject.set = require('./set');
|
||||
KeyValueAccessObject.expire = require('./expire');
|
||||
KeyValueAccessObject.ttl = require('./ttl');
|
||||
KeyValueAccessObject.iterateKeys = require('./iterate-keys');
|
||||
KeyValueAccessObject.keys = require('./keys');
|
||||
|
||||
KeyValueAccessObject.getConnector = function() {
|
||||
return this.getDataSource().connector;
|
||||
};
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
'use strict';
|
||||
|
||||
var assert = require('assert');
|
||||
var utils = require('../utils');
|
||||
|
||||
/**
|
||||
* Asynchronously iterate all keys in the database. Similar to `.keys()` but
|
||||
* instead allows for iteration over large data sets without having to load
|
||||
* everything into memory at once.
|
||||
*
|
||||
* @param {Object} filter An optional filter object with the following
|
||||
* @param {String} filter.match Glob string to use to filter returned
|
||||
* keys (i.e. `userid.*`). All connectors are required to support `*` and
|
||||
* `?`. They may also support additional special characters that are
|
||||
* specific to the backing database.
|
||||
* @param {Object} options
|
||||
* @returns {AsyncIterator} An Object implementing `next(cb) -> Promise`
|
||||
* function that can be used to iterate all keys.
|
||||
*
|
||||
* @header KVAO.iterateKeys(filter)
|
||||
*/
|
||||
module.exports = function keyValueIterateKeys(filter, options) {
|
||||
filter = filter || {};
|
||||
options = options || {};
|
||||
|
||||
assert(typeof filter === 'object', 'filter must be an object');
|
||||
assert(typeof options === 'object', 'options must be an object');
|
||||
|
||||
var iter = this.getConnector().iterateKeys(this.modelName, filter, options);
|
||||
// promisify the returned iterator
|
||||
return {
|
||||
next: function(callback) {
|
||||
callback = callback || utils.createPromiseCallback();
|
||||
iter.next(callback);
|
||||
return callback.promise;
|
||||
},
|
||||
};
|
||||
};
|
|
@ -0,0 +1,56 @@
|
|||
'use strict';
|
||||
|
||||
var assert = require('assert');
|
||||
var utils = require('../utils');
|
||||
|
||||
/**
|
||||
* Return all keys in the database.
|
||||
*
|
||||
* **WARNING**: This method is not suitable for large data sets as all
|
||||
* key-values pairs are loaded into memory at once. For large data sets,
|
||||
* use `iterateKeys()` instead.
|
||||
*
|
||||
* @param {Object} filter An optional filter object with the following
|
||||
* @param {String} filter.match Glob string used to filter returned
|
||||
* keys (i.e. `userid.*`). All connectors are required to support `*` and
|
||||
* `?`, but may also support additional special characters specific to the
|
||||
* database.
|
||||
* @param {Object} options
|
||||
* @callback {Function} callback
|
||||
* @promise
|
||||
*
|
||||
*
|
||||
* @header KVAO.keys(filter, callback)
|
||||
*/
|
||||
module.exports = function keyValueKeys(filter, options, callback) {
|
||||
if (callback === undefined) {
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
} else if (options === undefined && typeof filter === 'function') {
|
||||
callback = filter;
|
||||
filter = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
filter = filter || {};
|
||||
options = options || {};
|
||||
|
||||
assert(typeof filter === 'object', 'filter must be an object');
|
||||
assert(typeof options === 'object', 'options must be an object');
|
||||
|
||||
callback = callback || utils.createPromiseCallback();
|
||||
|
||||
var iter = this.iterateKeys(filter, options);
|
||||
var keys = [];
|
||||
iter.next(onNextKey);
|
||||
|
||||
function onNextKey(err, key) {
|
||||
if (err) return callback(err);
|
||||
if (key === undefined) return callback(null, keys);
|
||||
keys.push(key);
|
||||
iter.next(onNextKey);
|
||||
}
|
||||
|
||||
return callback.promise;
|
||||
};
|
|
@ -0,0 +1,44 @@
|
|||
'use strict';
|
||||
|
||||
var assert = require('assert');
|
||||
var utils = require('../utils');
|
||||
|
||||
/**
|
||||
* Persist a value and associate it with the given key.
|
||||
*
|
||||
* @param {String} key Key to associate with the given value.
|
||||
* @param {*} value Value to persist.
|
||||
* @options {Number|Object} options Optional settings for the key-value
|
||||
* pair. If a Number is provided, it is set as the TTL (time to live) in ms
|
||||
* (milliseconds) for the key-value pair.
|
||||
* @property {Number} ttl TTL for the key-value pair in ms.
|
||||
* @callback {Function} callback
|
||||
* @param {Error} err Error object.
|
||||
* @promise
|
||||
*
|
||||
* @header KVAO.set(key, value, cb)
|
||||
*/
|
||||
module.exports = function keyValueSet(key, value, options, callback) {
|
||||
if (callback == undefined && typeof options === 'function') {
|
||||
callback = options;
|
||||
options = {};
|
||||
} else if (typeof options === 'number') {
|
||||
options = {ttl: options};
|
||||
} else if (!options) {
|
||||
options = {};
|
||||
}
|
||||
|
||||
assert(typeof key === 'string' && key, 'key must be a non-empty string');
|
||||
assert(value != null, 'value must be defined and not null');
|
||||
assert(typeof options === 'object', 'options must be an object');
|
||||
if (options && 'ttl' in options) {
|
||||
assert(typeof options.ttl === 'number' && options.ttl > 0,
|
||||
'options.ttl must be a positive number');
|
||||
}
|
||||
|
||||
callback = callback || utils.createPromiseCallback();
|
||||
|
||||
// TODO convert possible model instance in "value" to raw data via toObect()
|
||||
this.getConnector().set(this.modelName, key, value, options, callback);
|
||||
return callback.promise;
|
||||
};
|
|
@ -0,0 +1,34 @@
|
|||
'use strict';
|
||||
|
||||
var assert = require('assert');
|
||||
var utils = require('../utils');
|
||||
|
||||
/**
|
||||
* Return the TTL (time to live) for a given key. TTL is the remaining time
|
||||
* before a key-value pair is discarded from the database.
|
||||
*
|
||||
* @param {String} key Key to use when searching the database.
|
||||
* @options {Object} options
|
||||
* @callback {Function} callback
|
||||
* @param {Error} error
|
||||
* @param {Number} ttl Expiration time for the key-value pair. `undefined` if
|
||||
* TTL was not initially set.
|
||||
* @promise
|
||||
*
|
||||
* @header KVAO.ttl(key, cb)
|
||||
*/
|
||||
module.exports = function keyValueTtl(key, options, callback) {
|
||||
if (callback == undefined && typeof options === 'function') {
|
||||
callback = options;
|
||||
options = {};
|
||||
} else if (!options) {
|
||||
options = {};
|
||||
}
|
||||
|
||||
assert(typeof key === 'string' && key, 'key must be a non-empty string');
|
||||
assert(typeof options === 'object', 'options must be an object');
|
||||
|
||||
callback = callback || utils.createPromiseCallback();
|
||||
this.getConnector().ttl(this.modelName, key, options, callback);
|
||||
return callback.promise;
|
||||
};
|
31
lib/list.js
31
lib/list.js
|
@ -1,3 +1,10 @@
|
|||
// Copyright IBM Corp. 2012,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var g = require('strong-globalize')();
|
||||
var util = require('util');
|
||||
var Any = require('./types').Types.Any;
|
||||
|
||||
|
@ -13,7 +20,7 @@ function List(items, itemType, parent) {
|
|||
try {
|
||||
items = JSON.parse(items);
|
||||
} catch (e) {
|
||||
var err = new Error(util.format('could not create List from JSON string: %j', items));
|
||||
var err = new Error(g.f('could not create List from JSON string: %j', items));
|
||||
err.statusCode = 400;
|
||||
throw err;
|
||||
}
|
||||
|
@ -24,12 +31,12 @@ function List(items, itemType, parent) {
|
|||
|
||||
items = items || [];
|
||||
if (!Array.isArray(items)) {
|
||||
var err = new Error(util.format('Items must be an array: %j', items));
|
||||
var err = new Error(g.f('Items must be an array: %j', items));
|
||||
err.statusCode = 400;
|
||||
throw err;
|
||||
}
|
||||
|
||||
if(!itemType) {
|
||||
if (!itemType) {
|
||||
itemType = items[0] && items[0].constructor;
|
||||
}
|
||||
|
||||
|
@ -37,25 +44,25 @@ function List(items, itemType, parent) {
|
|||
itemType = itemType[0];
|
||||
}
|
||||
|
||||
if(itemType === Array) {
|
||||
if (itemType === Array) {
|
||||
itemType = Any;
|
||||
}
|
||||
|
||||
Object.defineProperty(arr, 'itemType', {
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
value: itemType
|
||||
value: itemType,
|
||||
});
|
||||
|
||||
if (parent) {
|
||||
Object.defineProperty(arr, 'parent', {
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
value: parent
|
||||
value: parent,
|
||||
});
|
||||
}
|
||||
|
||||
items.forEach(function (item, i) {
|
||||
items.forEach(function(item, i) {
|
||||
if (itemType && !(item instanceof itemType)) {
|
||||
arr[i] = itemType(item);
|
||||
} else {
|
||||
|
@ -70,15 +77,15 @@ util.inherits(List, Array);
|
|||
|
||||
var _push = List.prototype.push;
|
||||
|
||||
List.prototype.push = function (obj) {
|
||||
List.prototype.push = function(obj) {
|
||||
var item = this.itemType && (obj instanceof this.itemType) ? obj : this.itemType(obj);
|
||||
_push.call(this, item);
|
||||
return item;
|
||||
};
|
||||
|
||||
List.prototype.toObject = function (onlySchema, removeHidden, removeProtected) {
|
||||
List.prototype.toObject = function(onlySchema, removeHidden, removeProtected) {
|
||||
var items = [];
|
||||
this.forEach(function (item) {
|
||||
this.forEach(function(item) {
|
||||
if (item && typeof item === 'object' && item.toObject) {
|
||||
items.push(item.toObject(onlySchema, removeHidden, removeProtected));
|
||||
} else {
|
||||
|
@ -88,11 +95,11 @@ List.prototype.toObject = function (onlySchema, removeHidden, removeProtected) {
|
|||
return items;
|
||||
};
|
||||
|
||||
List.prototype.toJSON = function () {
|
||||
List.prototype.toJSON = function() {
|
||||
return this.toObject(true);
|
||||
};
|
||||
|
||||
List.prototype.toString = function () {
|
||||
List.prototype.toString = function() {
|
||||
return JSON.stringify(this.toJSON());
|
||||
};
|
||||
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var debug = require('debug')('loopback:mixin');
|
||||
var assert = require('assert');
|
||||
var DefaultModelBaseClass = require('./model.js');
|
||||
|
@ -35,7 +41,7 @@ MixinProvider.prototype.applyMixin = function applyMixin(modelClass, name, optio
|
|||
} else {
|
||||
// Try model name
|
||||
var model = this.modelBuilder.getModel(name);
|
||||
if(model) {
|
||||
if (model) {
|
||||
debug('Mixin is resolved to a model: %s', name);
|
||||
modelClass.mixin(model, options);
|
||||
} else {
|
||||
|
@ -57,7 +63,7 @@ MixinProvider.prototype.define = function defineMixin(name, mixin) {
|
|||
debug('Defining mixin: %s', name);
|
||||
}
|
||||
if (isModelClass(mixin)) {
|
||||
this.mixins[name] = function (Model, options) {
|
||||
this.mixins[name] = function(Model, options) {
|
||||
Model.mixin(mixin, options);
|
||||
};
|
||||
} else if (typeof mixin === 'function') {
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
/*!
|
||||
* Module dependencies
|
||||
*/
|
||||
|
||||
var g = require('strong-globalize')();
|
||||
var inflection = require('inflection');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var util = require('util');
|
||||
|
@ -39,6 +46,7 @@ function ModelBuilder() {
|
|||
// create blank models pool
|
||||
this.models = {};
|
||||
this.definitions = {};
|
||||
this.settings = {};
|
||||
this.mixins = new MixinProvider(this);
|
||||
this.defaultModelBaseClass = DefaultModelBaseClass;
|
||||
}
|
||||
|
@ -63,7 +71,7 @@ function isModelClass(cls) {
|
|||
* @param {Boolean} forceCreate Whether the create a stub for the given name if a model doesn't exist.
|
||||
* @returns {*} The model class
|
||||
*/
|
||||
ModelBuilder.prototype.getModel = function (name, forceCreate) {
|
||||
ModelBuilder.prototype.getModel = function(name, forceCreate) {
|
||||
var model = this.models[name];
|
||||
if (!model && forceCreate) {
|
||||
model = this.define(name, {}, {unresolved: true});
|
||||
|
@ -76,7 +84,7 @@ ModelBuilder.prototype.getModel = function (name, forceCreate) {
|
|||
* @param {String} name The model name
|
||||
* @returns {ModelDefinition} The model definition
|
||||
*/
|
||||
ModelBuilder.prototype.getModelDefinition = function (name) {
|
||||
ModelBuilder.prototype.getModelDefinition = function(name) {
|
||||
return this.definitions[name];
|
||||
};
|
||||
|
||||
|
@ -119,7 +127,7 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
|
|||
var pathName = httpOptions.path || pluralName;
|
||||
|
||||
if (!className) {
|
||||
throw new Error('Class name required');
|
||||
throw new Error(g.f('Class name required'));
|
||||
}
|
||||
if (args.length === 1) {
|
||||
properties = {};
|
||||
|
@ -172,7 +180,7 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
|
|||
return new ModelConstructor(data, options);
|
||||
}
|
||||
if (ModelClass.settings.unresolved) {
|
||||
throw new Error('Model ' + ModelClass.modelName + ' is not defined.');
|
||||
throw new Error(g.f('Model %s is not defined.', ModelClass.modelName));
|
||||
}
|
||||
ModelBaseClass.apply(this, arguments);
|
||||
};
|
||||
|
@ -222,9 +230,10 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
|
|||
// Support both flavors path: 'x' and path: '/x'
|
||||
pathName = '/' + pathName;
|
||||
}
|
||||
hiddenProperty(ModelClass, 'http', { path: pathName });
|
||||
hiddenProperty(ModelClass, 'http', {path: pathName});
|
||||
hiddenProperty(ModelClass, 'base', ModelBaseClass);
|
||||
hiddenProperty(ModelClass, '_observers', {});
|
||||
hiddenProperty(ModelClass, '_warned', {});
|
||||
|
||||
// inherit ModelBaseClass static methods
|
||||
for (var i in ModelBaseClass) {
|
||||
|
@ -236,7 +245,7 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
|
|||
|
||||
// Load and inject the model classes
|
||||
if (settings.models) {
|
||||
Object.keys(settings.models).forEach(function (m) {
|
||||
Object.keys(settings.models).forEach(function(m) {
|
||||
var model = settings.models[m];
|
||||
ModelClass[m] = typeof model === 'string' ? modelBuilder.getModel(model, true) : model;
|
||||
});
|
||||
|
@ -254,8 +263,8 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
|
|||
|
||||
// Warn about properties with unsupported names
|
||||
if (/\./.test(p)) {
|
||||
deprecated('Property names containing a dot are not supported. ' +
|
||||
'Model: ' + className + ', property: ' + p);
|
||||
deprecated(g.f('Property names containing a dot are not supported. ' +
|
||||
'Model: %s, property: %s', className, p));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -283,7 +292,7 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
|
|||
// Add the id property
|
||||
if (idInjection) {
|
||||
// Set up the id property
|
||||
ModelClass.definition.defineProperty('id', { type: Number, id: 1, generated: true });
|
||||
ModelClass.definition.defineProperty('id', {type: Number, id: 1, generated: true});
|
||||
}
|
||||
|
||||
idNames = modelDefinition.idNames(); // Reload it after rebuild
|
||||
|
@ -292,33 +301,33 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
|
|||
var idProp = idNames[0];
|
||||
if (idProp !== 'id') {
|
||||
Object.defineProperty(ModelClass.prototype, 'id', {
|
||||
get: function () {
|
||||
get: function() {
|
||||
var idProp = ModelClass.definition.idNames()[0];
|
||||
return this.__data[idProp];
|
||||
return this.__data && this.__data[idProp];
|
||||
},
|
||||
configurable: true,
|
||||
enumerable: false
|
||||
enumerable: false,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Now the id property is an object that consists of multiple keys
|
||||
Object.defineProperty(ModelClass.prototype, 'id', {
|
||||
get: function () {
|
||||
get: function() {
|
||||
var compositeId = {};
|
||||
var idNames = ModelClass.definition.idNames();
|
||||
for (var i = 0, p; i < idNames.length; i++) {
|
||||
p = idNames[i];
|
||||
compositeId[p] = this.__data[p];
|
||||
compositeId[p] = this.__data && this.__data[p];
|
||||
}
|
||||
return compositeId;
|
||||
},
|
||||
configurable: true,
|
||||
enumerable: false
|
||||
enumerable: false,
|
||||
});
|
||||
}
|
||||
|
||||
// A function to loop through the properties
|
||||
ModelClass.forEachProperty = function (cb) {
|
||||
ModelClass.forEachProperty = function(cb) {
|
||||
var props = ModelClass.definition.properties;
|
||||
var keys = Object.keys(props);
|
||||
for (var i = 0, n = keys.length; i < n; i++) {
|
||||
|
@ -327,7 +336,7 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
|
|||
};
|
||||
|
||||
// A function to attach the model class to a data source
|
||||
ModelClass.attachTo = function (dataSource) {
|
||||
ModelClass.attachTo = function(dataSource) {
|
||||
dataSource.attach(this);
|
||||
};
|
||||
|
||||
|
@ -351,7 +360,7 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
|
|||
* @options {Object} settings Model settings, such as relations and acls.
|
||||
*
|
||||
*/
|
||||
ModelClass.extend = function (className, subclassProperties, subclassSettings) {
|
||||
ModelClass.extend = function(className, subclassProperties, subclassSettings) {
|
||||
var properties = ModelClass.definition.properties;
|
||||
var settings = ModelClass.definition.settings;
|
||||
|
||||
|
@ -413,12 +422,12 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
|
|||
* Register a property for the model class
|
||||
* @param {String} propertyName Name of the property.
|
||||
*/
|
||||
ModelClass.registerProperty = function (propertyName) {
|
||||
ModelClass.registerProperty = function(propertyName) {
|
||||
var properties = modelDefinition.build();
|
||||
var prop = properties[propertyName];
|
||||
var DataType = prop.type;
|
||||
if (!DataType) {
|
||||
throw new Error('Invalid type for property ' + propertyName);
|
||||
throw new Error(g.f('Invalid type for property %s', propertyName));
|
||||
}
|
||||
|
||||
if (prop.required) {
|
||||
|
@ -427,14 +436,14 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
|
|||
}
|
||||
|
||||
Object.defineProperty(ModelClass.prototype, propertyName, {
|
||||
get: function () {
|
||||
get: function() {
|
||||
if (ModelClass.getter[propertyName]) {
|
||||
return ModelClass.getter[propertyName].call(this); // Try getter first
|
||||
} else {
|
||||
return this.__data && this.__data[propertyName]; // Try __data
|
||||
}
|
||||
},
|
||||
set: function (value) {
|
||||
set: function(value) {
|
||||
var DataType = ModelClass.definition.properties[propertyName].type;
|
||||
if (Array.isArray(DataType) || DataType === Array) {
|
||||
DataType = List;
|
||||
|
@ -469,23 +478,23 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
|
|||
}
|
||||
},
|
||||
configurable: true,
|
||||
enumerable: true
|
||||
enumerable: true,
|
||||
});
|
||||
|
||||
// FIXME: [rfeng] Do we need to keep the raw data?
|
||||
// Use $ as the prefix to avoid conflicts with properties such as _id
|
||||
Object.defineProperty(ModelClass.prototype, '$' + propertyName, {
|
||||
get: function () {
|
||||
get: function() {
|
||||
return this.__data && this.__data[propertyName];
|
||||
},
|
||||
set: function (value) {
|
||||
set: function(value) {
|
||||
if (!this.__data) {
|
||||
this.__data = {};
|
||||
}
|
||||
this.__data[propertyName] = value;
|
||||
},
|
||||
configurable: true,
|
||||
enumerable: false
|
||||
enumerable: false,
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -521,14 +530,13 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
|
|||
ModelClass.emit('defined', ModelClass);
|
||||
|
||||
return ModelClass;
|
||||
|
||||
};
|
||||
|
||||
// DataType for Date
|
||||
function DateType(arg) {
|
||||
var d = new Date(arg);
|
||||
if (isNaN(d.getTime())) {
|
||||
throw new Error('Invalid date: ' + arg);
|
||||
throw new Error(g.f('Invalid date: %s', arg));
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
@ -558,7 +566,7 @@ function BooleanType(arg) {
|
|||
* @param {String} propertyName Name of property
|
||||
* @param {Object} propertyDefinition Property settings
|
||||
*/
|
||||
ModelBuilder.prototype.defineProperty = function (model, propertyName, propertyDefinition) {
|
||||
ModelBuilder.prototype.defineProperty = function(model, propertyName, propertyDefinition) {
|
||||
this.definitions[model].defineProperty(propertyName, propertyDefinition);
|
||||
this.models[model].registerProperty(propertyName);
|
||||
};
|
||||
|
@ -602,7 +610,7 @@ ModelBuilder.prototype.defineValueType = function(type, aliases) {
|
|||
* @property {String} type Datatype of property: Must be an [LDL type](http://docs.strongloop.com/display/LB/LoopBack+types).
|
||||
* @property {Boolean} index True if the property is an index; false otherwise.
|
||||
*/
|
||||
ModelBuilder.prototype.extendModel = function (model, props) {
|
||||
ModelBuilder.prototype.extendModel = function(model, props) {
|
||||
var t = this;
|
||||
var keys = Object.keys(props);
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
|
@ -628,12 +636,11 @@ ModelBuilder.prototype.copyModel = function copyModel(Master) {
|
|||
hiddenProperty(Slave, 'relations', Master.relations);
|
||||
|
||||
if (!(className in modelBuilder.models)) {
|
||||
|
||||
// store class in model pool
|
||||
modelBuilder.models[className] = Slave;
|
||||
modelBuilder.definitions[className] = {
|
||||
properties: md.properties,
|
||||
settings: md.settings
|
||||
settings: md.settings,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -648,14 +655,14 @@ function hiddenProperty(where, property, value) {
|
|||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
value: value
|
||||
value: value,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the schema name
|
||||
*/
|
||||
ModelBuilder.prototype.getSchemaName = function (name) {
|
||||
ModelBuilder.prototype.getSchemaName = function(name) {
|
||||
if (name) {
|
||||
return name;
|
||||
}
|
||||
|
@ -672,7 +679,7 @@ ModelBuilder.prototype.getSchemaName = function (name) {
|
|||
* Returns {Function} if the type is resolved
|
||||
* @param {String} type The type string, such as 'number', 'Number', 'boolean', or 'String'. It's case insensitive
|
||||
*/
|
||||
ModelBuilder.prototype.resolveType = function (type) {
|
||||
ModelBuilder.prototype.resolveType = function(type) {
|
||||
if (!type) {
|
||||
return type;
|
||||
}
|
||||
|
@ -681,8 +688,7 @@ ModelBuilder.prototype.resolveType = function (type) {
|
|||
var itemType = this.resolveType(type[0]);
|
||||
if (typeof itemType === 'function') {
|
||||
return [itemType];
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return itemType; // Not resolved, return the type string
|
||||
}
|
||||
}
|
||||
|
@ -701,7 +707,11 @@ ModelBuilder.prototype.resolveType = function (type) {
|
|||
return this.resolveType(type.type);
|
||||
} else {
|
||||
return this.define(this.getSchemaName(null),
|
||||
type, {anonymous: true, idInjection: false});
|
||||
type, {
|
||||
anonymous: true,
|
||||
idInjection: false,
|
||||
strict: this.settings.strictEmbeddedModels || false,
|
||||
});
|
||||
}
|
||||
} else if ('function' === typeof type) {
|
||||
return type;
|
||||
|
@ -721,7 +731,7 @@ ModelBuilder.prototype.resolveType = function (type) {
|
|||
* @param {*} schemas The schemas
|
||||
* @returns {Object} A map of model constructors keyed by model name
|
||||
*/
|
||||
ModelBuilder.prototype.buildModels = function (schemas, createModel) {
|
||||
ModelBuilder.prototype.buildModels = function(schemas, createModel) {
|
||||
var models = {};
|
||||
|
||||
// Normalize the schemas to be an array of the schema objects {name: <name>, properties: {}, options: {}}
|
||||
|
@ -735,8 +745,8 @@ ModelBuilder.prototype.buildModels = function (schemas, createModel) {
|
|||
{
|
||||
name: this.getSchemaName(),
|
||||
properties: schemas,
|
||||
options: {anonymous: true}
|
||||
}
|
||||
options: {anonymous: true},
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -746,7 +756,7 @@ ModelBuilder.prototype.buildModels = function (schemas, createModel) {
|
|||
var name = this.getSchemaName(schemas[s].name);
|
||||
schemas[s].name = name;
|
||||
var model;
|
||||
if(typeof createModel === 'function') {
|
||||
if (typeof createModel === 'function') {
|
||||
model = createModel(schemas[s].name, schemas[s].properties, schemas[s].options);
|
||||
} else {
|
||||
model = this.define(schemas[s].name, schemas[s].properties, schemas[s].options);
|
||||
|
@ -776,14 +786,10 @@ ModelBuilder.prototype.buildModels = function (schemas, createModel) {
|
|||
* @param {Object} options The options
|
||||
* @returns {}
|
||||
*/
|
||||
ModelBuilder.prototype.buildModelFromInstance = function (name, json, options) {
|
||||
|
||||
ModelBuilder.prototype.buildModelFromInstance = function(name, json, options) {
|
||||
// Introspect the JSON document to generate a schema
|
||||
var schema = introspect(json);
|
||||
|
||||
// Create a model for the generated schema
|
||||
return this.define(name, schema, options);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var assert = require('assert');
|
||||
var util = require('util');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
|
@ -53,7 +59,7 @@ require('./types')(ModelDefinition);
|
|||
* Return table name for specified `modelName`
|
||||
* @param {String} connectorType The connector type, such as 'oracle' or 'mongodb'
|
||||
*/
|
||||
ModelDefinition.prototype.tableName = function (connectorType) {
|
||||
ModelDefinition.prototype.tableName = function(connectorType) {
|
||||
var settings = this.settings;
|
||||
if (settings[connectorType]) {
|
||||
return settings[connectorType].table || settings[connectorType].tableName || this.name;
|
||||
|
@ -68,7 +74,7 @@ ModelDefinition.prototype.tableName = function (connectorType) {
|
|||
* @param propertyName The property name
|
||||
* @returns {String} columnName
|
||||
*/
|
||||
ModelDefinition.prototype.columnName = function (connectorType, propertyName) {
|
||||
ModelDefinition.prototype.columnName = function(connectorType, propertyName) {
|
||||
if (!propertyName) {
|
||||
return propertyName;
|
||||
}
|
||||
|
@ -87,7 +93,7 @@ ModelDefinition.prototype.columnName = function (connectorType, propertyName) {
|
|||
* @param propertyName The property name
|
||||
* @returns {Object} column metadata
|
||||
*/
|
||||
ModelDefinition.prototype.columnMetadata = function (connectorType, propertyName) {
|
||||
ModelDefinition.prototype.columnMetadata = function(connectorType, propertyName) {
|
||||
if (!propertyName) {
|
||||
return propertyName;
|
||||
}
|
||||
|
@ -105,7 +111,7 @@ ModelDefinition.prototype.columnMetadata = function (connectorType, propertyName
|
|||
* @param {String} connectorType The connector type, such as 'oracle' or 'mongodb'
|
||||
* @returns {String[]} column names
|
||||
*/
|
||||
ModelDefinition.prototype.columnNames = function (connectorType) {
|
||||
ModelDefinition.prototype.columnNames = function(connectorType) {
|
||||
this.build();
|
||||
var props = this.properties;
|
||||
var cols = [];
|
||||
|
@ -123,7 +129,7 @@ ModelDefinition.prototype.columnNames = function (connectorType) {
|
|||
* Find the ID properties sorted by the index
|
||||
* @returns {Object[]} property name/index for IDs
|
||||
*/
|
||||
ModelDefinition.prototype.ids = function () {
|
||||
ModelDefinition.prototype.ids = function() {
|
||||
if (this._ids) {
|
||||
return this._ids;
|
||||
}
|
||||
|
@ -140,7 +146,7 @@ ModelDefinition.prototype.ids = function () {
|
|||
}
|
||||
ids.push({name: key, id: id, property: props[key]});
|
||||
}
|
||||
ids.sort(function (a, b) {
|
||||
ids.sort(function(a, b) {
|
||||
return a.id - b.id;
|
||||
});
|
||||
this._ids = ids;
|
||||
|
@ -152,7 +158,7 @@ ModelDefinition.prototype.ids = function () {
|
|||
* @param {String} modelName The model name
|
||||
* @returns {String} columnName for ID
|
||||
*/
|
||||
ModelDefinition.prototype.idColumnName = function (connectorType) {
|
||||
ModelDefinition.prototype.idColumnName = function(connectorType) {
|
||||
return this.columnName(connectorType, this.idName());
|
||||
};
|
||||
|
||||
|
@ -160,7 +166,7 @@ ModelDefinition.prototype.idColumnName = function (connectorType) {
|
|||
* Find the ID property name
|
||||
* @returns {String} property name for ID
|
||||
*/
|
||||
ModelDefinition.prototype.idName = function () {
|
||||
ModelDefinition.prototype.idName = function() {
|
||||
var id = this.ids()[0];
|
||||
if (this.properties.id && this.properties.id.id) {
|
||||
return 'id';
|
||||
|
@ -173,9 +179,9 @@ ModelDefinition.prototype.idName = function () {
|
|||
* Find the ID property names sorted by the index
|
||||
* @returns {String[]} property names for IDs
|
||||
*/
|
||||
ModelDefinition.prototype.idNames = function () {
|
||||
ModelDefinition.prototype.idNames = function() {
|
||||
var ids = this.ids();
|
||||
var names = ids.map(function (id) {
|
||||
var names = ids.map(function(id) {
|
||||
return id.name;
|
||||
});
|
||||
return names;
|
||||
|
@ -185,7 +191,7 @@ ModelDefinition.prototype.idNames = function () {
|
|||
*
|
||||
* @returns {{}}
|
||||
*/
|
||||
ModelDefinition.prototype.indexes = function () {
|
||||
ModelDefinition.prototype.indexes = function() {
|
||||
this.build();
|
||||
var indexes = {};
|
||||
if (this.settings.indexes) {
|
||||
|
@ -205,7 +211,7 @@ ModelDefinition.prototype.indexes = function () {
|
|||
* Build a model definition
|
||||
* @param {Boolean} force Forcing rebuild
|
||||
*/
|
||||
ModelDefinition.prototype.build = function (forceRebuild) {
|
||||
ModelDefinition.prototype.build = function(forceRebuild) {
|
||||
if (forceRebuild) {
|
||||
this.properties = null;
|
||||
this.relations = [];
|
||||
|
@ -224,11 +230,11 @@ ModelDefinition.prototype.build = function (forceRebuild) {
|
|||
source: this.name,
|
||||
target: type,
|
||||
type: Array.isArray(prop) ? 'hasMany' : 'belongsTo',
|
||||
as: p
|
||||
as: p,
|
||||
});
|
||||
} else {
|
||||
var typeDef = {
|
||||
type: type
|
||||
type: type,
|
||||
};
|
||||
if (typeof prop === 'object' && prop !== null) {
|
||||
for (var a in prop) {
|
||||
|
@ -249,7 +255,7 @@ ModelDefinition.prototype.build = function (forceRebuild) {
|
|||
* @param {String} propertyName The property name
|
||||
* @param {Object} propertyDefinition The property definition
|
||||
*/
|
||||
ModelDefinition.prototype.defineProperty = function (propertyName, propertyDefinition) {
|
||||
ModelDefinition.prototype.defineProperty = function(propertyName, propertyDefinition) {
|
||||
this.rawProperties[propertyName] = propertyDefinition;
|
||||
this.build(true);
|
||||
};
|
||||
|
@ -261,7 +267,7 @@ function isModelClass(cls) {
|
|||
return cls.prototype instanceof ModelBaseClass;
|
||||
}
|
||||
|
||||
ModelDefinition.prototype.toJSON = function (forceRebuild) {
|
||||
ModelDefinition.prototype.toJSON = function(forceRebuild) {
|
||||
if (forceRebuild) {
|
||||
this.json = null;
|
||||
}
|
||||
|
@ -271,11 +277,11 @@ ModelDefinition.prototype.toJSON = function (forceRebuild) {
|
|||
var json = {
|
||||
name: this.name,
|
||||
properties: {},
|
||||
settings: this.settings
|
||||
settings: this.settings,
|
||||
};
|
||||
this.build(forceRebuild);
|
||||
|
||||
var mapper = function (val) {
|
||||
var mapper = function(val) {
|
||||
if (val === undefined || val === null) {
|
||||
return val;
|
||||
}
|
||||
|
|
107
lib/model.js
107
lib/model.js
|
@ -1,3 +1,12 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
|
||||
// Turning on strict for this file breaks lots of test cases;
|
||||
// disabling strict for this file
|
||||
/* eslint-disable strict */
|
||||
|
||||
/*!
|
||||
* Module exports class Model
|
||||
*/
|
||||
|
@ -7,7 +16,7 @@ module.exports = ModelBaseClass;
|
|||
* Module dependencies
|
||||
*/
|
||||
|
||||
var async = require('async');
|
||||
var g = require('strong-globalize')();
|
||||
var util = require('util');
|
||||
var jutil = require('./jutil');
|
||||
var List = require('./list');
|
||||
|
@ -16,8 +25,9 @@ var validations = require('./validations');
|
|||
var _extend = util._extend;
|
||||
var utils = require('./utils');
|
||||
var fieldsToArray = utils.fieldsToArray;
|
||||
var uuid = require('node-uuid');
|
||||
var uuid = require('uuid');
|
||||
var deprecated = require('depd')('loopback-datasource-juggler');
|
||||
var shortid = require('shortid');
|
||||
|
||||
// Set up an object for quick lookup
|
||||
var BASE_TYPES = {
|
||||
|
@ -26,7 +36,7 @@ var BASE_TYPES = {
|
|||
'Number': true,
|
||||
'Date': true,
|
||||
'Text': true,
|
||||
'ObjectID': true
|
||||
'ObjectID': true,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -39,7 +49,7 @@ var BASE_TYPES = {
|
|||
*/
|
||||
function ModelBaseClass(data, options) {
|
||||
options = options || {};
|
||||
if(!('applySetters' in options)) {
|
||||
if (!('applySetters' in options)) {
|
||||
// Default to true
|
||||
options.applySetters = true;
|
||||
}
|
||||
|
@ -59,11 +69,11 @@ function ModelBaseClass(data, options) {
|
|||
* @property {Boolean} persisted Whether the instance has been persisted
|
||||
* @private
|
||||
*/
|
||||
ModelBaseClass.prototype._initProperties = function (data, options) {
|
||||
ModelBaseClass.prototype._initProperties = function(data, options) {
|
||||
var self = this;
|
||||
var ctor = this.constructor;
|
||||
|
||||
if(data instanceof ctor) {
|
||||
if (data instanceof ctor) {
|
||||
// Convert the data to be plain object to avoid pollutions
|
||||
data = data.toObject(false);
|
||||
}
|
||||
|
@ -79,7 +89,7 @@ ModelBaseClass.prototype._initProperties = function (data, options) {
|
|||
var applyDefaultValues = options.applyDefaultValues;
|
||||
var strict = options.strict;
|
||||
|
||||
if(strict === undefined) {
|
||||
if (strict === undefined) {
|
||||
strict = ctor.definition.settings.strict;
|
||||
}
|
||||
|
||||
|
@ -94,14 +104,14 @@ ModelBaseClass.prototype._initProperties = function (data, options) {
|
|||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
value: {}
|
||||
value: {},
|
||||
},
|
||||
|
||||
__data: {
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
value: {}
|
||||
value: {},
|
||||
},
|
||||
|
||||
// Instance level data source
|
||||
|
@ -109,7 +119,7 @@ ModelBaseClass.prototype._initProperties = function (data, options) {
|
|||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
value: options.dataSource
|
||||
value: options.dataSource,
|
||||
},
|
||||
|
||||
// Instance level strict mode
|
||||
|
@ -117,14 +127,14 @@ ModelBaseClass.prototype._initProperties = function (data, options) {
|
|||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
value: strict
|
||||
value: strict,
|
||||
},
|
||||
|
||||
__persisted: {
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
value: false
|
||||
value: false,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -133,7 +143,7 @@ ModelBaseClass.prototype._initProperties = function (data, options) {
|
|||
writable: true,
|
||||
enumerable: false,
|
||||
configrable: true,
|
||||
value: []
|
||||
value: [],
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
@ -192,7 +202,7 @@ ModelBaseClass.prototype._initProperties = function (data, options) {
|
|||
var multiple = ctor.relations[p].multiple;
|
||||
var typeName = multiple ? 'Array' : modelTo.modelName;
|
||||
var propType = multiple ? [modelTo] : modelTo;
|
||||
properties[p] = { name: typeName, type: propType };
|
||||
properties[p] = {name: typeName, type: propType};
|
||||
this.setStrict(false);
|
||||
}
|
||||
|
||||
|
@ -207,7 +217,11 @@ ModelBaseClass.prototype._initProperties = function (data, options) {
|
|||
if (!~fields.indexOf(ctor.relations[p].keyTo)) {
|
||||
fields.push(ctor.relations[p].keyTo);
|
||||
}
|
||||
self.__data[p] = new modelTo(propVal, { fields: fields, applySetters: false, persisted: options.persisted });
|
||||
self.__data[p] = new modelTo(propVal, {
|
||||
fields: fields,
|
||||
applySetters: false,
|
||||
persisted: options.persisted,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,12 +234,11 @@ ModelBaseClass.prototype._initProperties = function (data, options) {
|
|||
|
||||
// Warn about properties with unsupported names
|
||||
if (/\./.test(p)) {
|
||||
deprecated('Property names containing a dot are not supported. ' +
|
||||
'Model: ' + this.constructor.modelName +
|
||||
', dynamic property: ' + p);
|
||||
deprecated(g.f('Property names containing a dot are not supported. ' +
|
||||
'Model: %s, dynamic property: %s', this.constructor.modelName, p));
|
||||
}
|
||||
} else if (strict === 'throw') {
|
||||
throw new Error('Unknown property: ' + p);
|
||||
throw new Error(g.f('Unknown property: %s', p));
|
||||
} else if (strict === 'validate') {
|
||||
this.__unknownProperties.push(p);
|
||||
}
|
||||
|
@ -287,9 +300,12 @@ ModelBaseClass.prototype._initProperties = function (data, options) {
|
|||
case 'now':
|
||||
propVal = new Date();
|
||||
break;
|
||||
case 'shortid':
|
||||
propVal = shortid.generate();
|
||||
break;
|
||||
default:
|
||||
// TODO Support user-provided functions via a registry of functions
|
||||
console.warn('Unknown default value provider ' + defn);
|
||||
g.warn('Unknown default value provider %s', defn);
|
||||
}
|
||||
// FIXME: We should coerce the value
|
||||
// will implement it after we refactor the PropertyDefinition
|
||||
|
@ -303,7 +319,6 @@ ModelBaseClass.prototype._initProperties = function (data, options) {
|
|||
|
||||
// Handle complex types (JSON/Object)
|
||||
if (!BASE_TYPES[type.name]) {
|
||||
|
||||
if (typeof self.__data[p] !== 'object' && self.__data[p]) {
|
||||
try {
|
||||
self.__data[p] = JSON.parse(self.__data[p] + '');
|
||||
|
@ -313,15 +328,15 @@ ModelBaseClass.prototype._initProperties = function (data, options) {
|
|||
}
|
||||
|
||||
if (type.prototype instanceof ModelBaseClass) {
|
||||
if (!(self.__data[p] instanceof type)
|
||||
&& typeof self.__data[p] === 'object'
|
||||
&& self.__data[p] !== null ) {
|
||||
if (!(self.__data[p] instanceof type) &&
|
||||
typeof self.__data[p] === 'object' &&
|
||||
self.__data[p] !== null) {
|
||||
self.__data[p] = new type(self.__data[p]);
|
||||
}
|
||||
} else if (type.name === 'Array' || Array.isArray(type)) {
|
||||
if (!(self.__data[p] instanceof List)
|
||||
&& self.__data[p] !== undefined
|
||||
&& self.__data[p] !== null ) {
|
||||
if (!(self.__data[p] instanceof List) &&
|
||||
self.__data[p] !== undefined &&
|
||||
self.__data[p] !== null) {
|
||||
self.__data[p] = List(self.__data[p], type, self);
|
||||
}
|
||||
}
|
||||
|
@ -335,28 +350,28 @@ ModelBaseClass.prototype._initProperties = function (data, options) {
|
|||
* @param {String} prop Property name
|
||||
* @param {Object} params Various property configuration
|
||||
*/
|
||||
ModelBaseClass.defineProperty = function (prop, params) {
|
||||
if(this.dataSource) {
|
||||
ModelBaseClass.defineProperty = function(prop, params) {
|
||||
if (this.dataSource) {
|
||||
this.dataSource.defineProperty(this.modelName, prop, params);
|
||||
} else {
|
||||
this.modelBuilder.defineProperty(this.modelName, prop, params);
|
||||
}
|
||||
};
|
||||
|
||||
ModelBaseClass.getPropertyType = function (propName) {
|
||||
ModelBaseClass.getPropertyType = function(propName) {
|
||||
var prop = this.definition.properties[propName];
|
||||
if (!prop) {
|
||||
// The property is not part of the definition
|
||||
return null;
|
||||
}
|
||||
if (!prop.type) {
|
||||
throw new Error('Type not defined for property ' + this.modelName + '.' + propName);
|
||||
throw new Error(g.f('Type not defined for property %s.%s', this.modelName, propName));
|
||||
// return null;
|
||||
}
|
||||
return prop.type.name;
|
||||
};
|
||||
|
||||
ModelBaseClass.prototype.getPropertyType = function (propName) {
|
||||
ModelBaseClass.prototype.getPropertyType = function(propName) {
|
||||
return this.constructor.getPropertyType(propName);
|
||||
};
|
||||
|
||||
|
@ -364,7 +379,7 @@ ModelBaseClass.prototype.getPropertyType = function (propName) {
|
|||
* Return string representation of class
|
||||
* This overrides the default `toString()` method
|
||||
*/
|
||||
ModelBaseClass.toString = function () {
|
||||
ModelBaseClass.toString = function() {
|
||||
return '[Model ' + this.modelName + ']';
|
||||
};
|
||||
|
||||
|
@ -374,7 +389,7 @@ ModelBaseClass.toString = function () {
|
|||
*
|
||||
* @param {Boolean} onlySchema Restrict properties to dataSource only. Default is false. If true, the function returns only properties defined in the schema; Otherwise it returns all enumerable properties.
|
||||
*/
|
||||
ModelBaseClass.prototype.toObject = function (onlySchema, removeHidden, removeProtected) {
|
||||
ModelBaseClass.prototype.toObject = function(onlySchema, removeHidden, removeProtected) {
|
||||
if (onlySchema === undefined) {
|
||||
onlySchema = true;
|
||||
}
|
||||
|
@ -499,7 +514,7 @@ ModelBaseClass.prototype.toObject = function (onlySchema, removeHidden, removePr
|
|||
return data;
|
||||
};
|
||||
|
||||
ModelBaseClass.isProtectedProperty = function (propertyName) {
|
||||
ModelBaseClass.isProtectedProperty = function(propertyName) {
|
||||
var Model = this;
|
||||
var settings = Model.definition && Model.definition.settings;
|
||||
var protectedProperties = settings && (settings.protectedProperties || settings.protected);
|
||||
|
@ -518,7 +533,7 @@ ModelBaseClass.isProtectedProperty = function (propertyName) {
|
|||
}
|
||||
};
|
||||
|
||||
ModelBaseClass.isHiddenProperty = function (propertyName) {
|
||||
ModelBaseClass.isHiddenProperty = function(propertyName) {
|
||||
var Model = this;
|
||||
var settings = Model.definition && Model.definition.settings;
|
||||
var hiddenProperties = settings && (settings.hiddenProperties || settings.hidden);
|
||||
|
@ -537,11 +552,11 @@ ModelBaseClass.isHiddenProperty = function (propertyName) {
|
|||
}
|
||||
};
|
||||
|
||||
ModelBaseClass.prototype.toJSON = function () {
|
||||
ModelBaseClass.prototype.toJSON = function() {
|
||||
return this.toObject(false, true, false);
|
||||
};
|
||||
|
||||
ModelBaseClass.prototype.fromObject = function (obj) {
|
||||
ModelBaseClass.prototype.fromObject = function(obj) {
|
||||
for (var key in obj) {
|
||||
this[key] = obj[key];
|
||||
}
|
||||
|
@ -552,7 +567,7 @@ ModelBaseClass.prototype.fromObject = function (obj) {
|
|||
* This method does not perform any database operations; it just resets the object to its
|
||||
* initial state.
|
||||
*/
|
||||
ModelBaseClass.prototype.reset = function () {
|
||||
ModelBaseClass.prototype.reset = function() {
|
||||
var obj = this;
|
||||
for (var k in obj) {
|
||||
if (k !== 'id' && !obj.constructor.dataSource.definitions[obj.constructor.modelName].properties[k]) {
|
||||
|
@ -573,20 +588,20 @@ var INSPECT_SUPPORTS_OBJECT_RETVAL =
|
|||
versionParts[1] > 11 ||
|
||||
(versionParts[0] === 11 && versionParts[1] >= 14);
|
||||
|
||||
ModelBaseClass.prototype.inspect = function (depth) {
|
||||
ModelBaseClass.prototype.inspect = function(depth) {
|
||||
if (INSPECT_SUPPORTS_OBJECT_RETVAL)
|
||||
return this.__data;
|
||||
return this.__data;
|
||||
|
||||
// Workaround for older versions
|
||||
// See also https://github.com/joyent/node/commit/66280de133
|
||||
return util.inspect(this.__data, {
|
||||
showHidden: false,
|
||||
depth: depth,
|
||||
colors: false
|
||||
colors: false,
|
||||
});
|
||||
};
|
||||
|
||||
ModelBaseClass.mixin = function (anotherClass, options) {
|
||||
ModelBaseClass.mixin = function(anotherClass, options) {
|
||||
if (typeof anotherClass === 'string') {
|
||||
this.modelBuilder.mixins.applyMixin(this, anotherClass, options);
|
||||
} else {
|
||||
|
@ -603,15 +618,15 @@ ModelBaseClass.mixin = function (anotherClass, options) {
|
|||
}
|
||||
};
|
||||
|
||||
ModelBaseClass.prototype.getDataSource = function () {
|
||||
ModelBaseClass.prototype.getDataSource = function() {
|
||||
return this.__dataSource || this.constructor.dataSource;
|
||||
};
|
||||
|
||||
ModelBaseClass.getDataSource = function () {
|
||||
ModelBaseClass.getDataSource = function() {
|
||||
return this.dataSource;
|
||||
};
|
||||
|
||||
ModelBaseClass.prototype.setStrict = function (strict) {
|
||||
ModelBaseClass.prototype.setStrict = function(strict) {
|
||||
this.__strict = strict;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
// Copyright IBM Corp. 2015,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var async = require('async');
|
||||
var utils = require('./utils');
|
||||
|
||||
|
@ -103,7 +109,7 @@ ObserverMixin.notifyObserversOf = function(operation, context, callback) {
|
|||
);
|
||||
}
|
||||
},
|
||||
function(err) { callback(err, context) }
|
||||
function(err) { callback(err, context); }
|
||||
);
|
||||
});
|
||||
return callback.promise;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,3 +1,9 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
/*!
|
||||
* Dependencies
|
||||
*/
|
||||
|
@ -16,12 +22,12 @@ function RelationMixin() {
|
|||
|
||||
/**
|
||||
* Define a "one to many" relationship by specifying the model name
|
||||
*
|
||||
*
|
||||
* Examples:
|
||||
* ```
|
||||
* User.hasMany(Post, {as: 'posts', foreignKey: 'authorId'});
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* ```
|
||||
* Book.hasMany(Chapter);
|
||||
* ```
|
||||
|
@ -34,24 +40,24 @@ function RelationMixin() {
|
|||
*
|
||||
* ```js
|
||||
* Book.create(function(err, book) {
|
||||
*
|
||||
*
|
||||
* // Create a chapter instance ready to be saved in the data source.
|
||||
* var chapter = book.chapters.build({name: 'Chapter 1'});
|
||||
*
|
||||
*
|
||||
* // Save the new chapter
|
||||
* chapter.save();
|
||||
*
|
||||
*
|
||||
* // you can also call the Chapter.create method with the `chapters` property which will build a chapter
|
||||
* // instance and save the it in the data source.
|
||||
* book.chapters.create({name: 'Chapter 2'}, function(err, savedChapter) {
|
||||
* // this callback is optional
|
||||
* });
|
||||
*
|
||||
* // Query chapters for the book
|
||||
* book.chapters(function(err, chapters) { // all chapters with bookId = book.id
|
||||
*
|
||||
* // Query chapters for the book
|
||||
* book.chapters(function(err, chapters) { // all chapters with bookId = book.id
|
||||
* console.log(chapters);
|
||||
* });
|
||||
*
|
||||
*
|
||||
* book.chapters({where: {name: 'test'}, function(err, chapters) {
|
||||
* // All chapters with bookId = book.id and name = 'test'
|
||||
* console.log(chapters);
|
||||
|
@ -86,12 +92,13 @@ RelationMixin.hasMany = function hasMany(modelTo, params) {
|
|||
* Get the User object for the post author synchronously:
|
||||
* ```
|
||||
* post.author();
|
||||
* ```
|
||||
* Set the author to be the given user:
|
||||
* ```
|
||||
* post.author(user)
|
||||
* post.author(user)
|
||||
* ```
|
||||
* Examples:
|
||||
*
|
||||
*
|
||||
* Suppose the model Post has a *belongsTo* relationship with User (the author of the post). You could declare it this way:
|
||||
* ```js
|
||||
* Post.belongsTo(User, {as: 'author', foreignKey: 'userId'});
|
||||
|
@ -117,9 +124,9 @@ RelationMixin.hasMany = function hasMany(modelTo, params) {
|
|||
* @options {Object} params Configuration parameters; see below.
|
||||
* @property {String} as Name of the property in the referring model that corresponds to the foreign key field in the related model.
|
||||
* @property {String} foreignKey Name of foreign key property.
|
||||
*
|
||||
*
|
||||
*/
|
||||
RelationMixin.belongsTo = function (modelTo, params) {
|
||||
RelationMixin.belongsTo = function(modelTo, params) {
|
||||
return RelationDefinition.belongsTo(this, modelTo, params);
|
||||
};
|
||||
|
||||
|
@ -144,9 +151,9 @@ RelationMixin.belongsTo = function (modelTo, params) {
|
|||
* ```
|
||||
* Remove the user from the group:
|
||||
* ```
|
||||
* user.groups.remove(group, callback);
|
||||
* user.groups.remove(group, callback);
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* @param {String|Object} modelTo Model object (or String name of model) to which you are creating the relationship.
|
||||
* the relation
|
||||
* @options {Object} params Configuration parameters; see below.
|
||||
|
|
123
lib/scope.js
123
lib/scope.js
|
@ -1,9 +1,19 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
/*eslint-disable camelcase*/
|
||||
|
||||
var i8n = require('inflection');
|
||||
var utils = require('./utils');
|
||||
var defineCachedRelations = utils.defineCachedRelations;
|
||||
var setScopeValuesFromWhere = utils.setScopeValuesFromWhere;
|
||||
var mergeQuery = utils.mergeQuery;
|
||||
var DefaultModelBaseClass = require('./model.js');
|
||||
var collectTargetIds = utils.collectTargetIds;
|
||||
var idName = utils.idName;
|
||||
|
||||
/**
|
||||
* Module exports
|
||||
|
@ -75,24 +85,62 @@ ScopeDefinition.prototype.related = function(receiver, scopeParams, condOrRefres
|
|||
}
|
||||
cb = cb || utils.createPromiseCallback();
|
||||
|
||||
if (!self.__cachedRelations || self.__cachedRelations[name] === undefined
|
||||
|| actualRefresh) {
|
||||
if (!self.__cachedRelations || self.__cachedRelations[name] === undefined ||
|
||||
actualRefresh) {
|
||||
// It either doesn't hit the cache or refresh is required
|
||||
var params = mergeQuery(actualCond, scopeParams, {nestedInclude: true});
|
||||
var targetModel = this.targetModel(receiver);
|
||||
targetModel.find(params, options, function (err, data) {
|
||||
|
||||
// If there is a through model
|
||||
// run another query to apply filter on relatedModel(targetModel)
|
||||
// see github.com/strongloop/loopback-datasource-juggler/issues/166
|
||||
var scopeOnRelatedModel = params.collect &&
|
||||
params.include.scope !== null &&
|
||||
typeof params.include.scope === 'object';
|
||||
if (scopeOnRelatedModel) {
|
||||
var filter = params.include;
|
||||
// The filter applied on relatedModel
|
||||
var queryRelated = filter.scope;
|
||||
delete params.include.scope;
|
||||
};
|
||||
|
||||
targetModel.find(params, options, function(err, data) {
|
||||
if (!err && saveOnCache) {
|
||||
defineCachedRelations(self);
|
||||
self.__cachedRelations[name] = data;
|
||||
}
|
||||
cb(err, data);
|
||||
|
||||
if (scopeOnRelatedModel === true) {
|
||||
var relatedModel = targetModel.relations[filter.relation].modelTo;
|
||||
var IdKey = idName(relatedModel);
|
||||
|
||||
// Merge queryRelated filter and targetId filter
|
||||
var buildWhere = function() {
|
||||
var IdKeyCondition = {};
|
||||
IdKeyCondition[IdKey] = collectTargetIds(data, IdKey);
|
||||
var mergedWhere = {
|
||||
and: [IdKeyCondition, queryRelated.where],
|
||||
};
|
||||
return mergedWhere;
|
||||
};
|
||||
if (queryRelated.where !== undefined) {
|
||||
queryRelated.where = buildWhere();
|
||||
} else {
|
||||
queryRelated.where = {};
|
||||
queryRelated.where[IdKey] = collectTargetIds(data, IdKey);
|
||||
}
|
||||
|
||||
relatedModel.find(queryRelated, cb);
|
||||
} else {
|
||||
cb(err, data);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Return from cache
|
||||
cb(null, self.__cachedRelations[name]);
|
||||
}
|
||||
return cb.promise;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Define a scope method
|
||||
|
@ -101,7 +149,7 @@ ScopeDefinition.prototype.related = function(receiver, scopeParams, condOrRefres
|
|||
*/
|
||||
ScopeDefinition.prototype.defineMethod = function(name, fn) {
|
||||
return this.methods[name] = fn;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Define a scope to the class
|
||||
|
@ -138,10 +186,10 @@ function defineScope(cls, targetClass, name, params, methods, options) {
|
|||
name: name,
|
||||
params: params,
|
||||
methods: methods,
|
||||
options: options
|
||||
options: options,
|
||||
});
|
||||
|
||||
if(isStatic) {
|
||||
if (isStatic) {
|
||||
cls.scopes = cls.scopes || {};
|
||||
cls.scopes[name] = definition;
|
||||
} else {
|
||||
|
@ -164,7 +212,7 @@ function defineScope(cls, targetClass, name, params, methods, options) {
|
|||
* user.accounts.create(act, cb).
|
||||
*
|
||||
*/
|
||||
get: function () {
|
||||
get: function() {
|
||||
var targetModel = definition.targetModel(this);
|
||||
var self = this;
|
||||
|
||||
|
@ -176,8 +224,8 @@ function defineScope(cls, targetClass, name, params, methods, options) {
|
|||
return self.__cachedRelations[name];
|
||||
}
|
||||
} else {
|
||||
if (typeof condOrRefresh === 'function'
|
||||
&& options === undefined && cb === undefined) {
|
||||
if (typeof condOrRefresh === 'function' &&
|
||||
options === undefined && cb === undefined) {
|
||||
// customer.orders(cb)
|
||||
cb = condOrRefresh;
|
||||
options = {};
|
||||
|
@ -187,23 +235,14 @@ function defineScope(cls, targetClass, name, params, methods, options) {
|
|||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
options = options || {}
|
||||
options = options || {};
|
||||
// Check if there is a through model
|
||||
// see https://github.com/strongloop/loopback/issues/1076
|
||||
if (f._scope.collect &&
|
||||
condOrRefresh !== null && typeof condOrRefresh === 'object') {
|
||||
//extract the paging filters to the through model
|
||||
['limit','offset','skip','order'].forEach(function(pagerFilter){
|
||||
if(typeof(condOrRefresh[pagerFilter]) !== 'undefined'){
|
||||
f._scope[pagerFilter] = condOrRefresh[pagerFilter];
|
||||
delete condOrRefresh[pagerFilter];
|
||||
}
|
||||
});
|
||||
// Adjust the include so that the condition will be applied to
|
||||
// the target model
|
||||
f._scope.include = {
|
||||
relation: f._scope.collect,
|
||||
scope: condOrRefresh
|
||||
scope: condOrRefresh,
|
||||
};
|
||||
condOrRefresh = {};
|
||||
}
|
||||
|
@ -221,8 +260,8 @@ function defineScope(cls, targetClass, name, params, methods, options) {
|
|||
}
|
||||
|
||||
f.getAsync = function(condOrRefresh, options, cb) {
|
||||
if (typeof condOrRefresh === 'function'
|
||||
&& options === undefined && cb === undefined) {
|
||||
if (typeof condOrRefresh === 'function' &&
|
||||
options === undefined && cb === undefined) {
|
||||
// customer.orders.getAsync(cb)
|
||||
cb = condOrRefresh;
|
||||
options = {};
|
||||
|
@ -232,9 +271,9 @@ function defineScope(cls, targetClass, name, params, methods, options) {
|
|||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
options = options || {}
|
||||
options = options || {};
|
||||
return definition.related(self, f._scope, condOrRefresh, options, cb);
|
||||
}
|
||||
};
|
||||
|
||||
f.build = build;
|
||||
f.create = create;
|
||||
|
@ -254,21 +293,21 @@ function defineScope(cls, targetClass, name, params, methods, options) {
|
|||
// Station.scope('active', {where: {isActive: true}});
|
||||
// Station.scope('subway', {where: {isUndeground: true}});
|
||||
// Station.active.subway(cb);
|
||||
Object.keys(targetClass._scopeMeta).forEach(function (name) {
|
||||
Object.keys(targetClass._scopeMeta).forEach(function(name) {
|
||||
Object.defineProperty(f, name, {
|
||||
enumerable: false,
|
||||
get: function () {
|
||||
get: function() {
|
||||
mergeQuery(f._scope, targetModel._scopeMeta[name]);
|
||||
return f;
|
||||
}
|
||||
},
|
||||
});
|
||||
}.bind(self));
|
||||
return f;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// Wrap the property into a function for remoting
|
||||
var fn = function () {
|
||||
var fn = function() {
|
||||
// primaryObject.scopeName, such as user.accounts
|
||||
var f = this[name];
|
||||
// set receiver to be the scope property whose value is a function
|
||||
|
@ -277,42 +316,42 @@ function defineScope(cls, targetClass, name, params, methods, options) {
|
|||
|
||||
cls['__get__' + name] = fn;
|
||||
|
||||
var fn_create = function () {
|
||||
var fn_create = function() {
|
||||
var f = this[name].create;
|
||||
f.apply(this[name], arguments);
|
||||
};
|
||||
|
||||
cls['__create__' + name] = fn_create;
|
||||
|
||||
var fn_delete = function () {
|
||||
var fn_delete = function() {
|
||||
var f = this[name].destroyAll;
|
||||
f.apply(this[name], arguments);
|
||||
};
|
||||
|
||||
cls['__delete__' + name] = fn_delete;
|
||||
|
||||
var fn_update = function () {
|
||||
var fn_update = function() {
|
||||
var f = this[name].updateAll;
|
||||
f.apply(this[name], arguments);
|
||||
};
|
||||
|
||||
cls['__update__' + name] = fn_update;
|
||||
|
||||
var fn_findById = function (cb) {
|
||||
var fn_findById = function(cb) {
|
||||
var f = this[name].findById;
|
||||
f.apply(this[name], arguments);
|
||||
};
|
||||
|
||||
cls['__findById__' + name] = fn_findById;
|
||||
|
||||
var fn_findOne = function (cb) {
|
||||
var fn_findOne = function(cb) {
|
||||
var f = this[name].findOne;
|
||||
f.apply(this[name], arguments);
|
||||
};
|
||||
|
||||
cls['__findOne__' + name] = fn_findOne;
|
||||
|
||||
var fn_count = function (cb) {
|
||||
var fn_count = function(cb) {
|
||||
var f = this[name].count;
|
||||
f.apply(this[name], arguments);
|
||||
};
|
||||
|
@ -364,7 +403,7 @@ function defineScope(cls, targetClass, name, params, methods, options) {
|
|||
|
||||
var targetModel = definition.targetModel(this._receiver);
|
||||
var scoped = (this._scope && this._scope.where) || {};
|
||||
var filter = mergeQuery({ where: scoped }, { where: where || {} });
|
||||
var filter = mergeQuery({where: scoped}, {where: where || {}});
|
||||
return targetModel.destroyAll(filter.where, options, cb);
|
||||
}
|
||||
|
||||
|
@ -384,7 +423,7 @@ function defineScope(cls, targetClass, name, params, methods, options) {
|
|||
options = options || {};
|
||||
var targetModel = definition.targetModel(this._receiver);
|
||||
var scoped = (this._scope && this._scope.where) || {};
|
||||
var filter = mergeQuery({ where: scoped }, { where: where || {} });
|
||||
var filter = mergeQuery({where: scoped}, {where: where || {}});
|
||||
return targetModel.updateAll(filter.where, data, options, cb);
|
||||
}
|
||||
|
||||
|
@ -407,7 +446,7 @@ function defineScope(cls, targetClass, name, params, methods, options) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
options = options || {};
|
||||
filter = filter || {};
|
||||
var targetModel = definition.targetModel(this._receiver);
|
||||
|
@ -432,7 +471,7 @@ function defineScope(cls, targetClass, name, params, methods, options) {
|
|||
options = options || {};
|
||||
var targetModel = definition.targetModel(this._receiver);
|
||||
var scoped = (this._scope && this._scope.where) || {};
|
||||
filter = mergeQuery({ where: scoped }, filter || {});
|
||||
filter = mergeQuery({where: scoped}, filter || {});
|
||||
return targetModel.findOne(filter, options, cb);
|
||||
}
|
||||
|
||||
|
@ -450,7 +489,7 @@ function defineScope(cls, targetClass, name, params, methods, options) {
|
|||
|
||||
var targetModel = definition.targetModel(this._receiver);
|
||||
var scoped = (this._scope && this._scope.where) || {};
|
||||
var filter = mergeQuery({ where: scoped }, { where: where || {} });
|
||||
var filter = mergeQuery({where: scoped}, {where: where || {}});
|
||||
return targetModel.count(filter.where, options, cb);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
// Copyright IBM Corp. 2015,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var g = require('strong-globalize')();
|
||||
var debug = require('debug')('loopback:connector:transaction');
|
||||
var uuid = require('node-uuid');
|
||||
var uuid = require('uuid');
|
||||
var utils = require('./utils');
|
||||
var jutil = require('./jutil');
|
||||
var ObserverMixin = require('./observer');
|
||||
|
@ -73,7 +80,7 @@ TransactionMixin.beginTransaction = function(options, cb) {
|
|||
setTimeout(function() {
|
||||
var context = {
|
||||
transaction: transaction,
|
||||
operation: 'timeout'
|
||||
operation: 'timeout',
|
||||
};
|
||||
transaction.notifyObserversOf('timeout', context, function(err) {
|
||||
if (!err) {
|
||||
|
@ -89,7 +96,7 @@ TransactionMixin.beginTransaction = function(options, cb) {
|
|||
});
|
||||
} else {
|
||||
process.nextTick(function() {
|
||||
var err = new Error('Transaction is not supported');
|
||||
var err = new Error(g.f('{{Transaction}} is not supported'));
|
||||
cb(err);
|
||||
});
|
||||
}
|
||||
|
@ -110,13 +117,13 @@ if (Transaction) {
|
|||
// Report an error if the transaction is not active
|
||||
if (!self.connection) {
|
||||
process.nextTick(function() {
|
||||
cb(new Error('The transaction is not active: ' + self.id));
|
||||
cb(new Error(g.f('The {{transaction}} is not active: %s', self.id)));
|
||||
});
|
||||
return cb.promise;
|
||||
}
|
||||
var context = {
|
||||
transaction: self,
|
||||
operation: 'commit'
|
||||
operation: 'commit',
|
||||
};
|
||||
|
||||
function work(done) {
|
||||
|
@ -144,13 +151,13 @@ if (Transaction) {
|
|||
// Report an error if the transaction is not active
|
||||
if (!self.connection) {
|
||||
process.nextTick(function() {
|
||||
cb(new Error('The transaction is not active: ' + self.id));
|
||||
cb(new Error(g.f('The {{transaction}} is not active: %s', self.id)));
|
||||
});
|
||||
return cb.promise;
|
||||
}
|
||||
var context = {
|
||||
transaction: self,
|
||||
operation: 'rollback'
|
||||
operation: 'rollback',
|
||||
};
|
||||
|
||||
function work(done) {
|
||||
|
@ -177,5 +184,3 @@ if (Transaction) {
|
|||
}
|
||||
|
||||
TransactionMixin.Transaction = Transaction;
|
||||
|
||||
|
||||
|
|
21
lib/types.js
21
lib/types.js
|
@ -1,3 +1,9 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var Types = {};
|
||||
/**
|
||||
* Schema types
|
||||
|
@ -9,7 +15,7 @@ Types.Text = function Text(value) {
|
|||
this.value = value;
|
||||
}; // Text type
|
||||
|
||||
Types.Text.prototype.toObject = Types.Text.prototype.toJSON = function () {
|
||||
Types.Text.prototype.toObject = Types.Text.prototype.toJSON = function() {
|
||||
return this.value;
|
||||
};
|
||||
|
||||
|
@ -19,7 +25,7 @@ Types.JSON = function JSON(value) {
|
|||
}
|
||||
this.value = value;
|
||||
}; // JSON Object
|
||||
Types.JSON.prototype.toObject = Types.JSON.prototype.toJSON = function () {
|
||||
Types.JSON.prototype.toObject = Types.JSON.prototype.toJSON = function() {
|
||||
return this.value;
|
||||
};
|
||||
|
||||
|
@ -29,20 +35,19 @@ Types.Any = function Any(value) {
|
|||
}
|
||||
this.value = value;
|
||||
}; // Any Type
|
||||
Types.Any.prototype.toObject = Types.Any.prototype.toJSON = function () {
|
||||
Types.Any.prototype.toObject = Types.Any.prototype.toJSON = function() {
|
||||
return this.value;
|
||||
};
|
||||
|
||||
module.exports = function (modelTypes) {
|
||||
|
||||
module.exports = function(modelTypes) {
|
||||
var GeoPoint = require('./geo').GeoPoint;
|
||||
|
||||
for(var t in Types) {
|
||||
for (var t in Types) {
|
||||
modelTypes[t] = Types[t];
|
||||
}
|
||||
|
||||
modelTypes.schemaTypes = {};
|
||||
modelTypes.registerType = function (type, names) {
|
||||
modelTypes.registerType = function(type, names) {
|
||||
names = names || [];
|
||||
names = names.concat([type.name]);
|
||||
for (var n = 0; n < names.length; n++) {
|
||||
|
@ -64,4 +69,4 @@ module.exports = function (modelTypes) {
|
|||
modelTypes.registerType(Object);
|
||||
};
|
||||
|
||||
module.exports.Types = Types;
|
||||
module.exports.Types = Types;
|
||||
|
|
95
lib/utils.js
95
lib/utils.js
|
@ -1,3 +1,9 @@
|
|||
// Copyright IBM Corp. 2012,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
exports.safeRequire = safeRequire;
|
||||
exports.fieldsToArray = fieldsToArray;
|
||||
exports.selectFields = selectFields;
|
||||
|
@ -16,7 +22,10 @@ exports.toRegExp = toRegExp;
|
|||
exports.hasRegExpFlags = hasRegExpFlags;
|
||||
exports.idEquals = idEquals;
|
||||
exports.findIndexOf = findIndexOf;
|
||||
exports.collectTargetIds = collectTargetIds;
|
||||
exports.idName = idName;
|
||||
|
||||
var g = require('strong-globalize')();
|
||||
var traverse = require('traverse');
|
||||
var assert = require('assert');
|
||||
|
||||
|
@ -24,9 +33,9 @@ function safeRequire(module) {
|
|||
try {
|
||||
return require(module);
|
||||
} catch (e) {
|
||||
console.log('Run "npm install loopback-datasource-juggler ' + module
|
||||
+ '" command to use loopback-datasource-juggler using ' + module
|
||||
+ ' database engine');
|
||||
g.log('Run "{{npm install loopback-datasource-juggler}} %s" command ',
|
||||
'to use {{loopback-datasource-juggler}} using %s database engine',
|
||||
module, module);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
@ -50,9 +59,8 @@ function setScopeValuesFromWhere(data, where, targetModel) {
|
|||
var prop = targetModel.definition.properties[i];
|
||||
if (prop) {
|
||||
var val = where[i];
|
||||
if (typeof val !== 'object' || val instanceof prop.type
|
||||
|| prop.type.name === 'ObjectID') // MongoDB key
|
||||
{
|
||||
if (typeof val !== 'object' || val instanceof prop.type ||
|
||||
prop.type.name === 'ObjectID') { // MongoDB key
|
||||
// Only pick the {propertyName: propertyValue}
|
||||
data[i] = where[i];
|
||||
}
|
||||
|
@ -130,9 +138,8 @@ function convertToArray(include) {
|
|||
if (typeof includeEntry === 'string') {
|
||||
var obj = {};
|
||||
obj[includeEntry] = true;
|
||||
normalized.push(obj)
|
||||
}
|
||||
else{
|
||||
normalized.push(obj);
|
||||
} else {
|
||||
normalized.push(includeEntry);
|
||||
}
|
||||
}
|
||||
|
@ -169,15 +176,14 @@ function mergeQuery(base, update, spec) {
|
|||
if (!base.include) {
|
||||
base.include = update.include;
|
||||
} else {
|
||||
if (spec.nestedInclude === true){
|
||||
if (spec.nestedInclude === true) {
|
||||
//specify nestedInclude=true to force nesting of inclusions on scoped
|
||||
//queries. e.g. In physician.patients.getAsync({include: 'address'}),
|
||||
//inclusion should be on patient model, not on physician model.
|
||||
var saved = base.include;
|
||||
base.include = {};
|
||||
base.include[update.include] = saved;
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
//default behaviour of inclusion merge - merge inclusions at the same
|
||||
//level. - https://github.com/strongloop/loopback-datasource-juggler/pull/569#issuecomment-95310874
|
||||
base.include = mergeIncludes(base.include, update.include);
|
||||
|
@ -278,7 +284,7 @@ function fieldsToArray(fields, properties, excludeUnknown) {
|
|||
|
||||
function selectFields(fields) {
|
||||
// map function
|
||||
return function (obj) {
|
||||
return function(obj) {
|
||||
var result = {};
|
||||
var key;
|
||||
|
||||
|
@ -303,14 +309,14 @@ function removeUndefined(query, handleUndefined) {
|
|||
}
|
||||
// WARNING: [rfeng] Use map() will cause mongodb to produce invalid BSON
|
||||
// as traverse doesn't transform the ObjectId correctly
|
||||
return traverse(query).forEach(function (x) {
|
||||
return traverse(query).forEach(function(x) {
|
||||
if (x === undefined) {
|
||||
switch (handleUndefined) {
|
||||
case 'nullify':
|
||||
this.update(null);
|
||||
break;
|
||||
case 'throw':
|
||||
throw new Error('Unexpected `undefined` in query');
|
||||
throw new Error(g.f('Unexpected `undefined` in query'));
|
||||
break;
|
||||
case 'ignore':
|
||||
default:
|
||||
|
@ -318,8 +324,8 @@ function removeUndefined(query, handleUndefined) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!Array.isArray(x) && (typeof x === 'object' && x !== null
|
||||
&& x.constructor !== Object)) {
|
||||
if (!Array.isArray(x) && (typeof x === 'object' && x !== null &&
|
||||
x.constructor !== Object)) {
|
||||
// This object is not a plain object
|
||||
this.update(x, true); // Stop navigating into this object
|
||||
return x;
|
||||
|
@ -425,7 +431,7 @@ function defineCachedRelations(obj) {
|
|||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
value: {}
|
||||
value: {},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -436,15 +442,13 @@ function defineCachedRelations(obj) {
|
|||
* @returns {boolean}
|
||||
*/
|
||||
function isPlainObject(obj) {
|
||||
return (typeof obj === 'object') && (obj !== null)
|
||||
&& (obj.constructor === Object);
|
||||
return (typeof obj === 'object') && (obj !== null) &&
|
||||
(obj.constructor === Object);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function sortObjectsByIds(idName, ids, objects, strict) {
|
||||
ids = ids.map(function(id) {
|
||||
return (typeof id === 'object') ? String(id) : id;
|
||||
return (typeof id === 'object') ? String(id) : id;
|
||||
});
|
||||
|
||||
var indexOf = function(x) {
|
||||
|
@ -480,15 +484,15 @@ function createPromiseCallback() {
|
|||
var cb;
|
||||
|
||||
if (!global.Promise) {
|
||||
cb = function(){};
|
||||
cb = function() {};
|
||||
cb.promise = {};
|
||||
Object.defineProperty(cb.promise, 'then', { get: throwPromiseNotDefined });
|
||||
Object.defineProperty(cb.promise, 'catch', { get: throwPromiseNotDefined });
|
||||
Object.defineProperty(cb.promise, 'then', {get: throwPromiseNotDefined});
|
||||
Object.defineProperty(cb.promise, 'catch', {get: throwPromiseNotDefined});
|
||||
return cb;
|
||||
}
|
||||
|
||||
var promise = new Promise(function (resolve, reject) {
|
||||
cb = function (err, data) {
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
cb = function(err, data) {
|
||||
if (err) return reject(err);
|
||||
return resolve(data);
|
||||
};
|
||||
|
@ -499,7 +503,7 @@ function createPromiseCallback() {
|
|||
|
||||
function throwPromiseNotDefined() {
|
||||
throw new Error(
|
||||
'Your Node runtime does support ES6 Promises. ' +
|
||||
'Your Node runtime does not support ES6 Promises. ' +
|
||||
'Set "global.Promise" to your preferred implementation of promises.');
|
||||
}
|
||||
|
||||
|
@ -532,8 +536,8 @@ function toRegExp(regex) {
|
|||
var isRegExp = regex instanceof RegExp;
|
||||
|
||||
if (!(isString || isRegExp))
|
||||
return new Error('Invalid argument, must be a string, regex literal, or ' +
|
||||
'RegExp object');
|
||||
return new Error(g.f('Invalid argument, must be a string, {{regex}} literal, or ' +
|
||||
'{{RegExp}} object'));
|
||||
|
||||
if (isRegExp)
|
||||
return regex;
|
||||
|
@ -552,7 +556,7 @@ function toRegExp(regex) {
|
|||
|
||||
var hasInvalidFlags = invalidFlags.length > 0;
|
||||
if (hasInvalidFlags)
|
||||
return new Error('Invalid regex flags: ' + invalidFlags);
|
||||
return new Error(g.f('Invalid {{regex}} flags: %s', invalidFlags));
|
||||
|
||||
// strip regex delimiter forward slashes
|
||||
var expression = regex.substr(1, regex.lastIndexOf('/') - 1);
|
||||
|
@ -599,3 +603,30 @@ function findIndexOf(arr, target, isEqual) {
|
|||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object that queries targetIds.
|
||||
* @param {Array} The array of targetData
|
||||
* @param {String} The Id property name of target model
|
||||
* @returns {Object} The object that queries targetIds
|
||||
*/
|
||||
function collectTargetIds(targetData, idPropertyName) {
|
||||
var targetIds = [];
|
||||
for (var i = 0; i < targetData.length; i++) {
|
||||
var targetId = targetData[i][idPropertyName];
|
||||
targetIds.push(targetId);
|
||||
};
|
||||
var IdQuery = {
|
||||
inq: uniq(targetIds),
|
||||
};
|
||||
return IdQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the idKey of a Model.
|
||||
* @param {ModelConstructor} m - Model Constructor
|
||||
* @returns {String}
|
||||
*/
|
||||
function idName(m) {
|
||||
return m.definition.idName() || 'id';
|
||||
}
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var g = require('strong-globalize')();
|
||||
var util = require('util');
|
||||
var extend = util._extend;
|
||||
|
||||
|
@ -121,9 +128,11 @@ Validatable.validatesNumericalityOf = getConfigurator('numericality');
|
|||
* ```
|
||||
*
|
||||
* @param {String} propertyName Property name to validate.
|
||||
* @options {Object} Options
|
||||
* @options {Object} Options See below.
|
||||
* @property {Array} inArray Property must match one of the values in the array to be valid.
|
||||
* @property {String} message Optional error message if property is not valid. Default error message: "is not included in the list".
|
||||
* @property {String} message Optional error message if property is not valid.
|
||||
* Default error message: "is not included in the list".
|
||||
* @property {Boolean} allowNull Whether null values are allowed.
|
||||
*/
|
||||
Validatable.validatesInclusionOf = getConfigurator('inclusion');
|
||||
|
||||
|
@ -136,6 +145,7 @@ Validatable.validatesInclusionOf = getConfigurator('inclusion');
|
|||
* @options {Object} Options
|
||||
* @property {Array} inArray Property must match one of the values in the array to be valid.
|
||||
* @property {String} message Optional error message if property is not valid. Default error message: "is reserved".
|
||||
* @property {Boolean} allowNull Whether null values are allowed.
|
||||
*/
|
||||
Validatable.validatesExclusionOf = getConfigurator('exclusion');
|
||||
|
||||
|
@ -143,12 +153,13 @@ Validatable.validatesExclusionOf = getConfigurator('exclusion');
|
|||
* Validate format. Require a model to include a property that matches the given format.
|
||||
*
|
||||
* Require a model to include a property that matches the given format. Example:
|
||||
* `User.validatesFormat('name', {with: /\w+/});`
|
||||
* `User.validatesFormatOf('name', {with: /\w+/});`
|
||||
*
|
||||
* @param {String} propertyName Property name to validate.
|
||||
* @options {Object} Options
|
||||
* @property {RegExp} with Regular expression to validate format.
|
||||
* @property {String} message Optional error message if property is not valid. Default error message: " is invalid".
|
||||
* @property {Boolean} allowNull Whether null values are allowed.
|
||||
*/
|
||||
Validatable.validatesFormatOf = getConfigurator('format');
|
||||
|
||||
|
@ -170,6 +181,7 @@ Validatable.validatesFormatOf = getConfigurator('format');
|
|||
* @param {Function} validatorFn Custom validation function.
|
||||
* @options {Object} Options See below.
|
||||
* @property {String} message Optional error message if property is not valid. Default error message: " is invalid".
|
||||
* @property {Boolean} allowNull Whether null values are allowed.
|
||||
*/
|
||||
Validatable.validate = getConfigurator('custom');
|
||||
|
||||
|
@ -199,8 +211,9 @@ Validatable.validate = getConfigurator('custom');
|
|||
*```
|
||||
* @param {String} propertyName Property name to validate.
|
||||
* @param {Function} validatorFn Custom validation function.
|
||||
* @options {Object} Options See below
|
||||
* @options {Object} Options See below.
|
||||
* @property {String} message Optional error message if property is not valid. Default error message: " is invalid".
|
||||
* @property {Boolean} allowNull Whether null values are allowed.
|
||||
*/
|
||||
Validatable.validateAsync = getConfigurator('custom', {async: true});
|
||||
|
||||
|
@ -225,6 +238,7 @@ Validatable.validateAsync = getConfigurator('custom', {async: true});
|
|||
* @property {RegExp} with Regular expression to validate format.
|
||||
* @property {Array.<String>} scopedTo List of properties defining the scope.
|
||||
* @property {String} message Optional error message if property is not valid. Default error message: "is not unique".
|
||||
* @property {Boolean} allowNull Whether null values are allowed.
|
||||
*/
|
||||
Validatable.validatesUniquenessOf = getConfigurator('uniqueness', {async: true});
|
||||
|
||||
|
@ -233,7 +247,7 @@ Validatable.validatesUniquenessOf = getConfigurator('uniqueness', {async: true})
|
|||
/*!
|
||||
* Presence validator
|
||||
*/
|
||||
function validatePresence(attr, conf, err) {
|
||||
function validatePresence(attr, conf, err, options) {
|
||||
if (blank(this[attr])) {
|
||||
err();
|
||||
}
|
||||
|
@ -242,7 +256,7 @@ function validatePresence(attr, conf, err) {
|
|||
/*!
|
||||
* Absence validator
|
||||
*/
|
||||
function validateAbsence(attr, conf, err) {
|
||||
function validateAbsence(attr, conf, err, options) {
|
||||
if (!blank(this[attr])) {
|
||||
err();
|
||||
}
|
||||
|
@ -251,7 +265,7 @@ function validateAbsence(attr, conf, err) {
|
|||
/*!
|
||||
* Length validator
|
||||
*/
|
||||
function validateLength(attr, conf, err) {
|
||||
function validateLength(attr, conf, err, options) {
|
||||
if (nullCheck.call(this, attr, conf, err)) return;
|
||||
|
||||
var len = this[attr].length;
|
||||
|
@ -269,7 +283,7 @@ function validateLength(attr, conf, err) {
|
|||
/*!
|
||||
* Numericality validator
|
||||
*/
|
||||
function validateNumericality(attr, conf, err) {
|
||||
function validateNumericality(attr, conf, err, options) {
|
||||
if (nullCheck.call(this, attr, conf, err)) return;
|
||||
|
||||
if (typeof this[attr] !== 'number') {
|
||||
|
@ -283,29 +297,29 @@ function validateNumericality(attr, conf, err) {
|
|||
/*!
|
||||
* Inclusion validator
|
||||
*/
|
||||
function validateInclusion(attr, conf, err) {
|
||||
function validateInclusion(attr, conf, err, options) {
|
||||
if (nullCheck.call(this, attr, conf, err)) return;
|
||||
|
||||
if (!~conf.in.indexOf(this[attr])) {
|
||||
err()
|
||||
err();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Exclusion validator
|
||||
*/
|
||||
function validateExclusion(attr, conf, err) {
|
||||
function validateExclusion(attr, conf, err, options) {
|
||||
if (nullCheck.call(this, attr, conf, err)) return;
|
||||
|
||||
if (~conf.in.indexOf(this[attr])) {
|
||||
err()
|
||||
err();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Format validator
|
||||
*/
|
||||
function validateFormat(attr, conf, err) {
|
||||
function validateFormat(attr, conf, err, options) {
|
||||
if (nullCheck.call(this, attr, conf, err)) return;
|
||||
|
||||
if (typeof this[attr] === 'string') {
|
||||
|
@ -320,14 +334,22 @@ function validateFormat(attr, conf, err) {
|
|||
/*!
|
||||
* Custom validator
|
||||
*/
|
||||
function validateCustom(attr, conf, err, done) {
|
||||
function validateCustom(attr, conf, err, options, done) {
|
||||
if (typeof options === 'function') {
|
||||
done = options;
|
||||
options = {};
|
||||
}
|
||||
conf.customValidator.call(this, err, done);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Uniqueness validator
|
||||
*/
|
||||
function validateUniqueness(attr, conf, err, done) {
|
||||
function validateUniqueness(attr, conf, err, options, done) {
|
||||
if (typeof options === 'function') {
|
||||
done = options;
|
||||
options = {};
|
||||
}
|
||||
if (blank(this[attr])) {
|
||||
return process.nextTick(done);
|
||||
}
|
||||
|
@ -344,14 +366,15 @@ function validateUniqueness(attr, conf, err, done) {
|
|||
|
||||
var idName = this.constructor.definition.idName();
|
||||
var isNewRecord = this.isNewRecord();
|
||||
this.constructor.find(cond, function (error, found) {
|
||||
this.constructor.find(cond, options, function(error, found) {
|
||||
if (error) {
|
||||
err(error);
|
||||
} else if (found.length > 1) {
|
||||
err();
|
||||
} else if (found.length === 1 && idName === attr && isNewRecord) {
|
||||
err();
|
||||
} else if (found.length === 1 && (!this.id || !found[0].id || found[0].id.toString() != this.id.toString())) {
|
||||
} else if (found.length === 1 && (!this.id || !found[0].id ||
|
||||
found[0].id.toString() != this.id.toString())) {
|
||||
err();
|
||||
}
|
||||
done();
|
||||
|
@ -367,11 +390,11 @@ var validators = {
|
|||
exclusion: validateExclusion,
|
||||
format: validateFormat,
|
||||
custom: validateCustom,
|
||||
uniqueness: validateUniqueness
|
||||
uniqueness: validateUniqueness,
|
||||
};
|
||||
|
||||
function getConfigurator(name, opts) {
|
||||
return function () {
|
||||
return function() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
args[1] = args[1] || {};
|
||||
configure(this, name, args, opts);
|
||||
|
@ -410,7 +433,8 @@ function getConfigurator(name, opts) {
|
|||
* @param {Function} callback called with (valid)
|
||||
* @returns {Boolean} True if no asynchronous validation is configured and all properties pass validation.
|
||||
*/
|
||||
Validatable.prototype.isValid = function (callback, data) {
|
||||
Validatable.prototype.isValid = function(callback, data, options) {
|
||||
options = options || {};
|
||||
var valid = true, inst = this, wait = 0, async = false;
|
||||
var validations = this.constructor.validations;
|
||||
|
||||
|
@ -421,8 +445,8 @@ Validatable.prototype.isValid = function (callback, data) {
|
|||
if (typeof validations !== 'object' && !reportDiscardedProperties) {
|
||||
cleanErrors(this);
|
||||
if (callback) {
|
||||
this.trigger('validate', function (validationsDone) {
|
||||
validationsDone.call(inst, function () {
|
||||
this.trigger('validate', function(validationsDone) {
|
||||
validationsDone.call(inst, function() {
|
||||
callback(valid);
|
||||
});
|
||||
}, data, callback);
|
||||
|
@ -433,10 +457,10 @@ Validatable.prototype.isValid = function (callback, data) {
|
|||
Object.defineProperty(this, 'errors', {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
value: new Errors
|
||||
value: new Errors,
|
||||
});
|
||||
|
||||
this.trigger('validate', function (validationsDone) {
|
||||
this.trigger('validate', function(validationsDone) {
|
||||
var inst = this,
|
||||
asyncFail = false;
|
||||
|
||||
|
@ -448,8 +472,8 @@ Validatable.prototype.isValid = function (callback, data) {
|
|||
if (v.options && v.options.async) {
|
||||
async = true;
|
||||
wait += 1;
|
||||
process.nextTick(function () {
|
||||
validationFailed(inst, attr, v, done);
|
||||
process.nextTick(function() {
|
||||
validationFailed(inst, attr, v, options, done);
|
||||
});
|
||||
} else {
|
||||
if (validationFailed(inst, attr, v)) {
|
||||
|
@ -470,7 +494,7 @@ Validatable.prototype.isValid = function (callback, data) {
|
|||
}
|
||||
|
||||
if (!async) {
|
||||
validationsDone.call(inst, function () {
|
||||
validationsDone.call(inst, function() {
|
||||
if (valid) cleanErrors(inst);
|
||||
if (callback) {
|
||||
callback(valid);
|
||||
|
@ -481,7 +505,7 @@ Validatable.prototype.isValid = function (callback, data) {
|
|||
function done(fail) {
|
||||
asyncFail = asyncFail || fail;
|
||||
if (--wait === 0) {
|
||||
validationsDone.call(inst, function () {
|
||||
validationsDone.call(inst, function() {
|
||||
if (valid && !asyncFail) cleanErrors(inst);
|
||||
if (callback) {
|
||||
callback(valid && !asyncFail);
|
||||
|
@ -489,7 +513,6 @@ Validatable.prototype.isValid = function (callback, data) {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
}, data, callback);
|
||||
|
||||
if (async) {
|
||||
|
@ -499,26 +522,30 @@ Validatable.prototype.isValid = function (callback, data) {
|
|||
} else {
|
||||
return valid;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
function cleanErrors(inst) {
|
||||
Object.defineProperty(inst, 'errors', {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
value: false
|
||||
value: false,
|
||||
});
|
||||
}
|
||||
|
||||
function validationFailed(inst, attr, conf, cb) {
|
||||
function validationFailed(inst, attr, conf, options, cb) {
|
||||
var opts = conf.options || {};
|
||||
|
||||
if (typeof options === 'function') {
|
||||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
if (typeof attr !== 'string') return false;
|
||||
|
||||
// here we should check skip validation conditions (if, unless)
|
||||
// that can be specified in conf
|
||||
if (skipValidation(inst, conf, 'if')
|
||||
|| skipValidation(inst, conf, 'unless')) {
|
||||
if (skipValidation(inst, conf, 'if') ||
|
||||
skipValidation(inst, conf, 'unless')) {
|
||||
if (cb) cb(false);
|
||||
return false;
|
||||
}
|
||||
|
@ -553,8 +580,9 @@ function validationFailed(inst, attr, conf, cb) {
|
|||
if (kind !== false) inst.errors.add(attr, message, code);
|
||||
fail = true;
|
||||
});
|
||||
validatorArguments.push(options);
|
||||
if (cb) {
|
||||
validatorArguments.push(function () {
|
||||
validatorArguments.push(function() {
|
||||
cb(fail);
|
||||
});
|
||||
}
|
||||
|
@ -588,19 +616,19 @@ var defaultMessages = {
|
|||
length: {
|
||||
min: 'too short',
|
||||
max: 'too long',
|
||||
is: 'length is wrong'
|
||||
is: 'length is wrong',
|
||||
},
|
||||
common: {
|
||||
blank: 'is blank',
|
||||
'null': 'is null'
|
||||
'null': 'is null',
|
||||
},
|
||||
numericality: {
|
||||
'int': 'is not an integer',
|
||||
'number': 'is not a number'
|
||||
'number': 'is not a number',
|
||||
},
|
||||
inclusion: 'is not included in the list',
|
||||
exclusion: 'is reserved',
|
||||
uniqueness: 'is not unique'
|
||||
uniqueness: 'is not unique',
|
||||
};
|
||||
|
||||
function nullCheck(attr, conf, err) {
|
||||
|
@ -642,7 +670,7 @@ function configure(cls, validation, args, opts) {
|
|||
writable: true,
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
value: {}
|
||||
value: {},
|
||||
});
|
||||
}
|
||||
args = [].slice.call(args);
|
||||
|
@ -656,7 +684,7 @@ function configure(cls, validation, args, opts) {
|
|||
conf.customValidator = args.pop();
|
||||
}
|
||||
conf.validation = validation;
|
||||
args.forEach(function (attr) {
|
||||
args.forEach(function(attr) {
|
||||
if (typeof attr === 'string') {
|
||||
var validation = extend({}, conf);
|
||||
validation.options = opts || {};
|
||||
|
@ -670,11 +698,11 @@ function Errors() {
|
|||
Object.defineProperty(this, 'codes', {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
value: {}
|
||||
value: {},
|
||||
});
|
||||
}
|
||||
|
||||
Errors.prototype.add = function (field, message, code) {
|
||||
Errors.prototype.add = function(field, message, code) {
|
||||
code = code || 'invalid';
|
||||
if (!this[field]) {
|
||||
this[field] = [];
|
||||
|
@ -686,7 +714,7 @@ Errors.prototype.add = function (field, message, code) {
|
|||
|
||||
function ErrorCodes(messages) {
|
||||
var c = this;
|
||||
Object.keys(messages).forEach(function (field) {
|
||||
Object.keys(messages).forEach(function(field) {
|
||||
c[field] = messages[field].codes;
|
||||
});
|
||||
}
|
||||
|
@ -747,7 +775,7 @@ function ValidationError(obj) {
|
|||
this.name = 'ValidationError';
|
||||
|
||||
var context = obj && obj.constructor && obj.constructor.modelName;
|
||||
this.message = util.format(
|
||||
this.message = g.f(
|
||||
'The %s instance is not valid. Details: %s.',
|
||||
context ? '`' + context + '`' : 'model',
|
||||
formatErrors(obj.errors, obj.toJSON()) || '(unknown)'
|
||||
|
@ -758,7 +786,7 @@ function ValidationError(obj) {
|
|||
this.details = {
|
||||
context: context,
|
||||
codes: obj.errors && obj.errors.codes,
|
||||
messages: obj.errors
|
||||
messages: obj.errors,
|
||||
};
|
||||
|
||||
if (Error.captureStackTrace) {
|
||||
|
@ -808,7 +836,7 @@ function formatPropertyError(propertyName, propertyValue, errorMessage) {
|
|||
showHidden: false,
|
||||
color: false,
|
||||
// show top-level object properties only
|
||||
depth: Array.isArray(propertyValue) ? 1 : 0
|
||||
depth: Array.isArray(propertyValue) ? 1 : 0,
|
||||
});
|
||||
formattedValue = truncatePropertyString(formattedValue);
|
||||
} else {
|
||||
|
@ -834,5 +862,5 @@ function truncatePropertyString(value) {
|
|||
len -= 3;
|
||||
}
|
||||
|
||||
return value.slice(0, len-4) + '...' + tail;
|
||||
return value.slice(0, len - 4) + '...' + tail;
|
||||
}
|
||||
|
|
34
package.json
34
package.json
|
@ -1,6 +1,10 @@
|
|||
{
|
||||
"name": "loopback-datasource-juggler",
|
||||
"version": "2.44.0",
|
||||
"version": "2.57.0",
|
||||
"publishConfig": {
|
||||
"tag": "lts",
|
||||
"export-tests": true
|
||||
},
|
||||
"description": "LoopBack DataSoure Juggler",
|
||||
"keywords": [
|
||||
"StrongLoop",
|
||||
|
@ -20,18 +24,21 @@
|
|||
"depd": "./lib/browser.depd.js"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "make clean",
|
||||
"help": "make help",
|
||||
"refresh": "make refresh",
|
||||
"test": "make test"
|
||||
"lint": "eslint .",
|
||||
"test": "mocha",
|
||||
"posttest": "npm run lint"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"engines": [
|
||||
"node >= 0.6"
|
||||
],
|
||||
"devDependencies": {
|
||||
"async-iterators": "^0.2.2",
|
||||
"bluebird": "^2.9.9",
|
||||
"eslint": "^2.13.1",
|
||||
"eslint-config-loopback": "^4.0.0",
|
||||
"loopback-connector-throwing": "file:./test/fixtures/loopback-connector-throwing",
|
||||
"mocha": "^2.1.0",
|
||||
"should": "^5.0.0"
|
||||
"should": "^8.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"async": "~1.0.0",
|
||||
|
@ -39,9 +46,12 @@
|
|||
"depd": "^1.0.0",
|
||||
"inflection": "^1.6.0",
|
||||
"loopback-connector": "^2.1.0",
|
||||
"node-uuid": "^1.4.2",
|
||||
"qs": "^3.1.0",
|
||||
"traverse": "^0.6.6"
|
||||
"minimatch": "^3.0.3",
|
||||
"qs": "^6.5.0",
|
||||
"shortid": "^2.2.6",
|
||||
"strong-globalize": "^2.6.2",
|
||||
"traverse": "^0.6.6",
|
||||
"uuid": "^3.0.1"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
// Copyright IBM Corp. 2015,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
|
||||
/*
|
||||
* Describe context objects of operation hooks in comprehensive HTML table.
|
||||
* Usage:
|
||||
|
@ -12,12 +19,12 @@ var Memory = require('../lib/connectors/memory').Memory;
|
|||
var HOOK_NAMES = [
|
||||
'access',
|
||||
'before save', 'persist', 'after save',
|
||||
'before delete', 'after delete'
|
||||
'before delete', 'after delete',
|
||||
];
|
||||
|
||||
var dataSources = [
|
||||
createOptimizedDataSource(),
|
||||
createUnoptimizedDataSource()
|
||||
createUnoptimizedDataSource(),
|
||||
];
|
||||
|
||||
var observedContexts = [];
|
||||
|
@ -29,7 +36,7 @@ Promise.onPossiblyUnhandledRejection(function(err) {
|
|||
|
||||
var operations = [
|
||||
function find(ds) {
|
||||
return ds.TestModel.find({ where: { id: '1' } });
|
||||
return ds.TestModel.find({ where: { id: '1' }});
|
||||
},
|
||||
|
||||
function count(ds) {
|
||||
|
@ -42,13 +49,13 @@ var operations = [
|
|||
|
||||
function findOrCreate_found(ds) {
|
||||
return ds.TestModel.findOrCreate(
|
||||
{ where: { name: ds.existingInstance.name } },
|
||||
{ where: { name: ds.existingInstance.name }},
|
||||
{ name: ds.existingInstance.name });
|
||||
},
|
||||
|
||||
function findOrCreate_create(ds) {
|
||||
return ds.TestModel.findOrCreate(
|
||||
{ where: { name: 'new-record' } },
|
||||
{ where: { name: 'new-record' }},
|
||||
{ name: 'new-record' });
|
||||
},
|
||||
|
||||
|
@ -61,6 +68,21 @@ var operations = [
|
|||
{ id: ds.existingInstance.id, name: 'new name' });
|
||||
},
|
||||
|
||||
function replaceOrCreate_create(ds) {
|
||||
return ds.TestModel.replaceOrCreate({ id: 'not-found', name: 'not found' });
|
||||
},
|
||||
|
||||
function replaceOrCreate_update(ds) {
|
||||
return ds.TestModel.replaceOrCreate(
|
||||
{ id: ds.existingInstance.id, name: 'new name' });
|
||||
},
|
||||
|
||||
function replaceById(ds) {
|
||||
return ds.TestModel.replaceById(
|
||||
ds.existingInstance.id,
|
||||
{ name: 'new name' });
|
||||
},
|
||||
|
||||
function updateAll(ds) {
|
||||
return ds.TestModel.updateAll({ name: 'searched' }, { name: 'updated' });
|
||||
},
|
||||
|
@ -88,22 +110,11 @@ operations.forEach(function(op) {
|
|||
p = p.then(runner(op));
|
||||
});
|
||||
|
||||
p.then(report, console.error);
|
||||
|
||||
p.then(report, function(err) { console.error(err.stack); });
|
||||
|
||||
function createOptimizedDataSource() {
|
||||
var ds = new DataSource({ connector: Memory });
|
||||
ds.name = 'Optimized';
|
||||
|
||||
ds.connector.findOrCreate = function (model, query, data, callback) {
|
||||
this.all(model, query, {}, function (err, list) {
|
||||
if (err || (list && list[0])) return callback(err, list && list[0], false);
|
||||
this.create(model, data, {}, function (err) {
|
||||
callback(err, data, true);
|
||||
});
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
return ds;
|
||||
}
|
||||
|
||||
|
@ -114,6 +125,7 @@ function createUnoptimizedDataSource() {
|
|||
// disable optimized methods
|
||||
ds.connector.updateOrCreate = false;
|
||||
ds.connector.findOrCreate = false;
|
||||
ds.connector.replaceOrCreate = false;
|
||||
|
||||
return ds;
|
||||
}
|
||||
|
@ -123,7 +135,7 @@ function setupTestModels() {
|
|||
var TestModel = ds.TestModel = ds.createModel('TestModel', {
|
||||
id: { type: String, id: true, default: uid },
|
||||
name: { type: String, required: true },
|
||||
extra: { type: String, required: false }
|
||||
extra: { type: String, required: false },
|
||||
});
|
||||
});
|
||||
return Promise.resolve();
|
||||
|
@ -144,7 +156,7 @@ function runner(fn) {
|
|||
observedContexts.push({
|
||||
operation: fn.name,
|
||||
connector: ds.name,
|
||||
hooks: {}
|
||||
hooks: {},
|
||||
});
|
||||
return fn(ds);
|
||||
});
|
||||
|
@ -160,11 +172,11 @@ function resetStorage(ds) {
|
|||
});
|
||||
return TestModel.deleteAll()
|
||||
.then(function() {
|
||||
return TestModel.create({ name: 'first' })
|
||||
return TestModel.create({ name: 'first' });
|
||||
})
|
||||
.then(function(instance) {
|
||||
// Look it up from DB so that default values are retrieved
|
||||
return TestModel.findById(instance.id)
|
||||
return TestModel.findById(instance.id);
|
||||
})
|
||||
.then(function(instance) {
|
||||
ds.existingInstance = instance;
|
||||
|
@ -173,7 +185,7 @@ function resetStorage(ds) {
|
|||
.then(function() {
|
||||
HOOK_NAMES.forEach(function(hook) {
|
||||
TestModel.observe(hook, function(ctx, next) {
|
||||
var row = observedContexts[observedContexts.length-1];
|
||||
var row = observedContexts[observedContexts.length - 1];
|
||||
row.hooks[hook] = Object.keys(ctx);
|
||||
next();
|
||||
});
|
||||
|
@ -182,7 +194,7 @@ function resetStorage(ds) {
|
|||
}
|
||||
|
||||
function report() {
|
||||
console.log('<style>')
|
||||
console.log('<style>');
|
||||
console.log('td { font-family: "monospace": }');
|
||||
console.log('td, th {');
|
||||
console.log(' vertical-align: text-top;');
|
||||
|
@ -193,7 +205,7 @@ function report() {
|
|||
// merge rows where Optimized and Unoptimized produce the same context
|
||||
observedContexts.forEach(function(row, ix) {
|
||||
if (!ix) return;
|
||||
var last = observedContexts[ix-1];
|
||||
var last = observedContexts[ix - 1];
|
||||
if (row.operation != last.operation) return;
|
||||
if (JSON.stringify(row.hooks) !== JSON.stringify(last.hooks)) return;
|
||||
last.merge = true;
|
||||
|
|
|
@ -1,39 +1,45 @@
|
|||
// Copyright IBM Corp. 2015,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var should = require('./init.js');
|
||||
|
||||
var jdb = require('../');
|
||||
var DataSource = jdb.DataSource;
|
||||
|
||||
var ds, Item, Variant;
|
||||
describe('Datasource-specific field types for foreign keys', function () {
|
||||
before(function () {
|
||||
describe('Datasource-specific field types for foreign keys', function() {
|
||||
before(function() {
|
||||
ds = new DataSource('memory');
|
||||
Item = ds.define('Item', {
|
||||
"myProp": {
|
||||
"id": true,
|
||||
"type": "string",
|
||||
"memory": {
|
||||
"dataType": "string"
|
||||
}
|
||||
}
|
||||
'myProp': {
|
||||
'id': true,
|
||||
'type': 'string',
|
||||
'memory': {
|
||||
'dataType': 'string',
|
||||
},
|
||||
},
|
||||
});
|
||||
Variant = ds.define('Variant', {}, {
|
||||
relations: {
|
||||
"item": {
|
||||
"type": "belongsTo",
|
||||
"as": "item",
|
||||
"model": "Item",
|
||||
"foreignKey": "myProp"
|
||||
}
|
||||
}
|
||||
'item': {
|
||||
'type': 'belongsTo',
|
||||
'as': 'item',
|
||||
'model': 'Item',
|
||||
'foreignKey': 'myProp',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should create foreign key with database-specific field type', function (done) {
|
||||
it('should create foreign key with database-specific field type', function(done) {
|
||||
var VariantDefinition = ds.getModelDefinition('Variant');
|
||||
should.exist(VariantDefinition);
|
||||
should.exist(VariantDefinition.properties.myProp.memory);
|
||||
should.exist(VariantDefinition.properties.myProp.memory.dataType);
|
||||
VariantDefinition.properties.myProp.memory.dataType.should.be.equal("string");
|
||||
VariantDefinition.properties.myProp.memory.dataType.should.be.equal('string');
|
||||
done();
|
||||
});
|
||||
})
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
// Copyright IBM Corp. 2015,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var ModelBuilder = require('../').ModelBuilder;
|
||||
var should = require('./init');
|
||||
|
||||
|
@ -5,7 +11,7 @@ describe('async observer', function() {
|
|||
var TestModel;
|
||||
beforeEach(function defineTestModel() {
|
||||
var modelBuilder = new ModelBuilder();
|
||||
TestModel = modelBuilder.define('TestModel', { name: String });
|
||||
TestModel = modelBuilder.define('TestModel', {name: String});
|
||||
});
|
||||
|
||||
it('calls registered async observers', function(done) {
|
||||
|
@ -155,7 +161,7 @@ describe('async observer', function() {
|
|||
it('passes context to final callback', function(done) {
|
||||
var context = {};
|
||||
TestModel.notifyObserversOf('event', context, function(err, ctx) {
|
||||
(ctx || "null").should.equal(context);
|
||||
(ctx || 'null').should.equal(context);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@ -297,7 +303,7 @@ describe('async observer', function() {
|
|||
});
|
||||
|
||||
it('returns a promise when no callback is provided', function() {
|
||||
var context = { value: 'a-test-context' };
|
||||
var context = {value: 'a-test-context'};
|
||||
var p = TestModel.notifyObserversOf('event', context);
|
||||
(p !== undefined).should.be.true;
|
||||
return p.then(function(result) {
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
// This test written in mocha+should.js
|
||||
var should = require('./init.js');
|
||||
var async = require('async');
|
||||
var db, User;
|
||||
|
||||
describe('basic-querying', function () {
|
||||
|
||||
before(function (done) {
|
||||
describe('basic-querying', function() {
|
||||
before(function(done) {
|
||||
db = getSchema();
|
||||
User = db.define('User', {
|
||||
seq: {type: Number, index: true},
|
||||
|
@ -14,41 +19,39 @@ describe('basic-querying', function () {
|
|||
birthday: {type: Date, index: true},
|
||||
role: {type: String, index: true},
|
||||
order: {type: Number, index: true, sort: true},
|
||||
vip: {type: Boolean}
|
||||
vip: {type: Boolean},
|
||||
});
|
||||
|
||||
db.automigrate(done);
|
||||
|
||||
});
|
||||
|
||||
describe('ping', function () {
|
||||
it('should be able to test connections', function (done) {
|
||||
db.ping(function (err) {
|
||||
describe('ping', function() {
|
||||
it('should be able to test connections', function(done) {
|
||||
db.ping(function(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('findById', function () {
|
||||
|
||||
before(function (done) {
|
||||
describe('findById', function() {
|
||||
before(function(done) {
|
||||
User.destroyAll(done);
|
||||
});
|
||||
|
||||
it('should query by id: not found', function (done) {
|
||||
User.findById(1, function (err, u) {
|
||||
it('should query by id: not found', function(done) {
|
||||
User.findById(1, function(err, u) {
|
||||
should.not.exist(u);
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should query by id: found', function (done) {
|
||||
User.create(function (err, u) {
|
||||
it('should query by id: found', function(done) {
|
||||
User.create(function(err, u) {
|
||||
should.not.exist(err);
|
||||
should.exist(u.id);
|
||||
User.findById(u.id, function (err, u) {
|
||||
User.findById(u.id, function(err, u) {
|
||||
should.exist(u);
|
||||
should.not.exist(err);
|
||||
u.should.be.an.instanceOf(User);
|
||||
|
@ -56,19 +59,18 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('findByIds', function () {
|
||||
describe('findByIds', function() {
|
||||
var createdUsers;
|
||||
before(function(done) {
|
||||
var people = [
|
||||
{ name: 'a', vip: true },
|
||||
{ name: 'b' },
|
||||
{ name: 'c' },
|
||||
{ name: 'd', vip: true },
|
||||
{ name: 'e' },
|
||||
{ name: 'f' }
|
||||
{name: 'a', vip: true},
|
||||
{name: 'b'},
|
||||
{name: 'c'},
|
||||
{name: 'd', vip: true},
|
||||
{name: 'e'},
|
||||
{name: 'f'},
|
||||
];
|
||||
db.automigrate(['User'], function(err) {
|
||||
User.create(people, function(err, users) {
|
||||
|
@ -98,11 +100,11 @@ describe('basic-querying', function () {
|
|||
|
||||
it('should query by ids and condition', function(done) {
|
||||
User.findByIds([
|
||||
createdUsers[0].id,
|
||||
createdUsers[1].id,
|
||||
createdUsers[2].id,
|
||||
createdUsers[3].id],
|
||||
{ where: { vip: true } }, function(err, users) {
|
||||
createdUsers[0].id,
|
||||
createdUsers[1].id,
|
||||
createdUsers[2].id,
|
||||
createdUsers[3].id],
|
||||
{where: {vip: true}}, function(err, users) {
|
||||
should.exist(users);
|
||||
should.not.exist(err);
|
||||
var names = users.map(function(u) {
|
||||
|
@ -117,15 +119,21 @@ describe('basic-querying', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('find', function () {
|
||||
|
||||
describe('find', function() {
|
||||
before(seed);
|
||||
|
||||
it('should query collection', function (done) {
|
||||
User.find(function (err, users) {
|
||||
before(function setupDelayingLoadedHook() {
|
||||
User.observe('loaded', nextAfterDelay);
|
||||
});
|
||||
|
||||
after(function removeDelayingLoadHook() {
|
||||
User.removeObserver('loaded', nextAfterDelay);
|
||||
});
|
||||
|
||||
it('should query collection', function(done) {
|
||||
User.find(function(err, users) {
|
||||
should.exists(users);
|
||||
should.not.exists(err);
|
||||
users.should.have.lengthOf(6);
|
||||
|
@ -133,8 +141,8 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should query limited collection', function (done) {
|
||||
User.find({limit: 3}, function (err, users) {
|
||||
it('should query limited collection', function(done) {
|
||||
User.find({limit: 3}, function(err, users) {
|
||||
should.exists(users);
|
||||
should.not.exists(err);
|
||||
users.should.have.lengthOf(3);
|
||||
|
@ -142,8 +150,8 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should query collection with skip & limit', function (done) {
|
||||
User.find({skip: 1, limit: 4, order: 'seq'}, function (err, users) {
|
||||
it('should query collection with skip & limit', function(done) {
|
||||
User.find({skip: 1, limit: 4, order: 'seq'}, function(err, users) {
|
||||
should.exists(users);
|
||||
should.not.exists(err);
|
||||
users[0].seq.should.be.eql(1);
|
||||
|
@ -152,8 +160,8 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should query collection with offset & limit', function (done) {
|
||||
User.find({offset: 2, limit: 3, order: 'seq'}, function (err, users) {
|
||||
it('should query collection with offset & limit', function(done) {
|
||||
User.find({offset: 2, limit: 3, order: 'seq'}, function(err, users) {
|
||||
should.exists(users);
|
||||
should.not.exists(err);
|
||||
users[0].seq.should.be.eql(2);
|
||||
|
@ -162,8 +170,8 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should query filtered collection', function (done) {
|
||||
User.find({where: {role: 'lead'}}, function (err, users) {
|
||||
it('should query filtered collection', function(done) {
|
||||
User.find({where: {role: 'lead'}}, function(err, users) {
|
||||
should.exists(users);
|
||||
should.not.exists(err);
|
||||
users.should.have.lengthOf(2);
|
||||
|
@ -171,30 +179,30 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should query collection sorted by numeric field', function (done) {
|
||||
User.find({order: 'order'}, function (err, users) {
|
||||
it('should query collection sorted by numeric field', function(done) {
|
||||
User.find({order: 'order'}, function(err, users) {
|
||||
should.exists(users);
|
||||
should.not.exists(err);
|
||||
users.forEach(function (u, i) {
|
||||
users.forEach(function(u, i) {
|
||||
u.order.should.eql(i + 1);
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should query collection desc sorted by numeric field', function (done) {
|
||||
User.find({order: 'order DESC'}, function (err, users) {
|
||||
it('should query collection desc sorted by numeric field', function(done) {
|
||||
User.find({order: 'order DESC'}, function(err, users) {
|
||||
should.exists(users);
|
||||
should.not.exists(err);
|
||||
users.forEach(function (u, i) {
|
||||
users.forEach(function(u, i) {
|
||||
u.order.should.eql(users.length - i);
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should query collection sorted by string field', function (done) {
|
||||
User.find({order: 'name'}, function (err, users) {
|
||||
it('should query collection sorted by string field', function(done) {
|
||||
User.find({order: 'name'}, function(err, users) {
|
||||
should.exists(users);
|
||||
should.not.exists(err);
|
||||
users.shift().name.should.equal('George Harrison');
|
||||
|
@ -204,8 +212,8 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should query collection desc sorted by string field', function (done) {
|
||||
User.find({order: 'name DESC'}, function (err, users) {
|
||||
it('should query collection desc sorted by string field', function(done) {
|
||||
User.find({order: 'name DESC'}, function(err, users) {
|
||||
should.exists(users);
|
||||
should.not.exists(err);
|
||||
users.pop().name.should.equal('George Harrison');
|
||||
|
@ -215,53 +223,65 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should support "and" operator that is satisfied', function (done) {
|
||||
it('should query sorted desc by order integer field even though there' +
|
||||
'is an async model loaded hook', function(done) {
|
||||
User.find({order: 'order DESC'}, function(err, users) {
|
||||
if (err) return done(err);
|
||||
|
||||
should.exists(users);
|
||||
var order = users.map(function(u) { return u.order; });
|
||||
order.should.eql([6, 5, 4, 3, 2, 1]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should support "and" operator that is satisfied', function(done) {
|
||||
User.find({where: {and: [
|
||||
{name: 'John Lennon'},
|
||||
{role: 'lead'}
|
||||
]}}, function (err, users) {
|
||||
{role: 'lead'},
|
||||
]}}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.should.have.property('length', 1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should support "and" operator that is not satisfied', function (done) {
|
||||
it('should support "and" operator that is not satisfied', function(done) {
|
||||
User.find({where: {and: [
|
||||
{name: 'John Lennon'},
|
||||
{role: 'member'}
|
||||
]}}, function (err, users) {
|
||||
{role: 'member'},
|
||||
]}}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.should.have.property('length', 0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should support "or" that is satisfied', function (done) {
|
||||
it('should support "or" that is satisfied', function(done) {
|
||||
User.find({where: {or: [
|
||||
{name: 'John Lennon'},
|
||||
{role: 'lead'}
|
||||
]}}, function (err, users) {
|
||||
{role: 'lead'},
|
||||
]}}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.should.have.property('length', 2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should support "or" operator that is not satisfied', function (done) {
|
||||
it('should support "or" operator that is not satisfied', function(done) {
|
||||
User.find({where: {or: [
|
||||
{name: 'XYZ'},
|
||||
{role: 'Hello1'}
|
||||
]}}, function (err, users) {
|
||||
{role: 'Hello1'},
|
||||
]}}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.should.have.property('length', 0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should support date "gte" that is satisfied', function (done) {
|
||||
User.find({order: 'seq', where: { birthday: { "gte": new Date('1980-12-08') }
|
||||
}}, function (err, users) {
|
||||
it('should support date "gte" that is satisfied', function(done) {
|
||||
User.find({order: 'seq', where: {birthday: {'gte': new Date('1980-12-08')},
|
||||
}}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.should.have.property('length', 1);
|
||||
users[0].name.should.equal('John Lennon');
|
||||
|
@ -269,18 +289,18 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should support date "gt" that is not satisfied', function (done) {
|
||||
User.find({order: 'seq', where: { birthday: { "gt": new Date('1980-12-08') }
|
||||
}}, function (err, users) {
|
||||
it('should support date "gt" that is not satisfied', function(done) {
|
||||
User.find({order: 'seq', where: {birthday: {'gt': new Date('1980-12-08')},
|
||||
}}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.should.have.property('length', 0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should support date "gt" that is satisfied', function (done) {
|
||||
User.find({order: 'seq', where: { birthday: { "gt": new Date('1980-12-07') }
|
||||
}}, function (err, users) {
|
||||
it('should support date "gt" that is satisfied', function(done) {
|
||||
User.find({order: 'seq', where: {birthday: {'gt': new Date('1980-12-07')},
|
||||
}}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.should.have.property('length', 1);
|
||||
users[0].name.should.equal('John Lennon');
|
||||
|
@ -288,9 +308,9 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should support date "lt" that is satisfied', function (done) {
|
||||
User.find({order: 'seq', where: { birthday: { "lt": new Date('1980-12-07') }
|
||||
}}, function (err, users) {
|
||||
it('should support date "lt" that is satisfied', function(done) {
|
||||
User.find({order: 'seq', where: {birthday: {'lt': new Date('1980-12-07')},
|
||||
}}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.should.have.property('length', 1);
|
||||
users[0].name.should.equal('Paul McCartney');
|
||||
|
@ -298,9 +318,9 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should support number "gte" that is satisfied', function (done) {
|
||||
User.find({order: 'seq', where: { order: { "gte": 3}
|
||||
}}, function (err, users) {
|
||||
it('should support number "gte" that is satisfied', function(done) {
|
||||
User.find({order: 'seq', where: {order: {'gte': 3},
|
||||
}}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.should.have.property('length', 4);
|
||||
users[0].name.should.equal('George Harrison');
|
||||
|
@ -308,18 +328,18 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should support number "gt" that is not satisfied', function (done) {
|
||||
User.find({order: 'seq', where: { order: { "gt": 6 }
|
||||
}}, function (err, users) {
|
||||
it('should support number "gt" that is not satisfied', function(done) {
|
||||
User.find({order: 'seq', where: {order: {'gt': 6},
|
||||
}}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.should.have.property('length', 0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should support number "gt" that is satisfied', function (done) {
|
||||
User.find({order: 'seq', where: { order: { "gt": 5 }
|
||||
}}, function (err, users) {
|
||||
it('should support number "gt" that is satisfied', function(done) {
|
||||
User.find({order: 'seq', where: {order: {'gt': 5},
|
||||
}}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.should.have.property('length', 1);
|
||||
users[0].name.should.equal('Ringo Starr');
|
||||
|
@ -327,9 +347,9 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should support number "lt" that is satisfied', function (done) {
|
||||
User.find({order: 'seq', where: { order: { "lt": 2 }
|
||||
}}, function (err, users) {
|
||||
it('should support number "lt" that is satisfied', function(done) {
|
||||
User.find({order: 'seq', where: {order: {'lt': 2},
|
||||
}}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.should.have.property('length', 1);
|
||||
users[0].name.should.equal('Paul McCartney');
|
||||
|
@ -337,36 +357,36 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should support number "gt" that is satisfied by null value', function (done) {
|
||||
User.find({order: 'seq', where: { order: { "gt": null }
|
||||
}}, function (err, users) {
|
||||
it('should support number "gt" that is satisfied by null value', function(done) {
|
||||
User.find({order: 'seq', where: {order: {'gt': null},
|
||||
}}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.should.have.property('length', 0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should support number "lt" that is not satisfied by null value', function (done) {
|
||||
User.find({order: 'seq', where: { order: { "lt": null }
|
||||
}}, function (err, users) {
|
||||
it('should support number "lt" that is not satisfied by null value', function(done) {
|
||||
User.find({order: 'seq', where: {order: {'lt': null},
|
||||
}}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.should.have.property('length', 0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should support string "gte" that is satisfied by null value', function (done) {
|
||||
User.find({order: 'seq', where: { name: { "gte": null}
|
||||
}}, function (err, users) {
|
||||
it('should support string "gte" that is satisfied by null value', function(done) {
|
||||
User.find({order: 'seq', where: {name: {'gte': null},
|
||||
}}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.should.have.property('length', 0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should support string "gte" that is satisfied', function (done) {
|
||||
User.find({order: 'seq', where: { name: { "gte": 'Paul McCartney'}
|
||||
}}, function (err, users) {
|
||||
it('should support string "gte" that is satisfied', function(done) {
|
||||
User.find({order: 'seq', where: {name: {'gte': 'Paul McCartney'},
|
||||
}}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.should.have.property('length', 4);
|
||||
users[0].name.should.equal('Paul McCartney');
|
||||
|
@ -374,18 +394,18 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should support string "gt" that is not satisfied', function (done) {
|
||||
User.find({order: 'seq', where: { name: { "gt": 'xyz' }
|
||||
}}, function (err, users) {
|
||||
it('should support string "gt" that is not satisfied', function(done) {
|
||||
User.find({order: 'seq', where: {name: {'gt': 'xyz'},
|
||||
}}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.should.have.property('length', 0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should support string "gt" that is satisfied', function (done) {
|
||||
User.find({order: 'seq', where: { name: { "gt": 'Paul McCartney' }
|
||||
}}, function (err, users) {
|
||||
it('should support string "gt" that is satisfied', function(done) {
|
||||
User.find({order: 'seq', where: {name: {'gt': 'Paul McCartney'},
|
||||
}}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.should.have.property('length', 3);
|
||||
users[0].name.should.equal('Ringo Starr');
|
||||
|
@ -393,9 +413,9 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should support string "lt" that is satisfied', function (done) {
|
||||
User.find({order: 'seq', where: { name: { "lt": 'Paul McCartney' }
|
||||
}}, function (err, users) {
|
||||
it('should support string "lt" that is satisfied', function(done) {
|
||||
User.find({order: 'seq', where: {name: {'lt': 'Paul McCartney'},
|
||||
}}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.should.have.property('length', 2);
|
||||
users[0].name.should.equal('John Lennon');
|
||||
|
@ -403,9 +423,9 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should support boolean "gte" that is satisfied', function (done) {
|
||||
User.find({order: 'seq', where: { vip: { "gte": true}
|
||||
}}, function (err, users) {
|
||||
it('should support boolean "gte" that is satisfied', function(done) {
|
||||
User.find({order: 'seq', where: {vip: {'gte': true},
|
||||
}}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.should.have.property('length', 3);
|
||||
users[0].name.should.equal('John Lennon');
|
||||
|
@ -413,18 +433,18 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should support boolean "gt" that is not satisfied', function (done) {
|
||||
User.find({order: 'seq', where: { vip: { "gt": true }
|
||||
}}, function (err, users) {
|
||||
it('should support boolean "gt" that is not satisfied', function(done) {
|
||||
User.find({order: 'seq', where: {vip: {'gt': true},
|
||||
}}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.should.have.property('length', 0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should support boolean "gt" that is satisfied', function (done) {
|
||||
User.find({order: 'seq', where: { vip: { "gt": false }
|
||||
}}, function (err, users) {
|
||||
it('should support boolean "gt" that is satisfied', function(done) {
|
||||
User.find({order: 'seq', where: {vip: {'gt': false},
|
||||
}}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.should.have.property('length', 3);
|
||||
users[0].name.should.equal('John Lennon');
|
||||
|
@ -432,9 +452,9 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should support boolean "lt" that is satisfied', function (done) {
|
||||
User.find({order: 'seq', where: { vip: { "lt": true }
|
||||
}}, function (err, users) {
|
||||
it('should support boolean "lt" that is satisfied', function(done) {
|
||||
User.find({order: 'seq', where: {vip: {'lt': true},
|
||||
}}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
users.should.have.property('length', 2);
|
||||
users[0].name.should.equal('George Harrison');
|
||||
|
@ -442,17 +462,87 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('supports non-empty inq', function() {
|
||||
// note there is no record with seq=100
|
||||
return User.find({where: {seq: {inq: [0, 1, 100]}}})
|
||||
.then(function(result) {
|
||||
var seqsFound = result.map(function(r) { return r.seq; });
|
||||
should(seqsFound.sort()).eql([0, 1]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should only include fields as specified', function (done) {
|
||||
it('supports empty inq', function() {
|
||||
return User.find({where: {seq: {inq: []}}})
|
||||
.then(function(result) {
|
||||
var seqsFound = result.map(function(r) { return r.seq; });
|
||||
should(seqsFound).eql([]);
|
||||
});
|
||||
});
|
||||
|
||||
var itWhenIlikeSupported = connectorCapabilities.ilike ? it : it.skip.bind(it);
|
||||
|
||||
itWhenIlikeSupported('should support "like" that is satisfied', function(done) {
|
||||
User.find({where: {name: {like: 'John'}}}, function(err, users) {
|
||||
if (err) return done(err);
|
||||
users.length.should.equal(1);
|
||||
users[0].name.should.equal('John Lennon');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
itWhenIlikeSupported('should support "like" that is not satisfied', function(done) {
|
||||
User.find({where: {name: {like: 'Bob'}}}, function(err, users) {
|
||||
if (err) return done(err);
|
||||
users.length.should.equal(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
var itWhenNilikeSupported = connectorCapabilities.nilike ? it : it.skip.bind(it);
|
||||
|
||||
itWhenNilikeSupported('should support "nlike" that is satisfied', function(done) {
|
||||
User.find({where: {name: {nlike: 'John'}}}, function(err, users) {
|
||||
if (err) return done(err);
|
||||
users.length.should.equal(5);
|
||||
users[0].name.should.equal('Paul McCartney');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
itWhenIlikeSupported('should support "ilike" that is satisfied', function(done) {
|
||||
User.find({where: {name: {ilike: 'john'}}}, function(err, users) {
|
||||
if (err) return done(err);
|
||||
users.length.should.equal(1);
|
||||
users[0].name.should.equal('John Lennon');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
itWhenIlikeSupported('should support "ilike" that is not satisfied', function(done) {
|
||||
User.find({where: {name: {ilike: 'bob'}}}, function(err, users) {
|
||||
if (err) return done(err);
|
||||
users.length.should.equal(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
itWhenNilikeSupported('should support "nilike" that is satisfied', function(done) {
|
||||
User.find({where: {name: {nilike: 'john'}}}, function(err, users) {
|
||||
if (err) return done(err);
|
||||
users.length.should.equal(5);
|
||||
users[0].name.should.equal('Paul McCartney');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should only include fields as specified', function(done) {
|
||||
var remaining = 0;
|
||||
|
||||
function sample(fields) {
|
||||
|
||||
return {
|
||||
expect: function (arr) {
|
||||
expect: function(arr) {
|
||||
remaining++;
|
||||
User.find({fields: fields}, function (err, users) {
|
||||
|
||||
User.find({fields: fields}, function(err, users) {
|
||||
remaining--;
|
||||
if (err) return done(err);
|
||||
|
||||
|
@ -462,11 +552,11 @@ describe('basic-querying', function () {
|
|||
done();
|
||||
}
|
||||
|
||||
users.forEach(function (user) {
|
||||
users.forEach(function(user) {
|
||||
var obj = user.toObject();
|
||||
|
||||
Object.keys(obj)
|
||||
.forEach(function (key) {
|
||||
.forEach(function(key) {
|
||||
// if the obj has an unexpected value
|
||||
if (obj[key] !== undefined && arr.indexOf(key) === -1) {
|
||||
console.log('Given fields:', fields);
|
||||
|
@ -477,8 +567,8 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
sample({name: true}).expect(['name']);
|
||||
|
@ -489,15 +579,13 @@ describe('basic-querying', function () {
|
|||
sample(['id']).expect(['id']);
|
||||
sample(['email']).expect(['email']);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('count', function () {
|
||||
|
||||
describe('count', function() {
|
||||
before(seed);
|
||||
|
||||
it('should query total count', function (done) {
|
||||
User.count(function (err, n) {
|
||||
it('should query total count', function(done) {
|
||||
User.count(function(err, n) {
|
||||
should.not.exist(err);
|
||||
should.exist(n);
|
||||
n.should.equal(6);
|
||||
|
@ -505,8 +593,8 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should query filtered count', function (done) {
|
||||
User.count({role: 'lead'}, function (err, n) {
|
||||
it('should query filtered count', function(done) {
|
||||
User.count({role: 'lead'}, function(err, n) {
|
||||
should.not.exist(err);
|
||||
should.exist(n);
|
||||
n.should.equal(2);
|
||||
|
@ -515,13 +603,12 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe('findOne', function () {
|
||||
|
||||
describe('findOne', function() {
|
||||
before(seed);
|
||||
|
||||
it('should find first record (default sort by id)', function (done) {
|
||||
User.all({order: 'id'}, function (err, users) {
|
||||
User.findOne(function (e, u) {
|
||||
it('should find first record (default sort by id)', function(done) {
|
||||
User.all({order: 'id'}, function(err, users) {
|
||||
User.findOne(function(e, u) {
|
||||
should.not.exist(e);
|
||||
should.exist(u);
|
||||
u.id.toString().should.equal(users[0].id.toString());
|
||||
|
@ -530,8 +617,8 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should find first record', function (done) {
|
||||
User.findOne({order: 'order'}, function (e, u) {
|
||||
it('should find first record', function(done) {
|
||||
User.findOne({order: 'order'}, function(e, u) {
|
||||
should.not.exist(e);
|
||||
should.exist(u);
|
||||
u.order.should.equal(1);
|
||||
|
@ -540,8 +627,8 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should find last record', function (done) {
|
||||
User.findOne({order: 'order DESC'}, function (e, u) {
|
||||
it('should find last record', function(done) {
|
||||
User.findOne({order: 'order DESC'}, function(e, u) {
|
||||
should.not.exist(e);
|
||||
should.exist(u);
|
||||
u.order.should.equal(6);
|
||||
|
@ -550,11 +637,11 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should find last record in filtered set', function (done) {
|
||||
it('should find last record in filtered set', function(done) {
|
||||
User.findOne({
|
||||
where: {role: 'lead'},
|
||||
order: 'order DESC'
|
||||
}, function (e, u) {
|
||||
order: 'order DESC',
|
||||
}, function(e, u) {
|
||||
should.not.exist(e);
|
||||
should.exist(u);
|
||||
u.order.should.equal(2);
|
||||
|
@ -563,25 +650,23 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should work even when find by id', function (done) {
|
||||
User.findOne(function (e, u) {
|
||||
User.findOne({where: {id: u.id}}, function (err, user) {
|
||||
it('should work even when find by id', function(done) {
|
||||
User.findOne(function(e, u) {
|
||||
User.findOne({where: {id: u.id}}, function(err, user) {
|
||||
should.not.exist(err);
|
||||
should.exist(user);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('exists', function () {
|
||||
|
||||
describe('exists', function() {
|
||||
before(seed);
|
||||
|
||||
it('should check whether record exist', function (done) {
|
||||
User.findOne(function (e, u) {
|
||||
User.exists(u.id, function (err, exists) {
|
||||
it('should check whether record exist', function(done) {
|
||||
User.findOne(function(e, u) {
|
||||
User.exists(u.id, function(err, exists) {
|
||||
should.not.exist(err);
|
||||
should.exist(exists);
|
||||
exists.should.be.ok;
|
||||
|
@ -590,9 +675,9 @@ describe('basic-querying', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should check whether record not exist', function (done) {
|
||||
User.destroyAll(function () {
|
||||
User.exists(42, function (err, exists) {
|
||||
it('should check whether record not exist', function(done) {
|
||||
User.destroyAll(function() {
|
||||
User.exists(42, function(err, exists) {
|
||||
should.not.exist(err);
|
||||
exists.should.not.be.ok;
|
||||
done();
|
||||
|
@ -627,9 +712,9 @@ describe.skip('queries', function() {
|
|||
var db = getSchema();
|
||||
Todo = db.define('Todo', {
|
||||
id: false,
|
||||
content: {type: 'string'}
|
||||
content: {type: 'string'},
|
||||
}, {
|
||||
idInjection: false
|
||||
idInjection: false,
|
||||
});
|
||||
db.automigrate(['Todo'], done);
|
||||
});
|
||||
|
@ -638,7 +723,7 @@ describe.skip('queries', function() {
|
|||
Todo.create([
|
||||
{content: 'Buy eggs'},
|
||||
{content: 'Buy milk'},
|
||||
{content: 'Buy sausages'}
|
||||
{content: 'Buy sausages'},
|
||||
], done);
|
||||
});
|
||||
});
|
||||
|
@ -737,15 +822,15 @@ describe.skip('queries', function() {
|
|||
|
||||
it('should return an error for deleteById/destroyById/removeById',
|
||||
function(done) {
|
||||
var aliases = ['deleteById', 'destroyById', 'removeById'];
|
||||
async.each(aliases, function(alias, cb) {
|
||||
Todo[alias](1, function(err) {
|
||||
should.exist(err);
|
||||
err.message.should.equal(expectedErrMsg);
|
||||
cb();
|
||||
var aliases = ['deleteById', 'destroyById', 'removeById'];
|
||||
async.each(aliases, function(alias, cb) {
|
||||
Todo[alias](1, function(err) {
|
||||
should.exist(err);
|
||||
err.message.should.equal(expectedErrMsg);
|
||||
cb();
|
||||
});
|
||||
}, done);
|
||||
});
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should return an error for instance.save', function(done) {
|
||||
var todo = new Todo();
|
||||
|
@ -798,7 +883,7 @@ function seed(done) {
|
|||
role: 'lead',
|
||||
birthday: new Date('1980-12-08'),
|
||||
order: 2,
|
||||
vip: true
|
||||
vip: true,
|
||||
},
|
||||
{
|
||||
seq: 1,
|
||||
|
@ -807,18 +892,23 @@ function seed(done) {
|
|||
role: 'lead',
|
||||
birthday: new Date('1942-06-18'),
|
||||
order: 1,
|
||||
vip: true
|
||||
vip: true,
|
||||
},
|
||||
{seq: 2, name: 'George Harrison', order: 5, vip: false},
|
||||
{seq: 3, name: 'Ringo Starr', order: 6, vip: false},
|
||||
{seq: 4, name: 'Pete Best', order: 4},
|
||||
{seq: 5, name: 'Stuart Sutcliffe', order: 3, vip: true}
|
||||
{seq: 5, name: 'Stuart Sutcliffe', order: 3, vip: true},
|
||||
];
|
||||
|
||||
async.series([
|
||||
User.destroyAll.bind(User),
|
||||
function(cb) {
|
||||
async.each(beatles, User.create.bind(User), cb);
|
||||
}
|
||||
},
|
||||
], done);
|
||||
}
|
||||
|
||||
function nextAfterDelay(ctx, next) {
|
||||
var randomTimeoutTrigger = Math.floor(Math.random() * 100);
|
||||
setTimeout(function() { process.nextTick(next); }, randomTimeoutTrigger);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
require('./datatype.test.js');
|
||||
require('./basic-querying.test.js');
|
||||
require('./manipulation.test.js');
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
// Copyright IBM Corp. 2011,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var Schema = require('../index').Schema;
|
||||
var Text = Schema.Text;
|
||||
|
||||
|
@ -15,7 +21,6 @@ function skip(name) {
|
|||
}
|
||||
|
||||
module.exports = function testSchema(exportCasesHere, dataSource) {
|
||||
|
||||
batch = exportCasesHere;
|
||||
schemaName = dataSource.name;
|
||||
if (dataSource.name.match(/^\/.*\/test\/\.\.$/)) {
|
||||
|
@ -23,13 +28,13 @@ module.exports = function testSchema(exportCasesHere, dataSource) {
|
|||
}
|
||||
var start;
|
||||
|
||||
batch['should connect to database'] = function (test) {
|
||||
batch['should connect to database'] = function(test) {
|
||||
start = Date.now();
|
||||
if (dataSource.connected) return test.done();
|
||||
dataSource.on('connected', test.done);
|
||||
};
|
||||
|
||||
dataSource.log = function (a) {
|
||||
dataSource.log = function(a) {
|
||||
console.log(a);
|
||||
nbSchemaRequests++;
|
||||
};
|
||||
|
@ -38,7 +43,7 @@ module.exports = function testSchema(exportCasesHere, dataSource) {
|
|||
|
||||
testOrm(dataSource);
|
||||
|
||||
batch['all tests done'] = function (test) {
|
||||
batch['all tests done'] = function(test) {
|
||||
test.done();
|
||||
process.nextTick(allTestsDone);
|
||||
};
|
||||
|
@ -47,26 +52,25 @@ module.exports = function testSchema(exportCasesHere, dataSource) {
|
|||
// dataSource.disconnect();
|
||||
console.log('Test done in %dms\n', Date.now() - start);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Object.defineProperty(module.exports, 'it', {
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
value: it
|
||||
value: it,
|
||||
});
|
||||
|
||||
Object.defineProperty(module.exports, 'skip', {
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
value: skip
|
||||
value: skip,
|
||||
});
|
||||
|
||||
function clearAndCreate(model, data, callback) {
|
||||
var createdItems = [];
|
||||
model.destroyAll(function () {
|
||||
model.destroyAll(function() {
|
||||
nextItem(null, null);
|
||||
});
|
||||
|
||||
|
@ -90,57 +94,56 @@ function testOrm(dataSource) {
|
|||
|
||||
var Post, User, Passport, Log, Dog;
|
||||
|
||||
it('should define class', function (test) {
|
||||
|
||||
it('should define class', function(test) {
|
||||
User = dataSource.define('User', {
|
||||
name: { type: String, index: true },
|
||||
email: { type: String, index: true },
|
||||
name: {type: String, index: true},
|
||||
email: {type: String, index: true},
|
||||
bio: Text,
|
||||
approved: Boolean,
|
||||
joinedAt: Date,
|
||||
age: Number,
|
||||
passwd: { type: String, index: true }
|
||||
passwd: {type: String, index: true},
|
||||
});
|
||||
|
||||
Dog = dataSource.define('Dog', {
|
||||
name: { type: String, limit: 64, allowNull: false }
|
||||
name: {type: String, limit: 64, allowNull: false},
|
||||
});
|
||||
|
||||
Log = dataSource.define('Log', {
|
||||
ownerId: { type: Number, allowNull: true },
|
||||
name: { type: String, limit: 64, allowNull: false }
|
||||
ownerId: {type: Number, allowNull: true},
|
||||
name: {type: String, limit: 64, allowNull: false},
|
||||
});
|
||||
|
||||
Log.belongsTo(Dog, {as: 'owner', foreignKey: 'ownerId'});
|
||||
|
||||
dataSource.extendModel('User', {
|
||||
settings: { type: Schema.JSON },
|
||||
extra: Object
|
||||
settings: {type: Schema.JSON},
|
||||
extra: Object,
|
||||
});
|
||||
|
||||
var newuser = new User({settings: {hey: 'you'}});
|
||||
test.ok(newuser.settings);
|
||||
|
||||
Post = dataSource.define('Post', {
|
||||
title: { type: String, length: 255, index: true },
|
||||
subject: { type: String },
|
||||
content: { type: Text },
|
||||
date: { type: Date, default: function () {
|
||||
return new Date
|
||||
}, index: true },
|
||||
published: { type: Boolean, default: false, index: true },
|
||||
title: {type: String, length: 255, index: true},
|
||||
subject: {type: String},
|
||||
content: {type: Text},
|
||||
date: {type: Date, default: function() {
|
||||
return new Date;
|
||||
}, index: true},
|
||||
published: {type: Boolean, default: false, index: true},
|
||||
likes: [],
|
||||
related: [RelatedPost]
|
||||
related: [RelatedPost],
|
||||
}, {table: 'posts'});
|
||||
|
||||
function RelatedPost() {
|
||||
}
|
||||
|
||||
RelatedPost.prototype.someMethod = function () {
|
||||
RelatedPost.prototype.someMethod = function() {
|
||||
return this.parent;
|
||||
};
|
||||
|
||||
Post.validateAsync('title', function (err, done) {
|
||||
Post.validateAsync('title', function(err, done) {
|
||||
process.nextTick(done);
|
||||
});
|
||||
|
||||
|
@ -166,7 +169,7 @@ function testOrm(dataSource) {
|
|||
// post.author(user) -- setter when called with object
|
||||
|
||||
Passport = dataSource.define('Passport', {
|
||||
number: String
|
||||
number: String,
|
||||
});
|
||||
|
||||
Passport.belongsTo(User, {as: 'owner', foreignKey: 'ownerId'});
|
||||
|
@ -183,7 +186,7 @@ function testOrm(dataSource) {
|
|||
// instance methods
|
||||
test.ok(user.save instanceof Function);
|
||||
|
||||
dataSource.automigrate(function (err) {
|
||||
dataSource.automigrate(function(err) {
|
||||
if (err) {
|
||||
console.log('Error while migrating');
|
||||
console.log(err);
|
||||
|
@ -191,10 +194,9 @@ function testOrm(dataSource) {
|
|||
test.done();
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('should initialize object properly', function (test) {
|
||||
it('should initialize object properly', function(test) {
|
||||
var hw = 'Hello word',
|
||||
now = Date.now(),
|
||||
post = new Post({title: hw}),
|
||||
|
@ -213,31 +215,31 @@ function testOrm(dataSource) {
|
|||
test.done();
|
||||
});
|
||||
|
||||
it('should save object', function (test) {
|
||||
it('should save object', function(test) {
|
||||
var title = 'Initial title', title2 = 'Hello world',
|
||||
date = new Date;
|
||||
|
||||
Post.create({
|
||||
title: title,
|
||||
date: date
|
||||
}, function (err, obj) {
|
||||
date: date,
|
||||
}, function(err, obj) {
|
||||
test.ok(obj.id, 'Object id should present');
|
||||
test.equals(obj.title, title);
|
||||
// test.equals(obj.date, date);
|
||||
obj.title = title2;
|
||||
test.ok(obj.propertyChanged('title'), 'Title changed');
|
||||
obj.save(function (err, obj) {
|
||||
obj.save(function(err, obj) {
|
||||
test.equal(obj.title, title2);
|
||||
test.ok(!obj.propertyChanged('title'));
|
||||
|
||||
var p = new Post({title: 1});
|
||||
p.title = 2;
|
||||
p.save(function (err, obj) {
|
||||
p.save(function(err, obj) {
|
||||
test.ok(!p.propertyChanged('title'));
|
||||
p.title = 3;
|
||||
test.ok(p.propertyChanged('title'));
|
||||
test.equal(p.title_was, 2);
|
||||
p.save(function () {
|
||||
p.save(function() {
|
||||
test.equal(p.title_was, 3);
|
||||
test.ok(!p.propertyChanged('title'));
|
||||
test.done();
|
||||
|
@ -247,18 +249,18 @@ function testOrm(dataSource) {
|
|||
});
|
||||
});
|
||||
|
||||
it('should create object with initial data', function (test) {
|
||||
it('should create object with initial data', function(test) {
|
||||
var title = 'Initial title',
|
||||
date = new Date;
|
||||
|
||||
Post.create({
|
||||
title: title,
|
||||
date: date
|
||||
}, function (err, obj) {
|
||||
date: date,
|
||||
}, function(err, obj) {
|
||||
test.ok(obj.id);
|
||||
test.equals(obj.title, title);
|
||||
test.equals(obj.date, date);
|
||||
Post.findById(obj.id, function () {
|
||||
Post.findById(obj.id, function() {
|
||||
test.equal(obj.title, title);
|
||||
test.equal(obj.date.toString(), date.toString());
|
||||
test.done();
|
||||
|
@ -266,13 +268,13 @@ function testOrm(dataSource) {
|
|||
});
|
||||
});
|
||||
|
||||
it('should save only dataSource-defined field in database', function (test) {
|
||||
Post.create({title: '1602', nonSchemaField: 'some value'}, function (err, post) {
|
||||
it('should save only dataSource-defined field in database', function(test) {
|
||||
Post.create({title: '1602', nonSchemaField: 'some value'}, function(err, post) {
|
||||
test.ok(!post.nonSchemaField);
|
||||
post.a = 1;
|
||||
post.save(function () {
|
||||
post.save(function() {
|
||||
test.ok(post.a);
|
||||
post.reload(function (err, psto) {
|
||||
post.reload(function(err, psto) {
|
||||
test.ok(!psto.a);
|
||||
test.done();
|
||||
});
|
||||
|
@ -296,24 +298,25 @@ function testOrm(dataSource) {
|
|||
});
|
||||
*/
|
||||
|
||||
it('should not re-instantiate object on saving', function (test) {
|
||||
it('should not re-instantiate object on saving', function(test) {
|
||||
var title = 'Initial title';
|
||||
var post = new Post({title: title});
|
||||
post.save(function (err, savedPost) {
|
||||
post.save(function(err, savedPost) {
|
||||
test.strictEqual(post, savedPost);
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should destroy object', function (test) {
|
||||
Post.create(function (err, post) {
|
||||
Post.exists(post.id, function (err, exists) {
|
||||
it('should destroy object', function(test) {
|
||||
Post.create(function(err, post) {
|
||||
Post.exists(post.id, function(err, exists) {
|
||||
test.ok(exists, 'Object exists');
|
||||
post.destroy(function () {
|
||||
Post.exists(post.id, function (err, exists) {
|
||||
post.destroy(function() {
|
||||
Post.exists(post.id, function(err, exists) {
|
||||
if (err) console.log(err);
|
||||
test.ok(!exists, 'Hey! ORM told me that object exists, but it looks like it doesn\'t. Something went wrong...');
|
||||
Post.findById(post.id, function (err, obj) {
|
||||
test.ok(!exists, 'Hey! ORM told me that object exists, but it ' +
|
||||
'looks like it doesn\'t. Something went wrong...');
|
||||
Post.findById(post.id, function(err, obj) {
|
||||
test.equal(obj, null, 'Param obj should be null');
|
||||
test.done();
|
||||
});
|
||||
|
@ -323,10 +326,10 @@ function testOrm(dataSource) {
|
|||
});
|
||||
});
|
||||
|
||||
it('should handle virtual attributes', function (test) {
|
||||
it('should handle virtual attributes', function(test) {
|
||||
var salt = 's0m3s3cr3t5a1t';
|
||||
|
||||
User.setter.passwd = function (password) {
|
||||
User.setter.passwd = function(password) {
|
||||
this._passwd = calcHash(password, salt);
|
||||
};
|
||||
|
||||
|
@ -356,15 +359,15 @@ function testOrm(dataSource) {
|
|||
// });
|
||||
// });
|
||||
|
||||
it('should update single attribute', function (test) {
|
||||
Post.create({title: 'title', content: 'content', published: true}, function (err, post) {
|
||||
it('should update single attribute', function(test) {
|
||||
Post.create({title: 'title', content: 'content', published: true}, function(err, post) {
|
||||
post.content = 'New content';
|
||||
post.updateAttribute('title', 'New title', function () {
|
||||
post.updateAttribute('title', 'New title', function() {
|
||||
test.equal(post.title, 'New title');
|
||||
test.ok(!post.propertyChanged('title'));
|
||||
test.equal(post.content, 'New content', 'dirty state saved');
|
||||
test.ok(post.propertyChanged('content'));
|
||||
post.reload(function (err, post) {
|
||||
post.reload(function(err, post) {
|
||||
test.equal(post.title, 'New title');
|
||||
test.ok(!post.propertyChanged('title'), 'title not changed');
|
||||
test.equal(post.content, 'content', 'real value turned back');
|
||||
|
@ -376,22 +379,22 @@ function testOrm(dataSource) {
|
|||
});
|
||||
|
||||
var countOfposts, countOfpostsFiltered;
|
||||
it('should fetch collection', function (test) {
|
||||
Post.all(function (err, posts) {
|
||||
it('should fetch collection', function(test) {
|
||||
Post.all(function(err, posts) {
|
||||
countOfposts = posts.length;
|
||||
test.ok(countOfposts > 0);
|
||||
test.ok(posts[0] instanceof Post);
|
||||
countOfpostsFiltered = posts.filter(function (p) {
|
||||
countOfpostsFiltered = posts.filter(function(p) {
|
||||
return p.title === 'title';
|
||||
}).length;
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should find records filtered with multiple attributes', function (test) {
|
||||
it('should find records filtered with multiple attributes', function(test) {
|
||||
var d = new Date;
|
||||
Post.create({title: 'title', content: 'content', published: true, date: d}, function (err, post) {
|
||||
Post.all({where: {title: 'title', date: d, published: true}}, function (err, res) {
|
||||
Post.create({title: 'title', content: 'content', published: true, date: d}, function(err, post) {
|
||||
Post.all({where: {title: 'title', date: d, published: true}}, function(err, res) {
|
||||
test.equals(res.length, 1, 'Filtering Posts returns one post');
|
||||
test.done();
|
||||
});
|
||||
|
@ -404,7 +407,7 @@ function testOrm(dataSource) {
|
|||
dataSource.name !== 'neo4j' &&
|
||||
dataSource.name !== 'cradle'
|
||||
)
|
||||
it('relations key is working', function (test) {
|
||||
it('relations key is working', function(test) {
|
||||
test.ok(User.relations, 'Relations key should be defined');
|
||||
test.ok(User.relations.posts, 'posts relation should exist on User');
|
||||
test.equal(User.relations.posts.type, 'hasMany', 'Type of hasMany relation is hasMany');
|
||||
|
@ -421,15 +424,15 @@ function testOrm(dataSource) {
|
|||
test.done();
|
||||
});
|
||||
|
||||
it('should handle hasMany relationship', function (test) {
|
||||
User.create(function (err, u) {
|
||||
it('should handle hasMany relationship', function(test) {
|
||||
User.create(function(err, u) {
|
||||
if (err) return console.log(err);
|
||||
test.ok(u.posts, 'Method defined: posts');
|
||||
test.ok(u.posts.build, 'Method defined: posts.build');
|
||||
test.ok(u.posts.create, 'Method defined: posts.create');
|
||||
u.posts.create(function (err, post) {
|
||||
u.posts.create(function(err, post) {
|
||||
if (err) return console.log(err);
|
||||
u.posts(function (err, posts) {
|
||||
u.posts(function(err, posts) {
|
||||
test.equal(posts.pop().id.toString(), post.id.toString());
|
||||
test.done();
|
||||
});
|
||||
|
@ -437,13 +440,12 @@ function testOrm(dataSource) {
|
|||
});
|
||||
});
|
||||
|
||||
it('should navigate variations of belongsTo regardless of column name', function (test) {
|
||||
|
||||
Dog.create({name: 'theDog'}, function (err, obj) {
|
||||
it('should navigate variations of belongsTo regardless of column name', function(test) {
|
||||
Dog.create({name: 'theDog'}, function(err, obj) {
|
||||
test.ok(obj instanceof Dog);
|
||||
Log.create({name: 'theLog', ownerId: obj.id}, function (err, obj) {
|
||||
Log.create({name: 'theLog', ownerId: obj.id}, function(err, obj) {
|
||||
test.ok(obj instanceof Log);
|
||||
obj.owner(function (err, obj) {
|
||||
obj.owner(function(err, obj) {
|
||||
test.ok(!err, 'Should not have an error.'); // Before cba174b this would be 'Error: Permission denied'
|
||||
if (err) {
|
||||
console.log('Found: ' + err);
|
||||
|
@ -462,39 +464,37 @@ function testOrm(dataSource) {
|
|||
});
|
||||
});
|
||||
|
||||
it('hasMany should support additional conditions', function (test) {
|
||||
|
||||
User.create(function (e, u) {
|
||||
u.posts.create({}, function (e, p) {
|
||||
u.posts({where: {id: p.id}}, function (e, posts) {
|
||||
it('hasMany should support additional conditions', function(test) {
|
||||
User.create(function(e, u) {
|
||||
u.posts.create({}, function(e, p) {
|
||||
u.posts({where: {id: p.id}}, function(e, posts) {
|
||||
test.equal(posts.length, 1, 'There should be only 1 post.');
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('hasMany should be cached', function (test) {
|
||||
/*eslint-disable*/
|
||||
it('hasMany should be cached', function(test) {
|
||||
//User.create(function (e, u) {
|
||||
// u.posts.create({}, function (e, p) {
|
||||
// find all posts for a user.
|
||||
// Finding one post with an existing author associated
|
||||
Post.all(function (err, posts) {
|
||||
Post.all(function(err, posts) {
|
||||
// We try to get the first post with a userId != NULL
|
||||
for (var i = 0; i < posts.length; i++) {
|
||||
var post = posts[i];
|
||||
if (post.userId) {
|
||||
// We could get the user with belongs to relationship but it is better if there is no interactions.
|
||||
User.findById(post.userId, function (err, user) {
|
||||
User.create(function (err, voidUser) {
|
||||
Post.create({userId: user.id}, function () {
|
||||
|
||||
User.findById(post.userId, function(err, user) {
|
||||
User.create(function(err, voidUser) {
|
||||
Post.create({ userId: user.id }, function() {
|
||||
// There can't be any concurrency because we are counting requests
|
||||
// We are first testing cases when user has posts
|
||||
user.posts(function (err, data) {
|
||||
user.posts(function(err, data) {
|
||||
var nbInitialRequests = nbSchemaRequests;
|
||||
user.posts(function (err, data2) {
|
||||
user.posts(function(err, data2) {
|
||||
test.equal(data.length, 2, 'There should be 2 posts.');
|
||||
test.equal(data.length, data2.length, 'Posts should be the same, since we are loading on the same object.');
|
||||
requestsAreCounted && test.equal(nbInitialRequests, nbSchemaRequests, 'There should not be any request because value is cached.');
|
||||
|
@ -502,23 +502,23 @@ function testOrm(dataSource) {
|
|||
if (dataSource.name === 'mongodb') { // for the moment mongodb doesn\'t support additional conditions on hasMany relations (see above)
|
||||
test.done();
|
||||
} else {
|
||||
user.posts({where: {id: data[0].id}}, function (err, data) {
|
||||
user.posts({ where: { id: data[0].id }}, function(err, data) {
|
||||
test.equal(data.length, 1, 'There should be only one post.');
|
||||
requestsAreCounted && test.equal(nbInitialRequests + 1, nbSchemaRequests, 'There should be one additional request since we added conditions.');
|
||||
|
||||
user.posts(function (err, data) {
|
||||
user.posts(function(err, data) {
|
||||
test.equal(data.length, 2, 'Previous get shouldn\'t have changed cached value though, since there was additional conditions.');
|
||||
requestsAreCounted && test.equal(nbInitialRequests + 1, nbSchemaRequests, 'There should not be any request because value is cached.');
|
||||
|
||||
// We are now testing cases when user doesn't have any post
|
||||
voidUser.posts(function (err, data) {
|
||||
voidUser.posts(function(err, data) {
|
||||
var nbInitialRequests = nbSchemaRequests;
|
||||
voidUser.posts(function (err, data2) {
|
||||
voidUser.posts(function(err, data2) {
|
||||
test.equal(data.length, 0, 'There shouldn\'t be any posts (1/2).');
|
||||
test.equal(data2.length, 0, 'There shouldn\'t be any posts (2/2).');
|
||||
requestsAreCounted && test.equal(nbInitialRequests, nbSchemaRequests, 'There should not be any request because value is cached.');
|
||||
|
||||
voidUser.posts(true, function (err, data3) {
|
||||
voidUser.posts(true, function(err, data3) {
|
||||
test.equal(data3.length, 0, 'There shouldn\'t be any posts.');
|
||||
requestsAreCounted && test.equal(nbInitialRequests + 1, nbSchemaRequests, 'There should be one additional request since we forced refresh.');
|
||||
|
||||
|
@ -526,14 +526,11 @@ function testOrm(dataSource) {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -541,8 +538,8 @@ function testOrm(dataSource) {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
/*eslint-enable*/
|
||||
|
||||
// it('should handle hasOne relationship', function (test) {
|
||||
// User.create(function (err, u) {
|
||||
|
@ -550,7 +547,7 @@ function testOrm(dataSource) {
|
|||
// });
|
||||
// });
|
||||
|
||||
it('should support scopes', function (test) {
|
||||
it('should support scopes', function(test) {
|
||||
var wait = 2;
|
||||
|
||||
test.ok(Post.scope, 'Scope supported');
|
||||
|
@ -560,14 +557,14 @@ function testOrm(dataSource) {
|
|||
var post = Post.published.build();
|
||||
test.ok(post.published, 'Can build');
|
||||
test.ok(post.isNewRecord());
|
||||
Post.published.create(function (err, psto) {
|
||||
Post.published.create(function(err, psto) {
|
||||
if (err) return console.log(err);
|
||||
test.ok(psto.published);
|
||||
test.ok(!psto.isNewRecord());
|
||||
done();
|
||||
});
|
||||
|
||||
User.create(function (err, u) {
|
||||
User.create(function(err, u) {
|
||||
if (err) return console.log(err);
|
||||
test.ok(typeof u.posts.published == 'function');
|
||||
test.ok(u.posts.published._scope.where.published);
|
||||
|
@ -581,7 +578,7 @@ function testOrm(dataSource) {
|
|||
};
|
||||
});
|
||||
|
||||
it('should return type of property', function (test) {
|
||||
it('should return type of property', function(test) {
|
||||
test.equal(Post.getPropertyType('title'), 'String');
|
||||
test.equal(Post.getPropertyType('content'), 'Text');
|
||||
var p = new Post;
|
||||
|
@ -590,25 +587,25 @@ function testOrm(dataSource) {
|
|||
test.done();
|
||||
});
|
||||
|
||||
it('should handle ORDER clause', function (test) {
|
||||
it('should handle ORDER clause', function(test) {
|
||||
var titles = [
|
||||
{ title: 'Title A', subject: "B" },
|
||||
{ title: 'Title Z', subject: "A" },
|
||||
{ title: 'Title M', subject: "C" },
|
||||
{ title: 'Title A', subject: "A" },
|
||||
{ title: 'Title B', subject: "A" },
|
||||
{ title: 'Title C', subject: "D" }
|
||||
{title: 'Title A', subject: 'B'},
|
||||
{title: 'Title Z', subject: 'A'},
|
||||
{title: 'Title M', subject: 'C'},
|
||||
{title: 'Title A', subject: 'A'},
|
||||
{title: 'Title B', subject: 'A'},
|
||||
{title: 'Title C', subject: 'D'},
|
||||
];
|
||||
var isRedis = Post.dataSource.name === 'redis';
|
||||
var dates = isRedis ? [ 5, 9, 0, 17, 10, 9 ] : [
|
||||
var dates = isRedis ? [5, 9, 0, 17, 10, 9] : [
|
||||
new Date(1000 * 5),
|
||||
new Date(1000 * 9),
|
||||
new Date(1000 * 0),
|
||||
new Date(1000 * 17),
|
||||
new Date(1000 * 10),
|
||||
new Date(1000 * 9)
|
||||
new Date(1000 * 9),
|
||||
];
|
||||
titles.forEach(function (t, i) {
|
||||
titles.forEach(function(t, i) {
|
||||
Post.create({title: t.title, subject: t.subject, date: dates[i]}, done);
|
||||
});
|
||||
|
||||
|
@ -638,10 +635,10 @@ function testOrm(dataSource) {
|
|||
|
||||
function doStringTest() {
|
||||
tests += 1;
|
||||
Post.all({order: 'title'}, function (err, posts) {
|
||||
Post.all({order: 'title'}, function(err, posts) {
|
||||
if (err) console.log(err);
|
||||
test.equal(posts.length, 6);
|
||||
titles.sort(compare).forEach(function (t, i) {
|
||||
titles.sort(compare).forEach(function(t, i) {
|
||||
if (posts[i]) test.equal(posts[i].title, t.title);
|
||||
});
|
||||
finished();
|
||||
|
@ -650,10 +647,10 @@ function testOrm(dataSource) {
|
|||
|
||||
function doNumberTest() {
|
||||
tests += 1;
|
||||
Post.all({order: 'date'}, function (err, posts) {
|
||||
Post.all({order: 'date'}, function(err, posts) {
|
||||
if (err) console.log(err);
|
||||
test.equal(posts.length, 6);
|
||||
dates.sort(numerically).forEach(function (d, i) {
|
||||
dates.sort(numerically).forEach(function(d, i) {
|
||||
if (posts[i])
|
||||
test.equal(posts[i].date.toString(), d.toString(), 'doNumberTest');
|
||||
});
|
||||
|
@ -663,11 +660,11 @@ function testOrm(dataSource) {
|
|||
|
||||
function doFilterAndSortTest() {
|
||||
tests += 1;
|
||||
Post.all({where: {date: new Date(1000 * 9)}, order: 'title', limit: 3}, function (err, posts) {
|
||||
Post.all({where: {date: new Date(1000 * 9)}, order: 'title', limit: 3}, function(err, posts) {
|
||||
if (err) console.log(err);
|
||||
console.log(posts.length);
|
||||
test.equal(posts.length, 2, 'Exactly 2 posts returned by query');
|
||||
[ 'Title C', 'Title Z' ].forEach(function (t, i) {
|
||||
['Title C', 'Title Z'].forEach(function(t, i) {
|
||||
if (posts[i]) {
|
||||
test.equal(posts[i].title, t, 'doFilterAndSortTest');
|
||||
}
|
||||
|
@ -678,10 +675,10 @@ function testOrm(dataSource) {
|
|||
|
||||
function doFilterAndSortReverseTest() {
|
||||
tests += 1;
|
||||
Post.all({where: {date: new Date(1000 * 9)}, order: 'title DESC', limit: 3}, function (err, posts) {
|
||||
Post.all({where: {date: new Date(1000 * 9)}, order: 'title DESC', limit: 3}, function(err, posts) {
|
||||
if (err) console.log(err);
|
||||
test.equal(posts.length, 2, 'Exactly 2 posts returned by query');
|
||||
[ 'Title Z', 'Title C' ].forEach(function (t, i) {
|
||||
['Title Z', 'Title C'].forEach(function(t, i) {
|
||||
if (posts[i]) {
|
||||
test.equal(posts[i].title, t, 'doFilterAndSortReverseTest');
|
||||
}
|
||||
|
@ -692,28 +689,28 @@ function testOrm(dataSource) {
|
|||
|
||||
function doMultipleSortTest() {
|
||||
tests += 1;
|
||||
Post.all({order: "title ASC, subject ASC"}, function (err, posts) {
|
||||
Post.all({order: 'title ASC, subject ASC'}, function(err, posts) {
|
||||
if (err) console.log(err);
|
||||
test.equal(posts.length, 6);
|
||||
test.equal(posts[0].title, "Title A");
|
||||
test.equal(posts[0].subject, "A");
|
||||
test.equal(posts[1].title, "Title A");
|
||||
test.equal(posts[1].subject, "B");
|
||||
test.equal(posts[5].title, "Title Z");
|
||||
test.equal(posts[0].title, 'Title A');
|
||||
test.equal(posts[0].subject, 'A');
|
||||
test.equal(posts[1].title, 'Title A');
|
||||
test.equal(posts[1].subject, 'B');
|
||||
test.equal(posts[5].title, 'Title Z');
|
||||
finished();
|
||||
});
|
||||
}
|
||||
|
||||
function doMultipleReverseSortTest() {
|
||||
tests += 1;
|
||||
Post.all({order: "title ASC, subject DESC"}, function (err, posts) {
|
||||
Post.all({order: 'title ASC, subject DESC'}, function(err, posts) {
|
||||
if (err) console.log(err);
|
||||
test.equal(posts.length, 6);
|
||||
test.equal(posts[0].title, "Title A");
|
||||
test.equal(posts[0].subject, "B");
|
||||
test.equal(posts[1].title, "Title A");
|
||||
test.equal(posts[1].subject, "A");
|
||||
test.equal(posts[5].title, "Title Z");
|
||||
test.equal(posts[0].title, 'Title A');
|
||||
test.equal(posts[0].subject, 'B');
|
||||
test.equal(posts[1].title, 'Title A');
|
||||
test.equal(posts[1].subject, 'A');
|
||||
test.equal(posts[5].title, 'Title Z');
|
||||
finished();
|
||||
});
|
||||
}
|
||||
|
@ -731,7 +728,6 @@ function testOrm(dataSource) {
|
|||
function numerically(a, b) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// if (
|
||||
|
@ -872,7 +868,7 @@ function testOrm(dataSource) {
|
|||
// }
|
||||
// });
|
||||
|
||||
it('should handle order clause with direction', function (test) {
|
||||
it('should handle order clause with direction', function(test) {
|
||||
var wait = 0;
|
||||
var emails = [
|
||||
'john@hcompany.com',
|
||||
|
@ -881,10 +877,10 @@ function testOrm(dataSource) {
|
|||
'tin@hcompany.com',
|
||||
'mike@hcompany.com',
|
||||
'susan@hcompany.com',
|
||||
'test@hcompany.com'
|
||||
'test@hcompany.com',
|
||||
];
|
||||
User.destroyAll(function () {
|
||||
emails.forEach(function (email) {
|
||||
User.destroyAll(function() {
|
||||
emails.forEach(function(email) {
|
||||
wait += 1;
|
||||
User.create({email: email, name: 'Nick'}, done);
|
||||
});
|
||||
|
@ -892,7 +888,7 @@ function testOrm(dataSource) {
|
|||
var tests = 2;
|
||||
|
||||
function done() {
|
||||
process.nextTick(function () {
|
||||
process.nextTick(function() {
|
||||
if (--wait === 0) {
|
||||
doSortTest();
|
||||
doReverseSortTest();
|
||||
|
@ -901,9 +897,9 @@ function testOrm(dataSource) {
|
|||
}
|
||||
|
||||
function doSortTest() {
|
||||
User.all({order: 'email ASC', where: {name: 'Nick'}}, function (err, users) {
|
||||
User.all({order: 'email ASC', where: {name: 'Nick'}}, function(err, users) {
|
||||
var _emails = emails.sort();
|
||||
users.forEach(function (user, i) {
|
||||
users.forEach(function(user, i) {
|
||||
test.equal(_emails[i], user.email, 'ASC sorting');
|
||||
});
|
||||
testDone();
|
||||
|
@ -911,9 +907,9 @@ function testOrm(dataSource) {
|
|||
}
|
||||
|
||||
function doReverseSortTest() {
|
||||
User.all({order: 'email DESC', where: {name: 'Nick'}}, function (err, users) {
|
||||
User.all({order: 'email DESC', where: {name: 'Nick'}}, function(err, users) {
|
||||
var _emails = emails.sort().reverse();
|
||||
users.forEach(function (user, i) {
|
||||
users.forEach(function(user, i) {
|
||||
test.equal(_emails[i], user.email, 'DESC sorting');
|
||||
});
|
||||
testDone();
|
||||
|
@ -925,12 +921,12 @@ function testOrm(dataSource) {
|
|||
}
|
||||
});
|
||||
|
||||
it('should return id in find result even after updateAttributes', function (test) {
|
||||
Post.create(function (err, post) {
|
||||
it('should return id in find result even after updateAttributes', function(test) {
|
||||
Post.create(function(err, post) {
|
||||
var id = post.id;
|
||||
test.ok(post.published === false);
|
||||
post.updateAttributes({title: 'hey', published: true}, function () {
|
||||
Post.find(id, function (err, post) {
|
||||
post.updateAttributes({title: 'hey', published: true}, function() {
|
||||
Post.find(id, function(err, post) {
|
||||
test.ok(!!post.published, 'Update boolean field');
|
||||
test.ok(post.id);
|
||||
test.done();
|
||||
|
@ -939,7 +935,7 @@ function testOrm(dataSource) {
|
|||
});
|
||||
});
|
||||
|
||||
it('should handle belongsTo correctly', function (test) {
|
||||
it('should handle belongsTo correctly', function(test) {
|
||||
var passport = new Passport({ownerId: 16});
|
||||
// sync getter
|
||||
test.equal(passport.owner(), 16);
|
||||
|
@ -949,18 +945,18 @@ function testOrm(dataSource) {
|
|||
test.done();
|
||||
});
|
||||
|
||||
it('should query one record', function (test) {
|
||||
it('should query one record', function(test) {
|
||||
test.expect(4);
|
||||
Post.findOne(function (err, post) {
|
||||
Post.findOne(function(err, post) {
|
||||
test.ok(post && post.id);
|
||||
Post.findOne({ where: { title: 'hey' } }, function (err, post) {
|
||||
Post.findOne({where: {title: 'hey'}}, function(err, post) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return test.done();
|
||||
}
|
||||
test.equal(post && post.constructor.modelName, 'Post');
|
||||
test.equal(post && post.title, 'hey');
|
||||
Post.findOne({ where: { title: 'not exists' } }, function (err, post) {
|
||||
Post.findOne({where: {title: 'not exists'}}, function(err, post) {
|
||||
test.ok(post === null);
|
||||
test.done();
|
||||
});
|
||||
|
@ -1018,13 +1014,13 @@ function testOrm(dataSource) {
|
|||
// });
|
||||
|
||||
if (dataSource.name !== 'mongoose' && dataSource.name !== 'neo4j')
|
||||
it('should update or create record', function (test) {
|
||||
it('should update or create record', function(test) {
|
||||
var newData = {
|
||||
id: 1,
|
||||
title: 'New title (really new)',
|
||||
content: 'Some example content (updated)'
|
||||
content: 'Some example content (updated)',
|
||||
};
|
||||
Post.updateOrCreate(newData, function (err, updatedPost) {
|
||||
Post.updateOrCreate(newData, function(err, updatedPost) {
|
||||
if (err) throw err;
|
||||
test.ok(updatedPost);
|
||||
if (!updatedPost) throw Error('No post!');
|
||||
|
@ -1035,7 +1031,7 @@ function testOrm(dataSource) {
|
|||
test.equal(newData.title, updatedPost.toObject().title);
|
||||
test.equal(newData.content, updatedPost.toObject().content);
|
||||
|
||||
Post.findById(updatedPost.id, function (err, post) {
|
||||
Post.findById(updatedPost.id, function(err, post) {
|
||||
if (err) throw err;
|
||||
if (!post) throw Error('No post!');
|
||||
if (dataSource.name !== 'mongodb') {
|
||||
|
@ -1043,10 +1039,10 @@ function testOrm(dataSource) {
|
|||
}
|
||||
test.equal(newData.title, post.toObject().title);
|
||||
test.equal(newData.content, post.toObject().content);
|
||||
Post.updateOrCreate({id: 100001, title: 'hey'}, function (err, post) {
|
||||
Post.updateOrCreate({id: 100001, title: 'hey'}, function(err, post) {
|
||||
if (dataSource.name !== 'mongodb') test.equal(post.id, 100001);
|
||||
test.equal(post.title, 'hey');
|
||||
Post.findById(post.id, function (err, post) {
|
||||
Post.findById(post.id, function(err, post) {
|
||||
if (!post) throw Error('No post!');
|
||||
test.done();
|
||||
});
|
||||
|
@ -1055,25 +1051,25 @@ function testOrm(dataSource) {
|
|||
});
|
||||
});
|
||||
|
||||
it('should work with custom setters and getters', function (test) {
|
||||
it('should work with custom setters and getters', function(test) {
|
||||
User.dataSource.defineForeignKey('User', 'passwd');
|
||||
User.setter.passwd = function (pass) {
|
||||
User.setter.passwd = function(pass) {
|
||||
this._passwd = pass + 'salt';
|
||||
};
|
||||
var u = new User({passwd: 'qwerty'});
|
||||
test.equal(u.passwd, 'qwertysalt');
|
||||
u.save(function (err, user) {
|
||||
User.findById(user.id, function (err, user) {
|
||||
u.save(function(err, user) {
|
||||
User.findById(user.id, function(err, user) {
|
||||
test.ok(user !== u);
|
||||
test.equal(user.passwd, 'qwertysalt');
|
||||
User.all({where: {passwd: 'qwertysalt'}}, function (err, users) {
|
||||
User.all({where: {passwd: 'qwertysalt'}}, function(err, users) {
|
||||
test.ok(users[0] !== user);
|
||||
test.equal(users[0].passwd, 'qwertysalt');
|
||||
User.create({passwd: 'asalat'}, function (err, usr) {
|
||||
User.create({passwd: 'asalat'}, function(err, usr) {
|
||||
test.equal(usr.passwd, 'asalatsalt');
|
||||
User.upsert({passwd: 'heyman'}, function (err, us) {
|
||||
User.upsert({passwd: 'heyman'}, function(err, us) {
|
||||
test.equal(us.passwd, 'heymansalt');
|
||||
User.findById(us.id, function (err, user) {
|
||||
User.findById(us.id, function(err, user) {
|
||||
test.equal(user.passwd, 'heymansalt');
|
||||
test.done();
|
||||
});
|
||||
|
@ -1084,18 +1080,18 @@ function testOrm(dataSource) {
|
|||
});
|
||||
});
|
||||
|
||||
it('should work with typed and untyped nested collections', function (test) {
|
||||
it('should work with typed and untyped nested collections', function(test) {
|
||||
var post = new Post;
|
||||
var like = post.likes.push({foo: 'bar'});
|
||||
test.equal(like.constructor.name, 'ListItem');
|
||||
var related = post.related.push({hello: 'world'});
|
||||
test.ok(related.someMethod);
|
||||
post.save(function (err, p) {
|
||||
post.save(function(err, p) {
|
||||
test.equal(p.likes.nextid, 2);
|
||||
p.likes.push({second: 2});
|
||||
p.likes.push({third: 3});
|
||||
p.save(function (err) {
|
||||
Post.findById(p.id, function (err, pp) {
|
||||
p.save(function(err) {
|
||||
Post.findById(p.id, function(err, pp) {
|
||||
test.equal(pp.likes.length, 3);
|
||||
test.ok(pp.likes[3].third);
|
||||
test.ok(pp.likes[2].second);
|
||||
|
@ -1107,8 +1103,8 @@ function testOrm(dataSource) {
|
|||
test.equal(pp.likes.length, 1);
|
||||
test.ok(!pp.likes[1]);
|
||||
test.ok(pp.likes[3]);
|
||||
pp.save(function () {
|
||||
Post.findById(p.id, function (err, pp) {
|
||||
pp.save(function() {
|
||||
Post.findById(p.id, function(err, pp) {
|
||||
test.equal(pp.likes.length, 1);
|
||||
test.ok(!pp.likes[1]);
|
||||
test.ok(pp.likes[3]);
|
||||
|
@ -1120,13 +1116,13 @@ function testOrm(dataSource) {
|
|||
});
|
||||
});
|
||||
|
||||
it('should find or create', function (test) {
|
||||
it('should find or create', function(test) {
|
||||
var email = 'some email ' + Math.random();
|
||||
User.findOrCreate({where: {email: email}}, function (err, u, created) {
|
||||
User.findOrCreate({where: {email: email}}, function(err, u, created) {
|
||||
test.ok(u);
|
||||
test.ok(!u.age);
|
||||
test.ok(created);
|
||||
User.findOrCreate({where: {email: email}}, {age: 21}, function (err, u2, created) {
|
||||
User.findOrCreate({where: {email: email}}, {age: 21}, function(err, u2, created) {
|
||||
test.equals(u.id.toString(), u2.id.toString(), 'Same user ids');
|
||||
test.ok(!u2.age);
|
||||
test.ok(!created);
|
||||
|
@ -1134,5 +1130,4 @@ function testOrm(dataSource) {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
// Copyright IBM Corp. 2015,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
// This test written in mocha+should.js
|
||||
var should = require('./init.js');
|
||||
var async = require('async');
|
||||
var db, User, options, filter;
|
||||
|
||||
describe('crud-with-options', function () {
|
||||
|
||||
before(function (done) {
|
||||
describe('crud-with-options', function() {
|
||||
before(function(done) {
|
||||
db = getSchema();
|
||||
User = db.define('User', {
|
||||
seq: {type: Number, index: true},
|
||||
|
@ -14,50 +19,49 @@ describe('crud-with-options', function () {
|
|||
birthday: {type: Date, index: true},
|
||||
role: {type: String, index: true},
|
||||
order: {type: Number, index: true, sort: true},
|
||||
vip: {type: Boolean}
|
||||
vip: {type: Boolean},
|
||||
meta: {type: Object},
|
||||
});
|
||||
options = {};
|
||||
filter = {fields: ['name', 'id']};
|
||||
|
||||
db.automigrate(['User'], done);
|
||||
|
||||
});
|
||||
|
||||
describe('findById', function () {
|
||||
|
||||
before(function (done) {
|
||||
describe('findById', function() {
|
||||
before(function(done) {
|
||||
User.destroyAll(done);
|
||||
});
|
||||
|
||||
it('should allow findById(id, options, cb)', function (done) {
|
||||
User.findById(1, options, function (err, u) {
|
||||
it('should allow findById(id, options, cb)', function(done) {
|
||||
User.findById(1, options, function(err, u) {
|
||||
should.not.exist(u);
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow findById(id, filter, cb)', function (done) {
|
||||
User.findById(1, filter, function (err, u) {
|
||||
it('should allow findById(id, filter, cb)', function(done) {
|
||||
User.findById(1, filter, function(err, u) {
|
||||
should.not.exist(u);
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow findById(id)', function () {
|
||||
it('should allow findById(id)', function() {
|
||||
User.findById(1);
|
||||
});
|
||||
|
||||
it('should allow findById(id, filter)', function () {
|
||||
it('should allow findById(id, filter)', function() {
|
||||
User.findById(1, filter);
|
||||
});
|
||||
|
||||
it('should allow findById(id, options)', function () {
|
||||
it('should allow findById(id, options)', function() {
|
||||
User.findById(1, options);
|
||||
});
|
||||
|
||||
it('should allow findById(id, filter, options)', function () {
|
||||
it('should allow findById(id, filter, options)', function() {
|
||||
User.findById(1, filter, options);
|
||||
});
|
||||
|
||||
|
@ -67,7 +71,7 @@ describe('crud-with-options', function () {
|
|||
User.findById(1, '123', function(err, u) {
|
||||
});
|
||||
}).should.throw('The filter argument must be an object');
|
||||
done();
|
||||
done();
|
||||
});
|
||||
|
||||
it('should throw when invalid options are provided for findById',
|
||||
|
@ -181,19 +185,17 @@ describe('crud-with-options', function () {
|
|||
done(err);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('findByIds', function () {
|
||||
|
||||
describe('findByIds', function() {
|
||||
before(function(done) {
|
||||
var people = [
|
||||
{ id: 1, name: 'a', vip: true },
|
||||
{ id: 2, name: 'b' },
|
||||
{ id: 3, name: 'c' },
|
||||
{ id: 4, name: 'd', vip: true },
|
||||
{ id: 5, name: 'e' },
|
||||
{ id: 6, name: 'f' }
|
||||
{id: 1, name: 'a', vip: true},
|
||||
{id: 2, name: 'b'},
|
||||
{id: 3, name: 'c'},
|
||||
{id: 4, name: 'd', vip: true},
|
||||
{id: 5, name: 'e'},
|
||||
{id: 6, name: 'f'},
|
||||
];
|
||||
// Use automigrate so that serial keys are 1-6
|
||||
db.automigrate(['User'], function(err) {
|
||||
|
@ -203,8 +205,8 @@ describe('crud-with-options', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should allow findByIds(ids, cb)', function (done) {
|
||||
User.findByIds([3, 2, 1], function (err, users) {
|
||||
it('should allow findByIds(ids, cb)', function(done) {
|
||||
User.findByIds([3, 2, 1], function(err, users) {
|
||||
should.exist(users);
|
||||
should.not.exist(err);
|
||||
var names = users.map(function(u) { return u.name; });
|
||||
|
@ -216,7 +218,7 @@ describe('crud-with-options', function () {
|
|||
it('should allow findByIds(ids, filter, options, cb)',
|
||||
function(done) {
|
||||
User.findByIds([4, 3, 2, 1],
|
||||
{ where: { vip: true } }, options, function(err, users) {
|
||||
{where: {vip: true}}, options, function(err, users) {
|
||||
should.exist(users);
|
||||
should.not.exist(err);
|
||||
var names = users.map(function(u) {
|
||||
|
@ -226,11 +228,9 @@ describe('crud-with-options', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('find', function () {
|
||||
|
||||
describe('find', function() {
|
||||
before(seed);
|
||||
|
||||
it('should allow find(cb)', function(done) {
|
||||
|
@ -260,6 +260,15 @@ describe('crud-with-options', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should not throw for nested properties for ANY or Object type', function(done) {
|
||||
User.find({where: {'meta.thisPropertyNotDefined': true}}, function(err, users) {
|
||||
should.not.exists(err);
|
||||
should.exists(users);
|
||||
users.should.have.lengthOf(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow find(filter, options)', function() {
|
||||
User.find({limit: 3}, options);
|
||||
});
|
||||
|
@ -298,15 +307,13 @@ describe('crud-with-options', function () {
|
|||
User.find({limit: 3}, {}, 'invalid cb');
|
||||
}).should.throw('The cb argument must be a function');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('count', function () {
|
||||
|
||||
describe('count', function() {
|
||||
before(seed);
|
||||
|
||||
it('should allow count(cb)', function (done) {
|
||||
User.count(function (err, n) {
|
||||
it('should allow count(cb)', function(done) {
|
||||
User.count(function(err, n) {
|
||||
should.not.exist(err);
|
||||
should.exist(n);
|
||||
n.should.equal(6);
|
||||
|
@ -314,8 +321,8 @@ describe('crud-with-options', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should allow count(where, cb)', function (done) {
|
||||
User.count({role: 'lead'}, function (err, n) {
|
||||
it('should allow count(where, cb)', function(done) {
|
||||
User.count({role: 'lead'}, function(err, n) {
|
||||
should.not.exist(err);
|
||||
should.exist(n);
|
||||
n.should.equal(2);
|
||||
|
@ -323,24 +330,22 @@ describe('crud-with-options', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should allow count(where, options, cb)', function (done) {
|
||||
User.count({role: 'lead'}, options, function (err, n) {
|
||||
it('should allow count(where, options, cb)', function(done) {
|
||||
User.count({role: 'lead'}, options, function(err, n) {
|
||||
should.not.exist(err);
|
||||
should.exist(n);
|
||||
n.should.equal(2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('findOne', function () {
|
||||
|
||||
describe('findOne', function() {
|
||||
before(seed);
|
||||
|
||||
it('should allow findOne(cb)', function (done) {
|
||||
User.find({order: 'id'}, function (err, users) {
|
||||
User.findOne(function (e, u) {
|
||||
it('should allow findOne(cb)', function(done) {
|
||||
User.find({order: 'id'}, function(err, users) {
|
||||
User.findOne(function(e, u) {
|
||||
should.not.exist(e);
|
||||
should.exist(u);
|
||||
u.id.toString().should.equal(users[0].id.toString());
|
||||
|
@ -349,8 +354,8 @@ describe('crud-with-options', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should allow findOne(filter, options, cb)', function (done) {
|
||||
User.findOne({order: 'order'}, options, function (e, u) {
|
||||
it('should allow findOne(filter, options, cb)', function(done) {
|
||||
User.findOne({order: 'order'}, options, function(e, u) {
|
||||
should.not.exist(e);
|
||||
should.exist(u);
|
||||
u.order.should.equal(1);
|
||||
|
@ -359,8 +364,8 @@ describe('crud-with-options', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should allow findOne(filter, cb)', function (done) {
|
||||
User.findOne({order: 'order'}, function (e, u) {
|
||||
it('should allow findOne(filter, cb)', function(done) {
|
||||
User.findOne({order: 'order'}, function(e, u) {
|
||||
should.not.exist(e);
|
||||
should.exist(u);
|
||||
u.order.should.equal(1);
|
||||
|
@ -369,8 +374,8 @@ describe('crud-with-options', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should allow trailing undefined args', function (done) {
|
||||
User.findOne({order: 'order'}, function (e, u) {
|
||||
it('should allow trailing undefined args', function(done) {
|
||||
User.findOne({order: 'order'}, function(e, u) {
|
||||
should.not.exist(e);
|
||||
should.exist(u);
|
||||
u.order.should.equal(1);
|
||||
|
@ -378,16 +383,14 @@ describe('crud-with-options', function () {
|
|||
done();
|
||||
}, undefined);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('exists', function () {
|
||||
|
||||
describe('exists', function() {
|
||||
before(seed);
|
||||
|
||||
it('should allow exists(id, cb)', function (done) {
|
||||
User.findOne(function (e, u) {
|
||||
User.exists(u.id, function (err, exists) {
|
||||
it('should allow exists(id, cb)', function(done) {
|
||||
User.findOne(function(e, u) {
|
||||
User.exists(u.id, function(err, exists) {
|
||||
should.not.exist(err);
|
||||
should.exist(exists);
|
||||
exists.should.be.ok;
|
||||
|
@ -396,22 +399,20 @@ describe('crud-with-options', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should allow exists(id, options, cb)', function (done) {
|
||||
User.destroyAll(function () {
|
||||
User.exists(42, options, function (err, exists) {
|
||||
it('should allow exists(id, options, cb)', function(done) {
|
||||
User.destroyAll(function() {
|
||||
User.exists(42, options, function(err, exists) {
|
||||
should.not.exist(err);
|
||||
exists.should.not.be.ok;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('save', function () {
|
||||
|
||||
it('should allow save(options, cb)', function (done) {
|
||||
var options = { foo: 'bar' };
|
||||
describe('save', function() {
|
||||
it('should allow save(options, cb)', function(done) {
|
||||
var options = {foo: 'bar'};
|
||||
var opts;
|
||||
|
||||
User.observe('after save', function(ctx, next) {
|
||||
|
@ -426,20 +427,18 @@ describe('crud-with-options', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('destroyAll with options', function () {
|
||||
|
||||
describe('destroyAll with options', function() {
|
||||
beforeEach(seed);
|
||||
|
||||
it('should allow destroyAll(where, options, cb)', function (done) {
|
||||
User.destroyAll({name: 'John Lennon'}, options, function (err) {
|
||||
it('should allow destroyAll(where, options, cb)', function(done) {
|
||||
User.destroyAll({name: 'John Lennon'}, options, function(err) {
|
||||
should.not.exist(err);
|
||||
User.find({where: {name: 'John Lennon'}}, function (err, data) {
|
||||
User.find({where: {name: 'John Lennon'}}, function(err, data) {
|
||||
should.not.exist(err);
|
||||
data.length.should.equal(0);
|
||||
User.find({where: {name: 'Paul McCartney'}}, function (err, data) {
|
||||
User.find({where: {name: 'Paul McCartney'}}, function(err, data) {
|
||||
should.not.exist(err);
|
||||
data.length.should.equal(1);
|
||||
done();
|
||||
|
@ -448,13 +447,13 @@ describe('crud-with-options', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should allow destroyAll(where, cb)', function (done) {
|
||||
User.destroyAll({name: 'John Lennon'}, function (err) {
|
||||
it('should allow destroyAll(where, cb)', function(done) {
|
||||
User.destroyAll({name: 'John Lennon'}, function(err) {
|
||||
should.not.exist(err);
|
||||
User.find({where: {name: 'John Lennon'}}, function (err, data) {
|
||||
User.find({where: {name: 'John Lennon'}}, function(err, data) {
|
||||
should.not.exist(err);
|
||||
data.length.should.equal(0);
|
||||
User.find({where: {name: 'Paul McCartney'}}, function (err, data) {
|
||||
User.find({where: {name: 'Paul McCartney'}}, function(err, data) {
|
||||
should.not.exist(err);
|
||||
data.length.should.equal(1);
|
||||
done();
|
||||
|
@ -463,13 +462,13 @@ describe('crud-with-options', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should allow destroyAll(cb)', function (done) {
|
||||
User.destroyAll(function (err) {
|
||||
it('should allow destroyAll(cb)', function(done) {
|
||||
User.destroyAll(function(err) {
|
||||
should.not.exist(err);
|
||||
User.find({where: {name: 'John Lennon'}}, function (err, data) {
|
||||
User.find({where: {name: 'John Lennon'}}, function(err, data) {
|
||||
should.not.exist(err);
|
||||
data.length.should.equal(0);
|
||||
User.find({where: {name: 'Paul McCartney'}}, function (err, data) {
|
||||
User.find({where: {name: 'Paul McCartney'}}, function(err, data) {
|
||||
should.not.exist(err);
|
||||
data.length.should.equal(0);
|
||||
done();
|
||||
|
@ -477,20 +476,18 @@ describe('crud-with-options', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('updateAll ', function () {
|
||||
|
||||
describe('updateAll ', function() {
|
||||
beforeEach(seed);
|
||||
|
||||
it('should allow updateAll(where, data, cb)', function (done) {
|
||||
User.update({name: 'John Lennon'}, {name: 'John Smith'}, function (err) {
|
||||
it('should allow updateAll(where, data, cb)', function(done) {
|
||||
User.update({name: 'John Lennon'}, {name: 'John Smith'}, function(err) {
|
||||
should.not.exist(err);
|
||||
User.find({where: {name: 'John Lennon'}}, function (err, data) {
|
||||
User.find({where: {name: 'John Lennon'}}, function(err, data) {
|
||||
should.not.exist(err);
|
||||
data.length.should.equal(0);
|
||||
User.find({where: {name: 'John Smith'}}, function (err, data) {
|
||||
User.find({where: {name: 'John Smith'}}, function(err, data) {
|
||||
should.not.exist(err);
|
||||
data.length.should.equal(1);
|
||||
done();
|
||||
|
@ -515,12 +512,12 @@ describe('crud-with-options', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should allow updateAll(data, cb)', function (done) {
|
||||
User.update({name: 'John Smith'}, function () {
|
||||
User.find({where: {name: 'John Lennon'}}, function (err, data) {
|
||||
it('should allow updateAll(data, cb)', function(done) {
|
||||
User.update({name: 'John Smith'}, function() {
|
||||
User.find({where: {name: 'John Lennon'}}, function(err, data) {
|
||||
should.not.exist(err);
|
||||
data.length.should.equal(0);
|
||||
User.find({where: {name: 'John Smith'}}, function (err, data) {
|
||||
User.find({where: {name: 'John Smith'}}, function(err, data) {
|
||||
should.not.exist(err);
|
||||
data.length.should.equal(6);
|
||||
done();
|
||||
|
@ -528,9 +525,70 @@ describe('crud-with-options', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('upsertWithWhere', function() {
|
||||
beforeEach(seed);
|
||||
it('rejects upsertWithWhere (options,cb)', function(done) {
|
||||
try {
|
||||
User.upsertWithWhere({}, function(err) {
|
||||
if (err) return done(err);
|
||||
});
|
||||
} catch (ex) {
|
||||
ex.message.should.equal('The data argument must be an object');
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('rejects upsertWithWhere (cb)', function(done) {
|
||||
try {
|
||||
User.upsertWithWhere(function(err) {
|
||||
if (err) return done(err);
|
||||
});
|
||||
} catch (ex) {
|
||||
ex.message.should.equal('The where argument must be an object');
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('allows upsertWithWhere by accepting where,data and cb as arguments', function(done) {
|
||||
User.upsertWithWhere({name: 'John Lennon'}, {name: 'John Smith'}, function(err) {
|
||||
if (err) return done(err);
|
||||
User.find({where: {name: 'John Lennon'}}, function(err, data) {
|
||||
if (err) return done(err);
|
||||
data.length.should.equal(0);
|
||||
User.find({where: {name: 'John Smith'}}, function(err, data) {
|
||||
if (err) return done(err);
|
||||
data.length.should.equal(1);
|
||||
data[0].name.should.equal('John Smith');
|
||||
data[0].email.should.equal('john@b3atl3s.co.uk');
|
||||
data[0].role.should.equal('lead');
|
||||
data[0].order.should.equal(2);
|
||||
data[0].vip.should.equal(true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('allows upsertWithWhere by accepting where, data, options, and cb as arguments', function(done) {
|
||||
options = {};
|
||||
User.upsertWithWhere({name: 'John Lennon'}, {name: 'John Smith'}, options, function(err) {
|
||||
if (err) return done(err);
|
||||
User.find({where: {name: 'John Smith'}}, function(err, data) {
|
||||
if (err) return done(err);
|
||||
data.length.should.equal(1);
|
||||
data[0].name.should.equal('John Smith');
|
||||
data[0].seq.should.equal(0);
|
||||
data[0].email.should.equal('john@b3atl3s.co.uk');
|
||||
data[0].role.should.equal('lead');
|
||||
data[0].order.should.equal(2);
|
||||
data[0].vip.should.equal(true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function seed(done) {
|
||||
|
@ -542,7 +600,7 @@ function seed(done) {
|
|||
role: 'lead',
|
||||
birthday: new Date('1980-12-08'),
|
||||
order: 2,
|
||||
vip: true
|
||||
vip: true,
|
||||
},
|
||||
{
|
||||
seq: 1,
|
||||
|
@ -551,18 +609,18 @@ function seed(done) {
|
|||
role: 'lead',
|
||||
birthday: new Date('1942-06-18'),
|
||||
order: 1,
|
||||
vip: true
|
||||
vip: true,
|
||||
},
|
||||
{seq: 2, name: 'George Harrison', order: 5, vip: false},
|
||||
{seq: 3, name: 'Ringo Starr', order: 6, vip: false},
|
||||
{seq: 4, name: 'Pete Best', order: 4},
|
||||
{seq: 5, name: 'Stuart Sutcliffe', order: 3, vip: true}
|
||||
{seq: 5, name: 'Stuart Sutcliffe', order: 3, vip: true},
|
||||
];
|
||||
|
||||
async.series([
|
||||
User.destroyAll.bind(User),
|
||||
function(cb) {
|
||||
async.each(beatles, User.create.bind(User), cb);
|
||||
}
|
||||
},
|
||||
], done);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright IBM Corp. 2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var should = require('./init.js');
|
||||
var DataSource = require('../lib/datasource.js').DataSource;
|
||||
|
||||
describe('DataSource', function() {
|
||||
it('reports helpful error when connector init throws', function() {
|
||||
var throwingConnector = {
|
||||
name: 'loopback-connector-throwing',
|
||||
initialize: function(ds, cb) {
|
||||
throw new Error('expected test error');
|
||||
},
|
||||
};
|
||||
|
||||
(function() {
|
||||
// this is what LoopBack does
|
||||
return new DataSource({
|
||||
name: 'dsname',
|
||||
connector: throwingConnector,
|
||||
});
|
||||
}).should.throw(/loopback-connector-throwing/);
|
||||
});
|
||||
|
||||
it('reports helpful error when connector init via short name throws', function() {
|
||||
(function() {
|
||||
// this is what LoopBack does
|
||||
return new DataSource({
|
||||
name: 'dsname',
|
||||
connector: 'throwing',
|
||||
});
|
||||
}).should.throw(/expected test error/);
|
||||
});
|
||||
|
||||
it('reports helpful error when connector init via long name throws', function() {
|
||||
(function() {
|
||||
// this is what LoopBack does
|
||||
return new DataSource({
|
||||
name: 'dsname',
|
||||
connector: 'loopback-connector-throwing',
|
||||
});
|
||||
}).should.throw(/expected test error/);
|
||||
});
|
||||
});
|
|
@ -1,13 +1,18 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
// This test written in mocha+should.js
|
||||
var should = require('./init.js');
|
||||
|
||||
var db, Model;
|
||||
|
||||
describe('datatypes', function () {
|
||||
|
||||
before(function (done) {
|
||||
describe('datatypes', function() {
|
||||
before(function(done) {
|
||||
db = getSchema();
|
||||
Nested = db.define('Nested', {});
|
||||
var Nested = db.define('Nested', {});
|
||||
|
||||
Model = db.define('Model', {
|
||||
str: String,
|
||||
|
@ -16,65 +21,71 @@ describe('datatypes', function () {
|
|||
bool: Boolean,
|
||||
list: {type: [String]},
|
||||
arr: Array,
|
||||
nested: Nested
|
||||
nested: Nested,
|
||||
});
|
||||
db.automigrate(['Model'], done);
|
||||
});
|
||||
|
||||
it('should return 400 when property of type array is set to string value',
|
||||
function (done) {
|
||||
function(done) {
|
||||
var myModel = db.define('myModel', {
|
||||
list: { type: ['object'] }
|
||||
list: {type: ['object']},
|
||||
});
|
||||
|
||||
(function(){
|
||||
myModel.create({ list: 'This string will crash the server' });
|
||||
}).should.throw({ statusCode: 400 });
|
||||
|
||||
done();
|
||||
});
|
||||
myModel.create({list: 'This string will crash the server'}, function(err) {
|
||||
(err.statusCode).should.equal(400);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return 400 when property of type array is set to object value',
|
||||
function (done) {
|
||||
function(done) {
|
||||
var myModel = db.define('myModel', {
|
||||
list: { type: ['object'] }
|
||||
list: {type: ['object']},
|
||||
});
|
||||
|
||||
(function(){
|
||||
myModel.create({ list: { key: 'This string will crash the server' } });
|
||||
}).should.throw({ statusCode: 400 });
|
||||
myModel.create({list: {key: 'This string will crash the server'}}, function(err) {
|
||||
(err.statusCode).should.equal(400);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
it('throws an error when property of type Date is set to an invalid value',
|
||||
function() {
|
||||
var myModel = db.define('myModel', {
|
||||
date: {type: Date},
|
||||
});
|
||||
|
||||
myModel.create({date: 'invalid'}, function(err) {
|
||||
(err.message).should.equal('Invalid date: invalid');
|
||||
});
|
||||
});
|
||||
|
||||
it('should keep types when get read data from db', function(done) {
|
||||
var d = new Date, id;
|
||||
|
||||
it('should keep types when get read data from db', function (done) {
|
||||
var d = new Date;
|
||||
var id;
|
||||
|
||||
Model.create({
|
||||
str: 'hello', date: d, num: '3', bool: 1, list: ['test'], arr: [1, 'str']
|
||||
}, function (err, m) {
|
||||
str: 'hello', date: d, num: '3', bool: 1, list: ['test'], arr: [1, 'str'],
|
||||
}, function(err, m) {
|
||||
should.not.exists(err);
|
||||
should.exist(m && m.id);
|
||||
should(m.str).be.type('string');
|
||||
should(m.num).be.type('number');
|
||||
should(m.bool).be.type('boolean');
|
||||
m.str.should.be.type('string');
|
||||
m.num.should.be.type('number');
|
||||
m.bool.should.be.type('boolean');
|
||||
m.list[0].should.be.equal('test');
|
||||
m.arr[0].should.be.equal(1);
|
||||
m.arr[1].should.be.equal('str');
|
||||
m.date.should.be.an.instanceOf(Date);
|
||||
m.date.toString().should.equal(d.toString())
|
||||
id = m.id;
|
||||
testFind(testAll);
|
||||
});
|
||||
|
||||
function testFind(next) {
|
||||
Model.findById(id, function (err, m) {
|
||||
Model.findById(id, function(err, m) {
|
||||
should.not.exist(err);
|
||||
should.exist(m);
|
||||
should(m.str).be.type('string');
|
||||
should(m.num).be.type('number');
|
||||
should(m.bool).be.type('boolean');
|
||||
m.str.should.be.type('string');
|
||||
m.num.should.be.type('number');
|
||||
m.bool.should.be.type('boolean');
|
||||
m.list[0].should.be.equal('test');
|
||||
m.arr[0].should.be.equal(1);
|
||||
m.arr[1].should.be.equal('str');
|
||||
|
@ -85,18 +96,20 @@ describe('datatypes', function () {
|
|||
}
|
||||
|
||||
function testAll() {
|
||||
Model.findOne(function (err, m) {
|
||||
Model.findOne(function(err, m) {
|
||||
should.not.exist(err);
|
||||
should.exist(m);
|
||||
should(m.str).be.type('string');
|
||||
should(m.num).be.type('number');
|
||||
should(m.bool).be.type('boolean');
|
||||
m.str.should.be.type('string');
|
||||
m.num.should.be.type('number');
|
||||
m.bool.should.be.type('boolean');
|
||||
m.date.should.be.an.instanceOf(Date);
|
||||
m.date.toString().should.equal(d.toString(), 'Time must match');
|
||||
done();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('should respect data types when updating attributes', function (done) {
|
||||
it('should respect data types when updating attributes', function(done) {
|
||||
var d = new Date, id;
|
||||
|
||||
Model.create({
|
||||
|
@ -105,11 +118,11 @@ describe('datatypes', function () {
|
|||
should.exist(m && m.id);
|
||||
|
||||
// sanity check initial types
|
||||
should(m.str).be.type('string');
|
||||
should(m.num).be.type('number');
|
||||
should(m.bool).be.type('boolean');
|
||||
m.str.should.be.type('string');
|
||||
m.num.should.be.type('number');
|
||||
m.bool.should.be.type('boolean');
|
||||
id = m.id;
|
||||
testDataInDB(function () {
|
||||
testDataInDB(function() {
|
||||
testUpdate(function() {
|
||||
testDataInDB(done);
|
||||
});
|
||||
|
@ -122,20 +135,20 @@ describe('datatypes', function () {
|
|||
|
||||
// update using updateAttributes
|
||||
m.updateAttributes({
|
||||
id: m.id, num: '10'
|
||||
}, function (err, m) {
|
||||
id: m.id, num: '10',
|
||||
}, function(err, m) {
|
||||
should.not.exist(err);
|
||||
m.num.should.be.type('number');
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testDataInDB(done) {
|
||||
|
||||
// verify that the value stored in the db is still an object
|
||||
function cb(err, data) {
|
||||
should.exist(data);
|
||||
should(data.num).be.type('number');
|
||||
data.num.should.be.type('number');
|
||||
done();
|
||||
}
|
||||
|
||||
|
@ -148,18 +161,18 @@ describe('datatypes', function () {
|
|||
});
|
||||
|
||||
it('should not coerce nested objects into ModelConstructor types', function() {
|
||||
var coerced = Model._coerce({ nested: { foo: 'bar' } });
|
||||
coerced.nested.constructor.name.should.equal('Object');
|
||||
var coerced = Model._coerce({nested: {foo: 'bar'}});
|
||||
coerced.nested.constructor.name.should.equal('Object');
|
||||
});
|
||||
|
||||
it('rejects array value converted to NaN for a required property',
|
||||
function(done) {
|
||||
db = getSchema();
|
||||
Model = db.define('RequiredNumber', {
|
||||
num: { type: Number, required: true }
|
||||
num: {type: Number, required: true},
|
||||
});
|
||||
db.automigrate(['Model'], function () {
|
||||
Model.create({ num: [1,2,3] }, function(err, inst) {
|
||||
db.automigrate(['Model'], function() {
|
||||
Model.create({num: [1, 2, 3]}, function(err, inst) {
|
||||
should.exist(err);
|
||||
err.should.have.property('name').equal('ValidationError');
|
||||
done();
|
||||
|
@ -173,11 +186,11 @@ describe('datatypes', function () {
|
|||
TestModel = db.define(
|
||||
'TestModel',
|
||||
{
|
||||
desc: { type: String, required: false },
|
||||
stars: { type: Number, required: false }
|
||||
desc: {type: String, required: false},
|
||||
stars: {type: Number, required: false},
|
||||
},
|
||||
{
|
||||
persistUndefinedAsNull: true
|
||||
persistUndefinedAsNull: true,
|
||||
});
|
||||
|
||||
isStrict = TestModel.definition.settings.strict;
|
||||
|
@ -186,39 +199,35 @@ describe('datatypes', function () {
|
|||
});
|
||||
|
||||
it('should set missing optional properties to null', function(done) {
|
||||
TestModel.create({ name: 'a-test-name' }, function(err, created) {
|
||||
var EXPECTED = {desc: null, stars: null};
|
||||
TestModel.create({name: 'a-test-name'}, function(err, created) {
|
||||
if (err) return done(err);
|
||||
created.should.have.property('desc', null);
|
||||
created.should.have.property('stars', null);
|
||||
created.should.have.properties(EXPECTED);
|
||||
|
||||
TestModel.findById(created.id, function(err, found) {
|
||||
if (err) return done(err);
|
||||
created.should.have.property('desc', null);
|
||||
created.should.have.property('stars', null);
|
||||
found.should.have.properties(EXPECTED);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert property value undefined to null', function(done) {
|
||||
it('should convert property value undefined to null', function(done) {
|
||||
var EXPECTED = {desc: null, extra: null};
|
||||
if (isStrict) {
|
||||
// SQL-based connectors don't support dynamic properties
|
||||
delete EXPECTED.extra;
|
||||
}
|
||||
|
||||
var data ={ desc: undefined, extra: undefined };
|
||||
var data = {desc: undefined, extra: undefined};
|
||||
TestModel.create(data, function(err, created) {
|
||||
if (err) return done(err);
|
||||
|
||||
created.should.have.property('desc', null);
|
||||
created.should.have.property('stars', null);
|
||||
created.should.have.properties(EXPECTED);
|
||||
|
||||
TestModel.findById(created.id, function(err, found) {
|
||||
if (err) return done(err);
|
||||
|
||||
created.should.have.property('desc', null);
|
||||
created.should.have.property('stars', null);
|
||||
|
||||
found.should.have.properties(EXPECTED);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@ -238,8 +247,8 @@ describe('datatypes', function () {
|
|||
inst.toObject().should.have.property('stars', null);
|
||||
});
|
||||
|
||||
// TODO: There is a bug for this; please refer to https://github.com/strongloop/loopback-connector-redis/issues/9
|
||||
it.skip('should convert undefined to null on save', function(done) {
|
||||
it('should convert undefined to null on save', function(done) {
|
||||
var EXPECTED = {desc: null, stars: null, extra: null, dx: null};
|
||||
if (isStrict) {
|
||||
// SQL-based connectors don't support dynamic properties
|
||||
delete EXPECTED.extra;
|
||||
|
@ -248,7 +257,6 @@ describe('datatypes', function () {
|
|||
|
||||
TestModel.create({}, function(err, created) {
|
||||
if (err) return done(err);
|
||||
|
||||
created.desc = undefined; // Note: this is may be a no-op
|
||||
created.unsetAttribute('stars');
|
||||
created.extra = undefined;
|
||||
|
@ -257,8 +265,8 @@ describe('datatypes', function () {
|
|||
created.save(function(err, saved) {
|
||||
if (err) return done(err);
|
||||
|
||||
saved.should.have.property('extra', null);
|
||||
saved.should.have.property('dx', null);
|
||||
created.should.have.properties(EXPECTED);
|
||||
saved.should.have.properties(EXPECTED);
|
||||
|
||||
function cb(err, found) {
|
||||
if (err) return done(err);
|
||||
|
@ -292,11 +300,9 @@ describe('datatypes', function () {
|
|||
inst.extra = undefined;
|
||||
inst.__data.dx = undefined;
|
||||
|
||||
var result = inst.toObject(false);
|
||||
result.should.have.property('desc', null);
|
||||
result.should.have.property('stars', null);
|
||||
result.should.have.property('extra', null);
|
||||
result.should.have.property('dx', null);
|
||||
inst.toObject(false).should.have.properties({
|
||||
desc: null, stars: null, extra: null, dx: null,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
// This test written in mocha+should.js
|
||||
var should = require('./init.js');
|
||||
var async = require('async');
|
||||
|
@ -41,80 +47,82 @@ var setupProducts = function(ids, done) {
|
|||
ids.widgetB = inst.id;
|
||||
next();
|
||||
});
|
||||
}
|
||||
},
|
||||
], done);
|
||||
};
|
||||
|
||||
describe('default scope', function () {
|
||||
|
||||
before(function (done) {
|
||||
describe('default scope', function() {
|
||||
before(function(done) {
|
||||
db = getSchema();
|
||||
|
||||
|
||||
Category = db.define('Category', {
|
||||
name: String
|
||||
name: String,
|
||||
});
|
||||
|
||||
Product = db.define('Product', {
|
||||
name: String,
|
||||
kind: String,
|
||||
description: String,
|
||||
active: { type: Boolean, default: true }
|
||||
active: {type: Boolean, default: true},
|
||||
}, {
|
||||
scope: { order: 'name' },
|
||||
scopes: { active: { where: { active: true } } }
|
||||
scope: {order: 'name'},
|
||||
scopes: {active: {where: {active: true}}},
|
||||
});
|
||||
|
||||
|
||||
Product.lookupModel = function(data) {
|
||||
var m = this.dataSource.models[data.kind];
|
||||
if (m.base === this) return m;
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
Tool = db.define('Tool', Product.definition.properties, {
|
||||
base: 'Product',
|
||||
scope: { where: { kind: 'Tool' }, order: 'name' },
|
||||
scopes: { active: { where: { active: true } } },
|
||||
mongodb: { collection: 'Product' },
|
||||
memory: { collection: 'Product' }
|
||||
});
|
||||
|
||||
Widget = db.define('Widget', Product.definition.properties, {
|
||||
base: 'Product',
|
||||
properties: { kind: 'Widget' },
|
||||
scope: { where: { kind: 'Widget' }, order: 'name' },
|
||||
scopes: { active: { where: { active: true } } },
|
||||
mongodb: { collection: 'Product' },
|
||||
memory: { collection: 'Product' }
|
||||
base: 'Product',
|
||||
scope: {where: {kind: 'Tool'}, order: 'name'},
|
||||
scopes: {active: {where: {active: true}}},
|
||||
arangodb: {collection: 'Product'},
|
||||
mongodb: {collection: 'Product'},
|
||||
memory: {collection: 'Product'},
|
||||
});
|
||||
|
||||
Person = db.define('Person', { name: String }, {
|
||||
scope: { include: 'things' }
|
||||
Widget = db.define('Widget', Product.definition.properties, {
|
||||
base: 'Product',
|
||||
properties: {kind: 'Widget'},
|
||||
scope: {where: {kind: 'Widget'}, order: 'name'},
|
||||
scopes: {active: {where: {active: true}}},
|
||||
arangodb: {collection: 'Product'},
|
||||
mongodb: {collection: 'Product'},
|
||||
memory: {collection: 'Product'},
|
||||
});
|
||||
|
||||
|
||||
Person = db.define('Person', {name: String}, {
|
||||
scope: {include: 'things'},
|
||||
});
|
||||
|
||||
// inst is only valid for instance methods
|
||||
// like save, updateAttributes
|
||||
|
||||
|
||||
var scopeFn = function(target, inst) {
|
||||
return { where: { kind: this.modelName } };
|
||||
return {where: {kind: this.modelName}};
|
||||
};
|
||||
|
||||
|
||||
var propertiesFn = function(target, inst) {
|
||||
return { kind: this.modelName };
|
||||
return {kind: this.modelName};
|
||||
};
|
||||
|
||||
|
||||
Thing = db.define('Thing', Product.definition.properties, {
|
||||
base: 'Product',
|
||||
attributes: propertiesFn,
|
||||
scope: scopeFn,
|
||||
mongodb: { collection: 'Product' },
|
||||
memory: { collection: 'Product' }
|
||||
base: 'Product',
|
||||
attributes: propertiesFn,
|
||||
scope: scopeFn,
|
||||
arangodb: {collection: 'Product'},
|
||||
mongodb: {collection: 'Product'},
|
||||
memory: {collection: 'Product'},
|
||||
});
|
||||
|
||||
|
||||
Category.hasMany(Product);
|
||||
Category.hasMany(Tool, {scope: {order: 'name DESC'}});
|
||||
Category.hasMany(Widget);
|
||||
Category.hasMany(Thing);
|
||||
|
||||
|
||||
Product.belongsTo(Category);
|
||||
Tool.belongsTo(Category);
|
||||
Widget.belongsTo(Category);
|
||||
|
@ -122,29 +130,28 @@ describe('default scope', function () {
|
|||
|
||||
Person.hasMany(Thing);
|
||||
Thing.belongsTo(Person);
|
||||
|
||||
|
||||
db.automigrate(done);
|
||||
});
|
||||
|
||||
|
||||
describe('manipulation', function() {
|
||||
|
||||
var ids = {};
|
||||
|
||||
|
||||
before(function(done) {
|
||||
db.automigrate(done);
|
||||
});
|
||||
|
||||
|
||||
it('should return a scoped instance', function() {
|
||||
var p = new Tool({name: 'Product A', kind:'ignored'});
|
||||
var p = new Tool({name: 'Product A', kind: 'ignored'});
|
||||
p.name.should.equal('Product A');
|
||||
p.kind.should.equal('Tool');
|
||||
p.setAttributes({ kind: 'ignored' });
|
||||
p.setAttributes({kind: 'ignored'});
|
||||
p.kind.should.equal('Tool');
|
||||
|
||||
|
||||
p.setAttribute('kind', 'other'); // currently not enforced
|
||||
p.kind.should.equal('other');
|
||||
});
|
||||
|
||||
|
||||
it('should create a scoped instance - tool', function(done) {
|
||||
Tool.create({name: 'Product A', kind: 'ignored'}, function(err, p) {
|
||||
should.not.exist(err);
|
||||
|
@ -154,7 +161,7 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should create a scoped instance - widget', function(done) {
|
||||
Widget.create({name: 'Product B', kind: 'ignored'}, function(err, p) {
|
||||
should.not.exist(err);
|
||||
|
@ -164,7 +171,7 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should update a scoped instance - updateAttributes', function(done) {
|
||||
Tool.findById(ids.productA, function(err, p) {
|
||||
p.updateAttributes({description: 'A thing...', kind: 'ingored'}, function(err, inst) {
|
||||
|
@ -176,7 +183,7 @@ describe('default scope', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should update a scoped instance - save', function(done) {
|
||||
Tool.findById(ids.productA, function(err, p) {
|
||||
p.description = 'Something...';
|
||||
|
@ -193,28 +200,26 @@ describe('default scope', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should update a scoped instance - updateOrCreate', function(done) {
|
||||
var data = {id: ids.productA, description: 'Anything...', kind: 'ingored'};
|
||||
Tool.updateOrCreate(data, function(err, p) {
|
||||
should.not.exist(err);
|
||||
p.name.should.equal('Product A');
|
||||
p.kind.should.equal('Tool');
|
||||
p.description.should.equal('Anything...');
|
||||
done();
|
||||
should.not.exist(err);
|
||||
p.name.should.equal('Product A');
|
||||
p.kind.should.equal('Tool');
|
||||
p.description.should.equal('Anything...');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('findById', function() {
|
||||
|
||||
var ids = {};
|
||||
|
||||
before(function (done) {
|
||||
|
||||
before(function(done) {
|
||||
db.automigrate(setupProducts.bind(null, ids, done));
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope', function(done) {
|
||||
Product.findById(ids.toolA, function(err, inst) {
|
||||
should.not.exist(err);
|
||||
|
@ -223,7 +228,7 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - tool', function(done) {
|
||||
Tool.findById(ids.toolA, function(err, inst) {
|
||||
should.not.exist(err);
|
||||
|
@ -231,7 +236,7 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope (no match)', function(done) {
|
||||
Widget.findById(ids.toolA, function(err, inst) {
|
||||
should.not.exist(err);
|
||||
|
@ -239,17 +244,15 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('find', function() {
|
||||
|
||||
var ids = {};
|
||||
|
||||
before(function (done) {
|
||||
|
||||
before(function(done) {
|
||||
db.automigrate(setupProducts.bind(null, ids, done));
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - order', function(done) {
|
||||
Product.find(function(err, products) {
|
||||
should.not.exist(err);
|
||||
|
@ -259,19 +262,19 @@ describe('default scope', function () {
|
|||
products[2].name.should.equal('Widget A');
|
||||
products[3].name.should.equal('Widget B');
|
||||
products[4].name.should.equal('Widget Z');
|
||||
|
||||
|
||||
products[0].should.be.instanceof(Product);
|
||||
products[0].should.be.instanceof(Tool);
|
||||
|
||||
|
||||
products[2].should.be.instanceof(Product);
|
||||
products[2].should.be.instanceof(Widget);
|
||||
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - order override', function(done) {
|
||||
Product.find({ order: 'name DESC' }, function(err, products) {
|
||||
Product.find({order: 'name DESC'}, function(err, products) {
|
||||
should.not.exist(err);
|
||||
products.should.have.length(5);
|
||||
products[0].name.should.equal('Widget Z');
|
||||
|
@ -282,7 +285,7 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - tool', function(done) {
|
||||
Tool.find(function(err, products) {
|
||||
should.not.exist(err);
|
||||
|
@ -292,9 +295,9 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - where (widget)', function(done) {
|
||||
Widget.find({ where: { active: true } }, function(err, products) {
|
||||
Widget.find({where: {active: true}}, function(err, products) {
|
||||
should.not.exist(err);
|
||||
products.should.have.length(2);
|
||||
products[0].name.should.equal('Widget A');
|
||||
|
@ -302,9 +305,9 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - order (widget)', function(done) {
|
||||
Widget.find({ order: 'name DESC' }, function(err, products) {
|
||||
Widget.find({order: 'name DESC'}, function(err, products) {
|
||||
should.not.exist(err);
|
||||
products.should.have.length(3);
|
||||
products[0].name.should.equal('Widget Z');
|
||||
|
@ -313,17 +316,15 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('exists', function() {
|
||||
|
||||
var ids = {};
|
||||
|
||||
before(function (done) {
|
||||
|
||||
before(function(done) {
|
||||
db.automigrate(setupProducts.bind(null, ids, done));
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope', function(done) {
|
||||
Product.exists(ids.widgetA, function(err, exists) {
|
||||
should.not.exist(err);
|
||||
|
@ -331,7 +332,7 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - tool', function(done) {
|
||||
Tool.exists(ids.toolZ, function(err, exists) {
|
||||
should.not.exist(err);
|
||||
|
@ -339,7 +340,7 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - widget', function(done) {
|
||||
Widget.exists(ids.widgetA, function(err, exists) {
|
||||
should.not.exist(err);
|
||||
|
@ -347,7 +348,7 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - tool (no match)', function(done) {
|
||||
Tool.exists(ids.widgetA, function(err, exists) {
|
||||
should.not.exist(err);
|
||||
|
@ -355,7 +356,7 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - widget (no match)', function(done) {
|
||||
Widget.exists(ids.toolZ, function(err, exists) {
|
||||
should.not.exist(err);
|
||||
|
@ -363,17 +364,15 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('count', function() {
|
||||
|
||||
var ids = {};
|
||||
|
||||
before(function (done) {
|
||||
|
||||
before(function(done) {
|
||||
db.automigrate(setupProducts.bind(null, ids, done));
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - order', function(done) {
|
||||
Product.count(function(err, count) {
|
||||
should.not.exist(err);
|
||||
|
@ -381,7 +380,7 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - tool', function(done) {
|
||||
Tool.count(function(err, count) {
|
||||
should.not.exist(err);
|
||||
|
@ -389,7 +388,7 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - widget', function(done) {
|
||||
Widget.count(function(err, count) {
|
||||
should.not.exist(err);
|
||||
|
@ -397,7 +396,7 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - where', function(done) {
|
||||
Widget.count({name: 'Widget Z'}, function(err, count) {
|
||||
should.not.exist(err);
|
||||
|
@ -405,7 +404,7 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - no match', function(done) {
|
||||
Tool.count({name: 'Widget Z'}, function(err, count) {
|
||||
should.not.exist(err);
|
||||
|
@ -413,13 +412,11 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('removeById', function() {
|
||||
|
||||
var ids = {};
|
||||
|
||||
|
||||
function isDeleted(id, done) {
|
||||
Product.exists(id, function(err, exists) {
|
||||
should.not.exist(err);
|
||||
|
@ -427,25 +424,25 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
};
|
||||
|
||||
before(function (done) {
|
||||
|
||||
before(function(done) {
|
||||
db.automigrate(setupProducts.bind(null, ids, done));
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope', function(done) {
|
||||
Product.removeById(ids.widgetZ, function(err) {
|
||||
should.not.exist(err);
|
||||
isDeleted(ids.widgetZ, done);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - tool', function(done) {
|
||||
Tool.removeById(ids.toolA, function(err) {
|
||||
should.not.exist(err);
|
||||
isDeleted(ids.toolA, done);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - no match', function(done) {
|
||||
Tool.removeById(ids.widgetA, function(err) {
|
||||
should.not.exist(err);
|
||||
|
@ -456,14 +453,14 @@ describe('default scope', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - widget', function(done) {
|
||||
Widget.removeById(ids.widgetA, function(err) {
|
||||
should.not.exist(err);
|
||||
isDeleted(ids.widgetA, done);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - verify', function(done) {
|
||||
Product.find(function(err, products) {
|
||||
should.not.exist(err);
|
||||
|
@ -473,21 +470,19 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('update', function() {
|
||||
|
||||
var ids = {};
|
||||
|
||||
before(function (done) {
|
||||
|
||||
before(function(done) {
|
||||
db.automigrate(setupProducts.bind(null, ids, done));
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope', function(done) {
|
||||
Widget.update({active: false},{active: true, kind: 'ignored'}, function(err) {
|
||||
Widget.update({active: false}, {active: true, kind: 'ignored'}, function(err) {
|
||||
should.not.exist(err);
|
||||
Widget.find({where: { active: true }}, function(err, products) {
|
||||
Widget.find({where: {active: true}}, function(err, products) {
|
||||
should.not.exist(err);
|
||||
products.should.have.length(3);
|
||||
products[0].name.should.equal('Widget A');
|
||||
|
@ -497,9 +492,9 @@ describe('default scope', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - no match', function(done) {
|
||||
Tool.update({name: 'Widget A'},{name: 'Ignored'}, function(err) {
|
||||
Tool.update({name: 'Widget A'}, {name: 'Ignored'}, function(err) {
|
||||
should.not.exist(err);
|
||||
Product.findById(ids.widgetA, function(err, product) {
|
||||
should.not.exist(err);
|
||||
|
@ -508,7 +503,7 @@ describe('default scope', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should have updated within scope', function(done) {
|
||||
Product.find({where: {active: true}}, function(err, products) {
|
||||
should.not.exist(err);
|
||||
|
@ -520,17 +515,15 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('remove', function() {
|
||||
|
||||
var ids = {};
|
||||
|
||||
before(function (done) {
|
||||
|
||||
before(function(done) {
|
||||
db.automigrate(setupProducts.bind(null, ids, done));
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - custom where', function(done) {
|
||||
Widget.remove({name: 'Widget A'}, function(err) {
|
||||
should.not.exist(err);
|
||||
|
@ -544,7 +537,7 @@ describe('default scope', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - custom where (no match)', function(done) {
|
||||
Tool.remove({name: 'Widget Z'}, function(err) {
|
||||
should.not.exist(err);
|
||||
|
@ -558,7 +551,7 @@ describe('default scope', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - deleteAll', function(done) {
|
||||
Tool.deleteAll(function(err) {
|
||||
should.not.exist(err);
|
||||
|
@ -570,7 +563,7 @@ describe('default scope', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should create a scoped instance - tool', function(done) {
|
||||
Tool.create({name: 'Tool B'}, function(err, p) {
|
||||
should.not.exist(err);
|
||||
|
@ -583,7 +576,7 @@ describe('default scope', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - destroyAll', function(done) {
|
||||
Widget.destroyAll(function(err) {
|
||||
should.not.exist(err);
|
||||
|
@ -594,17 +587,15 @@ describe('default scope', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('scopes', function() {
|
||||
|
||||
var ids = {};
|
||||
|
||||
before(function (done) {
|
||||
|
||||
before(function(done) {
|
||||
db.automigrate(setupProducts.bind(null, ids, done));
|
||||
});
|
||||
|
||||
|
||||
it('should merge with default scope', function(done) {
|
||||
Product.active(function(err, products) {
|
||||
should.not.exist(err);
|
||||
|
@ -615,7 +606,7 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should merge with default scope - tool', function(done) {
|
||||
Tool.active(function(err, products) {
|
||||
should.not.exist(err);
|
||||
|
@ -624,7 +615,7 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should merge with default scope - widget', function(done) {
|
||||
Widget.active(function(err, products) {
|
||||
should.not.exist(err);
|
||||
|
@ -634,31 +625,29 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('scope function', function() {
|
||||
|
||||
before(function(done) {
|
||||
db.automigrate(done);
|
||||
});
|
||||
|
||||
|
||||
it('should create a scoped instance - widget', function(done) {
|
||||
Widget.create({name: 'Product', kind:'ignored'}, function(err, p) {
|
||||
Widget.create({name: 'Product', kind: 'ignored'}, function(err, p) {
|
||||
p.name.should.equal('Product');
|
||||
p.kind.should.equal('Widget');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should create a scoped instance - thing', function(done) {
|
||||
Thing.create({name: 'Product', kind:'ignored'}, function(err, p) {
|
||||
Thing.create({name: 'Product', kind: 'ignored'}, function(err, p) {
|
||||
p.name.should.equal('Product');
|
||||
p.kind.should.equal('Thing');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should find a scoped instance - widget', function(done) {
|
||||
Widget.findOne({where: {name: 'Product'}}, function(err, p) {
|
||||
p.name.should.equal('Product');
|
||||
|
@ -666,7 +655,7 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should find a scoped instance - thing', function(done) {
|
||||
Thing.findOne({where: {name: 'Product'}}, function(err, p) {
|
||||
p.name.should.equal('Product');
|
||||
|
@ -674,30 +663,28 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should find a scoped instance - thing', function(done) {
|
||||
Product.find({where: {name: 'Product'}}, function(err, products) {
|
||||
products.should.have.length(2);
|
||||
products[0].name.should.equal('Product');
|
||||
products[1].name.should.equal('Product');
|
||||
var kinds = products.map(function(p) { return p.kind; })
|
||||
var kinds = products.map(function(p) { return p.kind; });
|
||||
kinds.sort();
|
||||
kinds.should.eql(['Thing', 'Widget']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('relations', function() {
|
||||
|
||||
var ids = {};
|
||||
|
||||
before(function (done) {
|
||||
|
||||
before(function(done) {
|
||||
db.automigrate(done);
|
||||
});
|
||||
|
||||
before(function (done) {
|
||||
|
||||
before(function(done) {
|
||||
Category.create({name: 'Category A'}, function(err, cat) {
|
||||
ids.categoryA = cat.id;
|
||||
async.series([
|
||||
|
@ -712,11 +699,11 @@ describe('default scope', function () {
|
|||
},
|
||||
function(next) {
|
||||
cat.things.create({name: 'Thing A'}, next);
|
||||
}
|
||||
},
|
||||
], done);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - products', function(done) {
|
||||
Category.findById(ids.categoryA, function(err, cat) {
|
||||
should.not.exist(err);
|
||||
|
@ -727,21 +714,21 @@ describe('default scope', function () {
|
|||
products[1].name.should.equal('Tool A');
|
||||
products[2].name.should.equal('Widget A');
|
||||
products[3].name.should.equal('Widget B');
|
||||
|
||||
|
||||
products[0].should.be.instanceof(Product);
|
||||
products[0].should.be.instanceof(Thing);
|
||||
|
||||
|
||||
products[1].should.be.instanceof(Product);
|
||||
products[1].should.be.instanceof(Tool);
|
||||
|
||||
|
||||
products[2].should.be.instanceof(Product);
|
||||
products[2].should.be.instanceof(Widget);
|
||||
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - widgets', function(done) {
|
||||
Category.findById(ids.categoryA, function(err, cat) {
|
||||
should.not.exist(err);
|
||||
|
@ -758,7 +745,7 @@ describe('default scope', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - tools', function(done) {
|
||||
Category.findById(ids.categoryA, function(err, cat) {
|
||||
should.not.exist(err);
|
||||
|
@ -774,7 +761,7 @@ describe('default scope', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should apply default scope - things', function(done) {
|
||||
Category.findById(ids.categoryA, function(err, cat) {
|
||||
should.not.exist(err);
|
||||
|
@ -790,13 +777,13 @@ describe('default scope', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should create related item with default scope', function(done) {
|
||||
Category.findById(ids.categoryA, function(err, cat) {
|
||||
cat.tools.create({name: 'Tool B'}, done);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should use relation scope order', function(done) {
|
||||
Category.findById(ids.categoryA, function(err, cat) {
|
||||
should.not.exist(err);
|
||||
|
@ -809,18 +796,16 @@ describe('default scope', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('with include option', function() {
|
||||
|
||||
before(function (done) {
|
||||
before(function(done) {
|
||||
db.automigrate(done);
|
||||
});
|
||||
|
||||
before(function (done) {
|
||||
Person.create({ id: 1, name: 'Person A' }, function(err, person) {
|
||||
person.things.create({ name: 'Thing A' }, done);
|
||||
before(function(done) {
|
||||
Person.create({id: 1, name: 'Person A'}, function(err, person) {
|
||||
person.things.create({name: 'Thing A'}, done);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -835,7 +820,5 @@ describe('default scope', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -1,47 +1,53 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
// This test written in mocha+should.js
|
||||
var should = require('./init.js');
|
||||
|
||||
var db = getSchema();
|
||||
|
||||
describe('defaults', function () {
|
||||
describe('defaults', function() {
|
||||
var Server;
|
||||
|
||||
before(function () {
|
||||
before(function() {
|
||||
Server = db.define('Server', {
|
||||
host: String,
|
||||
port: {type: Number, default: 80},
|
||||
createdAt: {type: Date, default: '$now'}
|
||||
createdAt: {type: Date, default: '$now'},
|
||||
});
|
||||
});
|
||||
|
||||
it('should apply defaults on new', function () {
|
||||
it('should apply defaults on new', function() {
|
||||
var s = new Server;
|
||||
s.port.should.equal(80);
|
||||
});
|
||||
|
||||
it('should apply defaults on create', function (done) {
|
||||
Server.create(function (err, s) {
|
||||
it('should apply defaults on create', function(done) {
|
||||
Server.create(function(err, s) {
|
||||
s.port.should.equal(80);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should apply defaults on read', function (done) {
|
||||
it('should apply defaults on read', function(done) {
|
||||
db.defineProperty('Server', 'host', {
|
||||
type: String,
|
||||
default: 'localhost'
|
||||
default: 'localhost',
|
||||
});
|
||||
Server.all(function (err, servers) {
|
||||
Server.all(function(err, servers) {
|
||||
(new String('localhost')).should.equal(servers[0].host);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should ignore defaults with limited fields', function (done) {
|
||||
Server.create({ host: 'localhost', port: 8080 }, function(err, s) {
|
||||
it('should ignore defaults with limited fields', function(done) {
|
||||
Server.create({host: 'localhost', port: 8080}, function(err, s) {
|
||||
should.not.exist(err);
|
||||
s.port.should.equal(8080);
|
||||
Server.find({ fields: ['host'] }, function (err, servers) {
|
||||
Server.find({fields: ['host']}, function(err, servers) {
|
||||
servers[0].host.should.equal('localhost');
|
||||
servers[0].should.have.property('host');
|
||||
servers[0].should.have.property('port', undefined);
|
||||
|
@ -50,17 +56,17 @@ describe('defaults', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should apply defaults in upsert create', function (done) {
|
||||
Server.upsert({port: 8181 }, function(err, server) {
|
||||
it('should apply defaults in upsert create', function(done) {
|
||||
Server.upsert({port: 8181}, function(err, server) {
|
||||
should.not.exist(err);
|
||||
should.exist(server.createdAt);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should preserve defaults in upsert update', function (done) {
|
||||
it('should preserve defaults in upsert update', function(done) {
|
||||
Server.findOne({}, function(err, server) {
|
||||
Server.upsert({id:server.id, port: 1337 }, function(err, s) {
|
||||
Server.upsert({id: server.id, port: 1337}, function(err, s) {
|
||||
should.not.exist(err);
|
||||
(Number(1337)).should.equal(s.port);
|
||||
server.createdAt.should.eql(s.createdAt);
|
||||
|
@ -68,5 +74,4 @@ describe('defaults', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
// Copyright IBM Corp. 2015,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var jdb = require('../');
|
||||
var DataSource = jdb.DataSource;
|
||||
var should = require('./init.js');
|
||||
|
@ -26,7 +32,7 @@ describe('Memory connector with mocked discovery', function() {
|
|||
dataLength: 20,
|
||||
dataPrecision: null,
|
||||
dataScale: null,
|
||||
nullable: 0
|
||||
nullable: 0,
|
||||
},
|
||||
{
|
||||
owner: 'STRONGLOOP',
|
||||
|
@ -36,7 +42,7 @@ describe('Memory connector with mocked discovery', function() {
|
|||
dataLength: 20,
|
||||
dataPrecision: null,
|
||||
dataScale: null,
|
||||
nullable: 0
|
||||
nullable: 0,
|
||||
},
|
||||
{
|
||||
owner: 'STRONGLOOP',
|
||||
|
@ -46,7 +52,7 @@ describe('Memory connector with mocked discovery', function() {
|
|||
dataLength: null,
|
||||
dataPrecision: 10,
|
||||
dataScale: 0,
|
||||
nullable: 1
|
||||
nullable: 1,
|
||||
},
|
||||
{
|
||||
owner: 'STRONGLOOP',
|
||||
|
@ -56,7 +62,7 @@ describe('Memory connector with mocked discovery', function() {
|
|||
dataLength: null,
|
||||
dataPrecision: 10,
|
||||
dataScale: 0,
|
||||
nullable: 1
|
||||
nullable: 1,
|
||||
}];
|
||||
|
||||
ds.discoverModelProperties = function(modelName, options, cb) {
|
||||
|
@ -83,7 +89,7 @@ describe('Memory connector with mocked discovery', function() {
|
|||
nameMapper: function(type, name) {
|
||||
// Convert all names to lower case
|
||||
return name.toLowerCase();
|
||||
}
|
||||
},
|
||||
}, function(err, schemas) {
|
||||
if (err) return done(err);
|
||||
schemas.should.have.property('STRONGLOOP.INVENTORY');
|
||||
|
@ -113,8 +119,8 @@ describe('Memory connector with mocked discovery', function() {
|
|||
var models = {
|
||||
inventory: {
|
||||
product: {type: 'string'},
|
||||
location: {type: 'string'}
|
||||
}
|
||||
location: {type: 'string'},
|
||||
},
|
||||
};
|
||||
ds.connector.discoverSchemas = function(modelName, options, cb) {
|
||||
process.nextTick(function() {
|
||||
|
@ -133,8 +139,8 @@ describe('Memory connector with mocked discovery', function() {
|
|||
var models = {
|
||||
inventory: {
|
||||
product: {type: 'string'},
|
||||
location: {type: 'string'}
|
||||
}
|
||||
location: {type: 'string'},
|
||||
},
|
||||
};
|
||||
ds.connector.discoverSchemas = function(modelName, options, cb) {
|
||||
process.nextTick(function() {
|
||||
|
@ -169,9 +175,9 @@ describe('Memory connector with mocked discovery', function() {
|
|||
.catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('discoverSchema', function(){
|
||||
describe('discoverSchema', function() {
|
||||
var models;
|
||||
var schema;
|
||||
before(function() {
|
||||
|
@ -179,7 +185,7 @@ describe('Memory connector with mocked discovery', function() {
|
|||
name: 'Inventory',
|
||||
options: {
|
||||
idInjection: false,
|
||||
memory: { schema: 'STRONGLOOP', table: 'INVENTORY' }
|
||||
memory: {schema: 'STRONGLOOP', table: 'INVENTORY'},
|
||||
},
|
||||
properties: {
|
||||
available: {
|
||||
|
@ -190,12 +196,12 @@ describe('Memory connector with mocked discovery', function() {
|
|||
dataPrecision: 10,
|
||||
dataScale: 0,
|
||||
dataType: 'int',
|
||||
nullable: 1
|
||||
nullable: 1,
|
||||
},
|
||||
precision: 10,
|
||||
required: false,
|
||||
scale: 0,
|
||||
type: undefined
|
||||
type: undefined,
|
||||
},
|
||||
locationId: {
|
||||
length: 20,
|
||||
|
@ -205,12 +211,12 @@ describe('Memory connector with mocked discovery', function() {
|
|||
dataPrecision: null,
|
||||
dataScale: null,
|
||||
dataType: 'varchar',
|
||||
nullable: 0
|
||||
nullable: 0,
|
||||
},
|
||||
precision: null,
|
||||
required: true,
|
||||
scale: null,
|
||||
type: undefined
|
||||
type: undefined,
|
||||
},
|
||||
productId: {
|
||||
length: 20,
|
||||
|
@ -220,12 +226,12 @@ describe('Memory connector with mocked discovery', function() {
|
|||
dataPrecision: null,
|
||||
dataScale: null,
|
||||
dataType: 'varchar',
|
||||
nullable: 0
|
||||
nullable: 0,
|
||||
},
|
||||
precision: null,
|
||||
required: true,
|
||||
scale: null,
|
||||
type: undefined
|
||||
type: undefined,
|
||||
},
|
||||
total: {
|
||||
length: null,
|
||||
|
@ -235,15 +241,15 @@ describe('Memory connector with mocked discovery', function() {
|
|||
dataPrecision: 10,
|
||||
dataScale: 0,
|
||||
dataType: 'int',
|
||||
nullable: 1
|
||||
nullable: 1,
|
||||
},
|
||||
precision: 10,
|
||||
required: false,
|
||||
scale: 0,
|
||||
type: undefined
|
||||
}
|
||||
}
|
||||
} ;
|
||||
type: undefined,
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
it('should discover schema using `discoverSchema`', function(done) {
|
||||
|
@ -270,16 +276,16 @@ describe('Memory connector with mocked discovery', function() {
|
|||
schemas.should.be.eql(schema);
|
||||
done();
|
||||
})
|
||||
.catch(function(err){
|
||||
.catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('discoverModelDefinitions', function(){
|
||||
describe('discoverModelDefinitions', function() {
|
||||
var ds;
|
||||
before(function(){
|
||||
before(function() {
|
||||
ds = new DataSource({connector: 'memory'});
|
||||
|
||||
var models = [{type: 'table', name: 'CUSTOMER', owner: 'STRONGLOOP'},
|
||||
|
@ -302,7 +308,7 @@ describe('discoverModelDefinitions', function(){
|
|||
});
|
||||
|
||||
tableNames.should.be.eql(
|
||||
["CUSTOMER", "INVENTORY", "LOCATION"]
|
||||
['CUSTOMER', 'INVENTORY', 'LOCATION']
|
||||
);
|
||||
done();
|
||||
});
|
||||
|
@ -317,7 +323,7 @@ describe('discoverModelDefinitions', function(){
|
|||
});
|
||||
|
||||
tableNames.should.be.eql(
|
||||
["CUSTOMER", "INVENTORY", "LOCATION"]
|
||||
['CUSTOMER', 'INVENTORY', 'LOCATION']
|
||||
);
|
||||
done();
|
||||
};
|
||||
|
@ -333,20 +339,20 @@ describe('discoverModelDefinitions', function(){
|
|||
});
|
||||
|
||||
tableNames.should.be.eql(
|
||||
["CUSTOMER", "INVENTORY", "LOCATION"]
|
||||
['CUSTOMER', 'INVENTORY', 'LOCATION']
|
||||
);
|
||||
done();
|
||||
})
|
||||
.catch(function(err){
|
||||
.catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('discoverModelProperties', function(){
|
||||
describe('discoverModelProperties', function() {
|
||||
var ds;
|
||||
var modelProperties;
|
||||
before(function(){
|
||||
before(function() {
|
||||
ds = new DataSource({connector: 'memory'});
|
||||
|
||||
modelProperties = [{
|
||||
|
@ -357,38 +363,38 @@ describe('discoverModelProperties', function(){
|
|||
dataLength: 20,
|
||||
dataPrecision: null,
|
||||
dataScale: null,
|
||||
nullable: 0
|
||||
nullable: 0,
|
||||
},
|
||||
{
|
||||
owner: 'STRONGLOOP',
|
||||
tableName: 'INVENTORY',
|
||||
columnName: 'LOCATION_ID',
|
||||
dataType: 'varchar',
|
||||
dataLength: 20,
|
||||
dataPrecision: null,
|
||||
dataScale: null,
|
||||
nullable: 0
|
||||
},
|
||||
{
|
||||
owner: 'STRONGLOOP',
|
||||
tableName: 'INVENTORY',
|
||||
columnName: 'AVAILABLE',
|
||||
dataType: 'int',
|
||||
dataLength: null,
|
||||
dataPrecision: 10,
|
||||
dataScale: 0,
|
||||
nullable: 1
|
||||
},
|
||||
{
|
||||
owner: 'STRONGLOOP',
|
||||
tableName: 'INVENTORY',
|
||||
columnName: 'TOTAL',
|
||||
dataType: 'int',
|
||||
dataLength: null,
|
||||
dataPrecision: 10,
|
||||
dataScale: 0,
|
||||
nullable: 1
|
||||
}];
|
||||
{
|
||||
owner: 'STRONGLOOP',
|
||||
tableName: 'INVENTORY',
|
||||
columnName: 'LOCATION_ID',
|
||||
dataType: 'varchar',
|
||||
dataLength: 20,
|
||||
dataPrecision: null,
|
||||
dataScale: null,
|
||||
nullable: 0,
|
||||
},
|
||||
{
|
||||
owner: 'STRONGLOOP',
|
||||
tableName: 'INVENTORY',
|
||||
columnName: 'AVAILABLE',
|
||||
dataType: 'int',
|
||||
dataLength: null,
|
||||
dataPrecision: 10,
|
||||
dataScale: 0,
|
||||
nullable: 1,
|
||||
},
|
||||
{
|
||||
owner: 'STRONGLOOP',
|
||||
tableName: 'INVENTORY',
|
||||
columnName: 'TOTAL',
|
||||
dataType: 'int',
|
||||
dataLength: null,
|
||||
dataPrecision: 10,
|
||||
dataScale: 0,
|
||||
nullable: 1,
|
||||
}];
|
||||
|
||||
ds.connector.discoverModelProperties = function(modelName, options, cb) {
|
||||
process.nextTick(function() {
|
||||
|
@ -399,11 +405,11 @@ describe('discoverModelProperties', function(){
|
|||
|
||||
it('should callback function, passed as options parameter', function(done) {
|
||||
var options = function(err, schemas) {
|
||||
if (err) return done(err);
|
||||
if (err) return done(err);
|
||||
|
||||
schemas.should.be.eql(modelProperties);
|
||||
done();
|
||||
};
|
||||
schemas.should.be.eql(modelProperties);
|
||||
done();
|
||||
};
|
||||
|
||||
ds.discoverModelProperties('INVENTORY', options);
|
||||
});
|
||||
|
@ -423,32 +429,32 @@ describe('discoverModelProperties', function(){
|
|||
schemas.should.be.eql(modelProperties);
|
||||
done();
|
||||
})
|
||||
.catch(function(err){
|
||||
.catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('discoverPrimaryKeys', function(){
|
||||
describe('discoverPrimaryKeys', function() {
|
||||
var ds;
|
||||
var modelProperties;
|
||||
before(function(){
|
||||
var modelProperties, primaryKeys;
|
||||
before(function() {
|
||||
ds = new DataSource({connector: 'memory'});
|
||||
|
||||
primaryKeys = [
|
||||
{
|
||||
{
|
||||
owner: 'STRONGLOOP',
|
||||
tableName: 'INVENTORY',
|
||||
columnName: 'PRODUCT_ID',
|
||||
keySeq: 1,
|
||||
pkName: 'ID_PK'
|
||||
},
|
||||
{
|
||||
pkName: 'ID_PK',
|
||||
},
|
||||
{
|
||||
owner: 'STRONGLOOP',
|
||||
tableName: 'INVENTORY',
|
||||
columnName: 'LOCATION_ID',
|
||||
keySeq: 2,
|
||||
pkName: 'ID_PK'
|
||||
pkName: 'ID_PK',
|
||||
}];
|
||||
|
||||
ds.connector.discoverPrimaryKeys = function(modelName, options, cb) {
|
||||
|
@ -483,19 +489,19 @@ describe('discoverPrimaryKeys', function(){
|
|||
modelPrimaryKeys.should.be.eql(primaryKeys);
|
||||
done();
|
||||
})
|
||||
.catch(function(err){
|
||||
.catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('discoverForeignKeys', function(){
|
||||
describe('discoverForeignKeys', function() {
|
||||
var ds;
|
||||
var modelProperties;
|
||||
before(function(){
|
||||
var modelProperties, foreignKeys;
|
||||
before(function() {
|
||||
ds = new DataSource({connector: 'memory'});
|
||||
|
||||
foreignKeys = [{
|
||||
foreignKeys = [{
|
||||
fkOwner: 'STRONGLOOP',
|
||||
fkName: 'PRODUCT_FK',
|
||||
fkTableName: 'INVENTORY',
|
||||
|
@ -504,7 +510,7 @@ describe('discoverForeignKeys', function(){
|
|||
pkOwner: 'STRONGLOOP',
|
||||
pkName: 'PRODUCT_PK',
|
||||
pkTableName: 'PRODUCT',
|
||||
pkColumnName: 'ID'
|
||||
pkColumnName: 'ID',
|
||||
}];
|
||||
|
||||
ds.connector.discoverForeignKeys = function(modelName, options, cb) {
|
||||
|
@ -540,16 +546,16 @@ describe('discoverForeignKeys', function(){
|
|||
modelForeignKeys.should.be.eql(foreignKeys);
|
||||
done();
|
||||
})
|
||||
.catch(function(err){
|
||||
.catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('discoverExportedForeignKeys', function(){
|
||||
describe('discoverExportedForeignKeys', function() {
|
||||
var ds;
|
||||
var modelProperties;
|
||||
before(function(){
|
||||
var modelProperties, exportedForeignKeys;
|
||||
before(function() {
|
||||
ds = new DataSource({connector: 'memory'});
|
||||
|
||||
exportedForeignKeys = [{
|
||||
|
@ -561,7 +567,7 @@ describe('discoverExportedForeignKeys', function(){
|
|||
pkName: 'PRODUCT_PK',
|
||||
pkOwner: 'STRONGLOOP',
|
||||
pkTableName: 'PRODUCT',
|
||||
pkColumnName: 'ID'
|
||||
pkColumnName: 'ID',
|
||||
}];
|
||||
|
||||
ds.connector.discoverExportedForeignKeys = function(modelName, options, cb) {
|
||||
|
@ -591,13 +597,14 @@ describe('discoverExportedForeignKeys', function(){
|
|||
ds.discoverExportedForeignKeys('INVENTORY', options);
|
||||
});
|
||||
|
||||
it('should discover foreign key definitions using `discoverExportedForeignKeys` - promise variant', function(done) {
|
||||
it('should discover foreign key definitions using ' +
|
||||
'`discoverExportedForeignKeys` - promise variant', function(done) {
|
||||
ds.discoverExportedForeignKeys('INVENTORY', {})
|
||||
.then(function(modelForeignKeys) {
|
||||
modelForeignKeys.should.be.eql(exportedForeignKeys);
|
||||
done();
|
||||
})
|
||||
.catch(function(err){
|
||||
.catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var should = require('./init.js');
|
||||
|
||||
describe('events', function() {
|
||||
|
@ -6,9 +12,9 @@ describe('events', function() {
|
|||
this.db = getSchema();
|
||||
this.TestModel = this.db.define('TestModel');
|
||||
this.db.automigrate(function(err) {
|
||||
if(err) return done(err);
|
||||
if (err) return done(err);
|
||||
test.TestModel.create(function(err, inst) {
|
||||
if(err) return done(err);
|
||||
if (err) return done(err);
|
||||
test.inst = inst;
|
||||
done();
|
||||
});
|
||||
|
@ -18,7 +24,7 @@ describe('events', function() {
|
|||
listener.apply(this, arguments);
|
||||
done();
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
describe('changed', function() {
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
|
||||
'use strict';
|
||||
|
||||
throw new Error('expected test error');
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"name": "loopback-connector-throwing",
|
||||
"version": "1.0.0",
|
||||
"description": "A dummy connector that throws at initialization time."
|
||||
}
|
|
@ -1,3 +1,9 @@
|
|||
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
/*global describe,it*/
|
||||
/*jshint expr:true */
|
||||
|
||||
|
@ -6,39 +12,37 @@ require('should');
|
|||
var GeoPoint = require('../lib/geo').GeoPoint;
|
||||
var DELTA = 0.0000001;
|
||||
|
||||
describe('GeoPoint', function () {
|
||||
|
||||
describe('GeoPoint', function() {
|
||||
describe('constructor', function() {
|
||||
|
||||
it('should support a valid array', function () {
|
||||
it('should support a valid array', function() {
|
||||
var point = new GeoPoint([-34, 150]);
|
||||
|
||||
point.lat.should.equal(-34);
|
||||
point.lng.should.equal(150);
|
||||
});
|
||||
|
||||
it('should support a valid object', function () {
|
||||
var point = new GeoPoint({ lat: -34, lng: 150 });
|
||||
it('should support a valid object', function() {
|
||||
var point = new GeoPoint({lat: -34, lng: 150});
|
||||
|
||||
point.lat.should.equal(-34);
|
||||
point.lng.should.equal(150);
|
||||
});
|
||||
|
||||
it('should support valid string geo coordinates', function () {
|
||||
it('should support valid string geo coordinates', function() {
|
||||
var point = new GeoPoint('-34,150');
|
||||
|
||||
point.lat.should.equal(-34);
|
||||
point.lng.should.equal(150);
|
||||
});
|
||||
|
||||
it('should support coordinates as inline parameters', function () {
|
||||
it('should support coordinates as inline parameters', function() {
|
||||
var point = new GeoPoint(-34, 150);
|
||||
|
||||
point.lat.should.equal(-34);
|
||||
point.lng.should.equal(150);
|
||||
});
|
||||
|
||||
it('should reject invalid parameters', function () {
|
||||
it('should reject invalid parameters', function() {
|
||||
/*jshint -W024 */
|
||||
var fn = function() {
|
||||
new GeoPoint('150,-34');
|
||||
|
@ -58,7 +62,7 @@ describe('GeoPoint', function () {
|
|||
fn = function() {
|
||||
new GeoPoint({
|
||||
lat: 150,
|
||||
lng: null
|
||||
lng: null,
|
||||
});
|
||||
};
|
||||
fn.should.throw();
|
||||
|
@ -73,33 +77,26 @@ describe('GeoPoint', function () {
|
|||
};
|
||||
fn.should.throw();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('toString()', function() {
|
||||
|
||||
it('should return a string in the form "lat,lng"', function() {
|
||||
|
||||
var point = new GeoPoint({ lat: -34, lng: 150 });
|
||||
var point = new GeoPoint({lat: -34, lng: 150});
|
||||
point.toString().should.equal('-34,150');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('distance calculation between two points', function () {
|
||||
|
||||
var here = new GeoPoint({ lat: 40.77492964101182, lng: -73.90950187151662 });
|
||||
var there = new GeoPoint({ lat: 40.7753227, lng: -73.909217 });
|
||||
|
||||
it('should return value in miles by default', function () {
|
||||
describe('distance calculation between two points', function() {
|
||||
var here = new GeoPoint({lat: 40.77492964101182, lng: -73.90950187151662});
|
||||
var there = new GeoPoint({lat: 40.7753227, lng: -73.909217});
|
||||
|
||||
it('should return value in miles by default', function() {
|
||||
var distance = GeoPoint.distanceBetween(here, there);
|
||||
distance.should.be.a.Number;
|
||||
distance.should.be.approximately(0.03097916611592679, DELTA);
|
||||
});
|
||||
|
||||
it('should return value using specified unit', function () {
|
||||
|
||||
it('should return value using specified unit', function() {
|
||||
/* Supported units:
|
||||
* - `radians`
|
||||
* - `kilometers`
|
||||
|
@ -109,31 +106,29 @@ describe('GeoPoint', function () {
|
|||
* - `degrees`
|
||||
*/
|
||||
|
||||
var distance = here.distanceTo(there, { type: 'radians'});
|
||||
var distance = here.distanceTo(there, {type: 'radians'});
|
||||
distance.should.be.a.Number;
|
||||
distance.should.be.approximately(0.000007825491914348416, DELTA);
|
||||
|
||||
distance = here.distanceTo(there, { type: 'kilometers'});
|
||||
distance = here.distanceTo(there, {type: 'kilometers'});
|
||||
distance.should.be.a.Number;
|
||||
distance.should.be.approximately(0.04985613511367009, DELTA);
|
||||
|
||||
distance = here.distanceTo(there, { type: 'meters'});
|
||||
distance = here.distanceTo(there, {type: 'meters'});
|
||||
distance.should.be.a.Number;
|
||||
distance.should.be.approximately(49.856135113670085, DELTA);
|
||||
|
||||
distance = here.distanceTo(there, { type: 'miles'});
|
||||
distance = here.distanceTo(there, {type: 'miles'});
|
||||
distance.should.be.a.Number;
|
||||
distance.should.be.approximately(0.03097916611592679, DELTA);
|
||||
|
||||
distance = here.distanceTo(there, { type: 'feet'});
|
||||
distance = here.distanceTo(there, {type: 'feet'});
|
||||
distance.should.be.a.Number;
|
||||
distance.should.be.approximately(163.56999709209347, DELTA);
|
||||
|
||||
distance = here.distanceTo(there, { type: 'degrees'});
|
||||
distance = here.distanceTo(there, {type: 'degrees'});
|
||||
distance.should.be.a.Number;
|
||||
distance.should.be.approximately(0.0004483676593058972, DELTA);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright IBM Corp. 2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
exports.describeIf = function describeIf(cond, name, fn) {
|
||||
if (cond)
|
||||
describe(name, fn);
|
||||
else
|
||||
describe.skip(name, fn);
|
||||
};
|
||||
|
||||
exports.itIf = function itIf(cond, name, fn) {
|
||||
if (cond)
|
||||
it(name, fn);
|
||||
else
|
||||
it.skip(name, fn);
|
||||
};
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright IBM Corp. 2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var traverse = require('traverse');
|
||||
|
||||
exports.ContextRecorder = ContextRecorder;
|
||||
exports.deepCloneToObject = deepCloneToObject;
|
||||
exports.aCtxForModel = aCtxForModel;
|
||||
|
||||
function ContextRecorder(initialValue) {
|
||||
if (!(this instanceof ContextRecorder)) {
|
||||
return new ContextRecorder(initialValue);
|
||||
}
|
||||
this.records = initialValue;
|
||||
};
|
||||
|
||||
ContextRecorder.prototype.recordAndNext = function(transformFm) {
|
||||
var self = this;
|
||||
return function(context, next) {
|
||||
if (typeof transformFm === 'function') {
|
||||
transformFm(context);
|
||||
}
|
||||
|
||||
context = deepCloneToObject(context);
|
||||
context.hookState.test = true;
|
||||
|
||||
if (typeof self.records === 'string') {
|
||||
self.records = context;
|
||||
return next();
|
||||
}
|
||||
|
||||
if (!Array.isArray(self.records)) {
|
||||
self.records = [self.records];
|
||||
}
|
||||
|
||||
self.records.push(context);
|
||||
next();
|
||||
};
|
||||
};
|
||||
|
||||
function deepCloneToObject(obj) {
|
||||
return traverse(obj).map(function(x) {
|
||||
if (x === undefined) {
|
||||
// RDBMSs return null
|
||||
return null;
|
||||
}
|
||||
if (x && x.toObject)
|
||||
return x.toObject(true);
|
||||
if (x && typeof x === 'function' && x.modelName)
|
||||
return '[ModelCtor ' + x.modelName + ']';
|
||||
});
|
||||
}
|
||||
|
||||
function aCtxForModel(TestModel, ctx) {
|
||||
ctx.Model = TestModel;
|
||||
|
||||
if (!ctx.hookState) {
|
||||
ctx.hookState = {};
|
||||
}
|
||||
|
||||
if (!('test' in ctx.hookState)) {
|
||||
ctx.hookState.test = true;
|
||||
}
|
||||
|
||||
if (!ctx.options) {
|
||||
ctx.options = {};
|
||||
}
|
||||
return deepCloneToObject(ctx);
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright IBM Corp. 2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
module.exports = HookMonitor;
|
||||
|
||||
function HookMonitor(opts) {
|
||||
if (!(this instanceof HookMonitor)) {
|
||||
return new HookMonitor();
|
||||
}
|
||||
|
||||
this.options = opts || {};
|
||||
this.names = [];
|
||||
};
|
||||
|
||||
HookMonitor.prototype.install = function(ObservedModel, hookNames) {
|
||||
var monitor = this;
|
||||
this.names = [];
|
||||
ObservedModel._notify = ObservedModel.notifyObserversOf;
|
||||
ObservedModel.notifyObserversOf = function(operation, context, callback) {
|
||||
if (!Array.isArray(hookNames) || hookNames.indexOf(operation) !== -1) {
|
||||
var item = monitor.options.includeModelName ?
|
||||
ObservedModel.modelName + ':' + operation :
|
||||
operation;
|
||||
monitor.names.push(item);
|
||||
}
|
||||
this._notify.apply(this, arguments);
|
||||
};
|
||||
};
|
||||
|
||||
HookMonitor.prototype.resetNames = function() {
|
||||
this.names = [];
|
||||
};
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright IBM Corp. 2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var lastId = 0;
|
||||
|
||||
exports.next = function() {
|
||||
lastId++;
|
||||
return exports.last();
|
||||
};
|
||||
|
||||
exports.last = function() {
|
||||
return '' + lastId;
|
||||
};
|
||||
|
||||
exports.reset = function() {
|
||||
lastId = 0;
|
||||
};
|
|
@ -1,3 +1,9 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
// This test written in mocha+should.js
|
||||
var should = require('./init.js');
|
||||
|
||||
|
@ -8,160 +14,156 @@ var j = require('../'),
|
|||
|
||||
db, User;
|
||||
|
||||
describe('hooks', function () {
|
||||
|
||||
before(function (done) {
|
||||
describe('hooks', function() {
|
||||
before(function(done) {
|
||||
db = getSchema();
|
||||
|
||||
User = db.define('User', {
|
||||
email: {type: String, index: true},
|
||||
name: String,
|
||||
password: String,
|
||||
state: String
|
||||
state: String,
|
||||
});
|
||||
|
||||
db.automigrate('User', done);
|
||||
});
|
||||
|
||||
describe('initialize', function () {
|
||||
|
||||
afterEach(function () {
|
||||
describe('initialize', function() {
|
||||
afterEach(function() {
|
||||
User.afterInitialize = null;
|
||||
});
|
||||
|
||||
it('should be triggered on new', function (done) {
|
||||
User.afterInitialize = function () {
|
||||
it('should be triggered on new', function(done) {
|
||||
User.afterInitialize = function() {
|
||||
done();
|
||||
};
|
||||
new User;
|
||||
});
|
||||
|
||||
it('should be triggered on create', function (done) {
|
||||
it('should be triggered on create', function(done) {
|
||||
var user;
|
||||
User.afterInitialize = function () {
|
||||
User.afterInitialize = function() {
|
||||
if (this.name === 'Nickolay') {
|
||||
this.name += ' Rozental';
|
||||
}
|
||||
};
|
||||
User.create({name: 'Nickolay'}, function (err, u) {
|
||||
User.create({name: 'Nickolay'}, function(err, u) {
|
||||
u.id.should.be.ok;
|
||||
u.name.should.equal('Nickolay Rozental');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('create', function () {
|
||||
|
||||
describe('create', function() {
|
||||
afterEach(removeHooks('Create'));
|
||||
|
||||
it('should be triggered on create', function (done) {
|
||||
it('should be triggered on create', function(done) {
|
||||
addHooks('Create', done);
|
||||
User.create();
|
||||
});
|
||||
|
||||
it('should not be triggered on new', function () {
|
||||
User.beforeCreate = function (next) {
|
||||
it('should not be triggered on new', function() {
|
||||
User.beforeCreate = function(next) {
|
||||
should.fail('This should not be called');
|
||||
next();
|
||||
};
|
||||
var u = new User;
|
||||
});
|
||||
|
||||
it('should be triggered on new+save', function (done) {
|
||||
it('should be triggered on new+save', function(done) {
|
||||
addHooks('Create', done);
|
||||
(new User).save();
|
||||
});
|
||||
|
||||
it('afterCreate should not be triggered on failed create', function (done) {
|
||||
it('afterCreate should not be triggered on failed create', function(done) {
|
||||
var old = User.dataSource.connector.create;
|
||||
User.dataSource.connector.create = function (modelName, id, cb) {
|
||||
User.dataSource.connector.create = function(modelName, id, cb) {
|
||||
cb(new Error('error'));
|
||||
}
|
||||
};
|
||||
|
||||
User.afterCreate = function () {
|
||||
User.afterCreate = function() {
|
||||
throw new Error('shouldn\'t be called');
|
||||
};
|
||||
User.create(function (err, user) {
|
||||
User.create(function(err, user) {
|
||||
User.dataSource.connector.create = old;
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('afterCreate should not be triggered on failed beforeCreate', function (done) {
|
||||
User.beforeCreate = function (next, data) {
|
||||
it('afterCreate should not be triggered on failed beforeCreate', function(done) {
|
||||
User.beforeCreate = function(next, data) {
|
||||
// Skip next()
|
||||
next(new Error('fail in beforeCreate'));
|
||||
};
|
||||
|
||||
var old = User.dataSource.connector.create;
|
||||
User.dataSource.connector.create = function (modelName, id, cb) {
|
||||
throw new Error('shouldn\'t be called');
|
||||
}
|
||||
|
||||
User.afterCreate = function () {
|
||||
User.dataSource.connector.create = function(modelName, id, cb) {
|
||||
throw new Error('shouldn\'t be called');
|
||||
};
|
||||
User.create(function (err, user) {
|
||||
|
||||
User.afterCreate = function() {
|
||||
throw new Error('shouldn\'t be called');
|
||||
};
|
||||
User.create(function(err, user) {
|
||||
User.dataSource.connector.create = old;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('save', function () {
|
||||
describe('save', function() {
|
||||
afterEach(removeHooks('Save'));
|
||||
|
||||
it('should be triggered on create', function (done) {
|
||||
it('should be triggered on create', function(done) {
|
||||
addHooks('Save', done);
|
||||
User.create();
|
||||
});
|
||||
|
||||
it('should be triggered on new+save', function (done) {
|
||||
it('should be triggered on new+save', function(done) {
|
||||
addHooks('Save', done);
|
||||
(new User).save();
|
||||
});
|
||||
|
||||
it('should be triggered on updateAttributes', function (done) {
|
||||
User.create(function (err, user) {
|
||||
it('should be triggered on updateAttributes', function(done) {
|
||||
User.create(function(err, user) {
|
||||
addHooks('Save', done);
|
||||
user.updateAttributes({name: 'Anatoliy'});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be triggered on save', function (done) {
|
||||
User.create(function (err, user) {
|
||||
it('should be triggered on save', function(done) {
|
||||
User.create(function(err, user) {
|
||||
addHooks('Save', done);
|
||||
user.name = 'Hamburger';
|
||||
user.save();
|
||||
});
|
||||
});
|
||||
|
||||
it('should save full object', function (done) {
|
||||
User.create(function (err, user) {
|
||||
User.beforeSave = function (next, data) {
|
||||
it('should save full object', function(done) {
|
||||
User.create(function(err, user) {
|
||||
User.beforeSave = function(next, data) {
|
||||
data.should.have.keys('id', 'name', 'email',
|
||||
'password', 'state')
|
||||
'password', 'state');
|
||||
done();
|
||||
};
|
||||
user.save();
|
||||
});
|
||||
});
|
||||
|
||||
it('should save actual modifications to database', function (done) {
|
||||
User.beforeSave = function (next, data) {
|
||||
it('should save actual modifications to database', function(done) {
|
||||
User.beforeSave = function(next, data) {
|
||||
data.password = 'hash';
|
||||
next();
|
||||
};
|
||||
User.destroyAll(function () {
|
||||
User.destroyAll(function() {
|
||||
User.create({
|
||||
email: 'james.bond@example.com',
|
||||
password: '53cr3t'
|
||||
}, function () {
|
||||
password: '53cr3t',
|
||||
}, function() {
|
||||
User.findOne({
|
||||
where: {email: 'james.bond@example.com'}
|
||||
}, function (err, jb) {
|
||||
where: {email: 'james.bond@example.com'},
|
||||
}, function(err, jb) {
|
||||
jb.password.should.equal('hash');
|
||||
done();
|
||||
});
|
||||
|
@ -169,22 +171,22 @@ describe('hooks', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should save actual modifications on updateAttributes', function (done) {
|
||||
User.beforeSave = function (next, data) {
|
||||
it('should save actual modifications on updateAttributes', function(done) {
|
||||
User.beforeSave = function(next, data) {
|
||||
data.password = 'hash';
|
||||
next();
|
||||
};
|
||||
User.destroyAll(function () {
|
||||
User.destroyAll(function() {
|
||||
User.create({
|
||||
email: 'james.bond@example.com'
|
||||
}, function (err, u) {
|
||||
u.updateAttribute('password', 'new password', function (e, u) {
|
||||
email: 'james.bond@example.com',
|
||||
}, function(err, u) {
|
||||
u.updateAttribute('password', 'new password', function(e, u) {
|
||||
should.not.exist(e);
|
||||
should.exist(u);
|
||||
u.password.should.equal('hash');
|
||||
User.findOne({
|
||||
where: {email: 'james.bond@example.com'}
|
||||
}, function (err, jb) {
|
||||
where: {email: 'james.bond@example.com'},
|
||||
}, function(err, jb) {
|
||||
jb.password.should.equal('hash');
|
||||
done();
|
||||
});
|
||||
|
@ -193,9 +195,9 @@ describe('hooks', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('beforeSave should be able to skip next', function (done) {
|
||||
User.create(function (err, user) {
|
||||
User.beforeSave = function (next, data) {
|
||||
it('beforeSave should be able to skip next', function(done) {
|
||||
User.create(function(err, user) {
|
||||
User.beforeSave = function(next, data) {
|
||||
next(null, 'XYZ');
|
||||
};
|
||||
user.save(function(err, result) {
|
||||
|
@ -204,46 +206,45 @@ describe('hooks', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('update', function () {
|
||||
describe('update', function() {
|
||||
afterEach(removeHooks('Update'));
|
||||
|
||||
it('should not be triggered on create', function () {
|
||||
User.beforeUpdate = function (next) {
|
||||
it('should not be triggered on create', function() {
|
||||
User.beforeUpdate = function(next) {
|
||||
should.fail('This should not be called');
|
||||
next();
|
||||
};
|
||||
User.create();
|
||||
});
|
||||
|
||||
it('should not be triggered on new+save', function () {
|
||||
User.beforeUpdate = function (next) {
|
||||
it('should not be triggered on new+save', function() {
|
||||
User.beforeUpdate = function(next) {
|
||||
should.fail('This should not be called');
|
||||
next();
|
||||
};
|
||||
(new User).save();
|
||||
});
|
||||
|
||||
it('should be triggered on updateAttributes', function (done) {
|
||||
User.create(function (err, user) {
|
||||
it('should be triggered on updateAttributes', function(done) {
|
||||
User.create(function(err, user) {
|
||||
addHooks('Update', done);
|
||||
user.updateAttributes({name: 'Anatoliy'});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be triggered on save', function (done) {
|
||||
User.create(function (err, user) {
|
||||
it('should be triggered on save', function(done) {
|
||||
User.create(function(err, user) {
|
||||
addHooks('Update', done);
|
||||
user.name = 'Hamburger';
|
||||
user.save();
|
||||
});
|
||||
});
|
||||
|
||||
it('should update limited set of fields', function (done) {
|
||||
User.create(function (err, user) {
|
||||
User.beforeUpdate = function (next, data) {
|
||||
it('should update limited set of fields', function(done) {
|
||||
User.create(function(err, user) {
|
||||
User.beforeUpdate = function(next, data) {
|
||||
data.should.have.keys('name', 'email');
|
||||
done();
|
||||
};
|
||||
|
@ -251,119 +252,117 @@ describe('hooks', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should not trigger after-hook on failed save', function (done) {
|
||||
User.afterUpdate = function () {
|
||||
it('should not trigger after-hook on failed save', function(done) {
|
||||
User.afterUpdate = function() {
|
||||
should.fail('afterUpdate shouldn\'t be called');
|
||||
};
|
||||
User.create(function (err, user) {
|
||||
User.create(function(err, user) {
|
||||
var save = User.dataSource.connector.save;
|
||||
User.dataSource.connector.save = function (modelName, id, cb) {
|
||||
User.dataSource.connector.save = function(modelName, id, cb) {
|
||||
User.dataSource.connector.save = save;
|
||||
cb(new Error('Error'));
|
||||
}
|
||||
};
|
||||
|
||||
user.save(function (err) {
|
||||
user.save(function(err) {
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('destroy', function () {
|
||||
|
||||
describe('destroy', function() {
|
||||
afterEach(removeHooks('Destroy'));
|
||||
|
||||
it('should be triggered on destroy', function (done) {
|
||||
it('should be triggered on destroy', function(done) {
|
||||
var hook = 'not called';
|
||||
User.beforeDestroy = function (next) {
|
||||
User.beforeDestroy = function(next) {
|
||||
hook = 'called';
|
||||
next();
|
||||
};
|
||||
User.afterDestroy = function (next) {
|
||||
User.afterDestroy = function(next) {
|
||||
hook.should.eql('called');
|
||||
next();
|
||||
};
|
||||
User.create(function (err, user) {
|
||||
User.create(function(err, user) {
|
||||
user.destroy(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not trigger after-hook on failed destroy', function (done) {
|
||||
it('should not trigger after-hook on failed destroy', function(done) {
|
||||
var destroy = User.dataSource.connector.destroy;
|
||||
User.dataSource.connector.destroy = function (modelName, id, cb) {
|
||||
User.dataSource.connector.destroy = function(modelName, id, cb) {
|
||||
cb(new Error('error'));
|
||||
}
|
||||
User.afterDestroy = function () {
|
||||
should.fail('afterDestroy shouldn\'t be called')
|
||||
};
|
||||
User.create(function (err, user) {
|
||||
user.destroy(function (err) {
|
||||
User.afterDestroy = function() {
|
||||
should.fail('afterDestroy shouldn\'t be called');
|
||||
};
|
||||
User.create(function(err, user) {
|
||||
user.destroy(function(err) {
|
||||
User.dataSource.connector.destroy = destroy;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('lifecycle', function () {
|
||||
describe('lifecycle', function() {
|
||||
var life = [], user;
|
||||
before(function (done) {
|
||||
User.beforeSave = function (d) {
|
||||
before(function(done) {
|
||||
User.beforeSave = function(d) {
|
||||
life.push('beforeSave');
|
||||
d();
|
||||
};
|
||||
User.beforeCreate = function (d) {
|
||||
User.beforeCreate = function(d) {
|
||||
life.push('beforeCreate');
|
||||
d();
|
||||
};
|
||||
User.beforeUpdate = function (d) {
|
||||
User.beforeUpdate = function(d) {
|
||||
life.push('beforeUpdate');
|
||||
d();
|
||||
};
|
||||
User.beforeDestroy = function (d) {
|
||||
User.beforeDestroy = function(d) {
|
||||
life.push('beforeDestroy');
|
||||
d();
|
||||
};
|
||||
User.beforeValidate = function (d) {
|
||||
User.beforeValidate = function(d) {
|
||||
life.push('beforeValidate');
|
||||
d();
|
||||
};
|
||||
User.afterInitialize = function () {
|
||||
User.afterInitialize = function() {
|
||||
life.push('afterInitialize');
|
||||
};
|
||||
User.afterSave = function (d) {
|
||||
User.afterSave = function(d) {
|
||||
life.push('afterSave');
|
||||
d();
|
||||
};
|
||||
User.afterCreate = function (d) {
|
||||
User.afterCreate = function(d) {
|
||||
life.push('afterCreate');
|
||||
d();
|
||||
};
|
||||
User.afterUpdate = function (d) {
|
||||
User.afterUpdate = function(d) {
|
||||
life.push('afterUpdate');
|
||||
d();
|
||||
};
|
||||
User.afterDestroy = function (d) {
|
||||
User.afterDestroy = function(d) {
|
||||
life.push('afterDestroy');
|
||||
d();
|
||||
};
|
||||
User.afterValidate = function (d) {
|
||||
User.afterValidate = function(d) {
|
||||
life.push('afterValidate');
|
||||
d();
|
||||
};
|
||||
User.create(function (e, u) {
|
||||
User.create(function(e, u) {
|
||||
user = u;
|
||||
life = [];
|
||||
done();
|
||||
});
|
||||
});
|
||||
beforeEach(function () {
|
||||
beforeEach(function() {
|
||||
life = [];
|
||||
});
|
||||
|
||||
it('should describe create sequence', function (done) {
|
||||
User.create(function () {
|
||||
it('should describe create sequence', function(done) {
|
||||
User.create(function() {
|
||||
life.should.eql([
|
||||
'afterInitialize',
|
||||
'beforeValidate',
|
||||
|
@ -371,15 +370,15 @@ describe('hooks', function () {
|
|||
'beforeCreate',
|
||||
'beforeSave',
|
||||
'afterSave',
|
||||
'afterCreate'
|
||||
'afterCreate',
|
||||
]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should describe new+save sequence', function (done) {
|
||||
it('should describe new+save sequence', function(done) {
|
||||
var u = new User;
|
||||
u.save(function () {
|
||||
u.save(function() {
|
||||
life.should.eql([
|
||||
'afterInitialize',
|
||||
'beforeValidate',
|
||||
|
@ -387,14 +386,14 @@ describe('hooks', function () {
|
|||
'beforeCreate',
|
||||
'beforeSave',
|
||||
'afterSave',
|
||||
'afterCreate'
|
||||
'afterCreate',
|
||||
]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should describe updateAttributes sequence', function (done) {
|
||||
user.updateAttributes({name: 'Antony'}, function () {
|
||||
it('should describe updateAttributes sequence', function(done) {
|
||||
user.updateAttributes({name: 'Antony'}, function() {
|
||||
life.should.eql([
|
||||
'beforeValidate',
|
||||
'afterValidate',
|
||||
|
@ -407,43 +406,40 @@ describe('hooks', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should describe isValid sequence', function (done) {
|
||||
it('should describe isValid sequence', function(done) {
|
||||
should.not.exist(
|
||||
user.constructor._validations,
|
||||
'Expected user to have no validations, but she have');
|
||||
user.isValid(function (valid) {
|
||||
user.isValid(function(valid) {
|
||||
valid.should.be.true;
|
||||
life.should.eql([
|
||||
'beforeValidate',
|
||||
'afterValidate'
|
||||
'afterValidate',
|
||||
]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should describe destroy sequence', function (done) {
|
||||
user.destroy(function () {
|
||||
it('should describe destroy sequence', function(done) {
|
||||
user.destroy(function() {
|
||||
life.should.eql([
|
||||
'beforeDestroy',
|
||||
'afterDestroy'
|
||||
'afterDestroy',
|
||||
]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
function addHooks(name, done) {
|
||||
var called = false, random = String(Math.floor(Math.random() * 1000));
|
||||
User['before' + name] = function (next, data) {
|
||||
User['before' + name] = function(next, data) {
|
||||
called = true;
|
||||
data.email = random;
|
||||
next();
|
||||
};
|
||||
User['after' + name] = function (next) {
|
||||
User['after' + name] = function(next) {
|
||||
(new Boolean(called)).should.equal(true);
|
||||
this.should.have.property('email', random);
|
||||
done();
|
||||
|
@ -451,7 +447,7 @@ function addHooks(name, done) {
|
|||
}
|
||||
|
||||
function removeHooks(name) {
|
||||
return function () {
|
||||
return function() {
|
||||
User['after' + name] = null;
|
||||
User['before' + name] = null;
|
||||
};
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
// Copyright IBM Corp. 2013,2015. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
// This test written in mocha+should.js
|
||||
var should = require('./init.js');
|
||||
var async = require('async');
|
||||
|
@ -7,14 +13,13 @@ var DataSource = require('../').DataSource;
|
|||
|
||||
var db, User, Profile, AccessToken, Post, Passport, City, Street, Building, Assembly, Part;
|
||||
|
||||
describe('include', function () {
|
||||
|
||||
describe('include', function() {
|
||||
before(setup);
|
||||
|
||||
it('should fetch belongsTo relation', function (done) {
|
||||
Passport.find({include: 'owner'}, function (err, passports) {
|
||||
it('should fetch belongsTo relation', function(done) {
|
||||
Passport.find({include: 'owner'}, function(err, passports) {
|
||||
passports.length.should.be.ok;
|
||||
passports.forEach(function (p) {
|
||||
passports.forEach(function(p) {
|
||||
p.__cachedRelations.should.have.property('owner');
|
||||
|
||||
// The relation should be promoted as the 'owner' property
|
||||
|
@ -34,19 +39,19 @@ describe('include', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should fetch hasMany relation', function (done) {
|
||||
User.find({include: 'posts'}, function (err, users) {
|
||||
it('should fetch hasMany relation', function(done) {
|
||||
User.find({include: 'posts'}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
should.exist(users);
|
||||
users.length.should.be.ok;
|
||||
users.forEach(function (u) {
|
||||
users.forEach(function(u) {
|
||||
// The relation should be promoted as the 'owner' property
|
||||
u.should.have.property('posts');
|
||||
// The __cachedRelations should be removed from json output
|
||||
u.toJSON().should.not.have.property('__cachedRelations');
|
||||
|
||||
u.__cachedRelations.should.have.property('posts');
|
||||
u.__cachedRelations.posts.forEach(function (p) {
|
||||
u.__cachedRelations.posts.forEach(function(p) {
|
||||
p.userId.should.eql(u.id);
|
||||
});
|
||||
});
|
||||
|
@ -54,13 +59,12 @@ describe('include', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should fetch Passport - Owner - Posts', function (done) {
|
||||
Passport.find({include: {owner: 'posts'}}, function (err, passports) {
|
||||
|
||||
it('should fetch Passport - Owner - Posts', function(done) {
|
||||
Passport.find({include: {owner: 'posts'}}, function(err, passports) {
|
||||
should.not.exist(err);
|
||||
should.exist(passports);
|
||||
passports.length.should.be.ok;
|
||||
passports.forEach(function (p) {
|
||||
passports.forEach(function(p) {
|
||||
p.__cachedRelations.should.have.property('owner');
|
||||
|
||||
// The relation should be promoted as the 'owner' property
|
||||
|
@ -77,7 +81,7 @@ describe('include', function () {
|
|||
user.__cachedRelations.should.have.property('posts');
|
||||
user.should.have.property('posts');
|
||||
user.toJSON().should.have.property('posts').and.be.an.Array;
|
||||
user.__cachedRelations.posts.forEach(function (pp) {
|
||||
user.__cachedRelations.posts.forEach(function(pp) {
|
||||
pp.userId.should.eql(user.id);
|
||||
});
|
||||
}
|
||||
|
@ -86,8 +90,8 @@ describe('include', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should fetch Passport - Owner - empty Posts', function (done) {
|
||||
Passport.findOne({where: {number: '4'}, include: {owner: 'posts'}}, function (err, passport) {
|
||||
it('should fetch Passport - Owner - empty Posts', function(done) {
|
||||
Passport.findOne({where: {number: '4'}, include: {owner: 'posts'}}, function(err, passport) {
|
||||
should.not.exist(err);
|
||||
should.exist(passport);
|
||||
passport.__cachedRelations.should.have.property('owner');
|
||||
|
@ -102,13 +106,14 @@ describe('include', function () {
|
|||
user.id.should.eql(passport.ownerId);
|
||||
user.__cachedRelations.should.have.property('posts');
|
||||
user.should.have.property('posts');
|
||||
user.toJSON().should.have.property('posts').and.be.an.Array.with.lengthOf(0);
|
||||
user.toJSON().should.have.property('posts').and.be.an.Array().with
|
||||
.length(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fetch Passport - Owner - Posts - alternate syntax', function (done) {
|
||||
Passport.find({include: {owner: {relation: 'posts'}}}, function (err, passports) {
|
||||
it('should fetch Passport - Owner - Posts - alternate syntax', function(done) {
|
||||
Passport.find({include: {owner: {relation: 'posts'}}}, function(err, passports) {
|
||||
should.not.exist(err);
|
||||
should.exist(passports);
|
||||
passports.length.should.be.ok;
|
||||
|
@ -118,14 +123,14 @@ describe('include', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should fetch Passports - User - Posts - User', function (done) {
|
||||
it('should fetch Passports - User - Posts - User', function(done) {
|
||||
Passport.find({
|
||||
include: {owner: {posts: 'author'}}
|
||||
}, function (err, passports) {
|
||||
include: {owner: {posts: 'author'}},
|
||||
}, function(err, passports) {
|
||||
should.not.exist(err);
|
||||
should.exist(passports);
|
||||
passports.length.should.be.ok;
|
||||
passports.forEach(function (p) {
|
||||
passports.forEach(function(p) {
|
||||
p.__cachedRelations.should.have.property('owner');
|
||||
var user = p.__cachedRelations.owner;
|
||||
if (!p.ownerId) {
|
||||
|
@ -134,7 +139,7 @@ describe('include', function () {
|
|||
should.exist(user);
|
||||
user.id.should.eql(p.ownerId);
|
||||
user.__cachedRelations.should.have.property('posts');
|
||||
user.__cachedRelations.posts.forEach(function (pp) {
|
||||
user.__cachedRelations.posts.forEach(function(pp) {
|
||||
pp.should.have.property('id');
|
||||
pp.userId.should.eql(user.id);
|
||||
pp.should.have.property('author');
|
||||
|
@ -148,13 +153,13 @@ describe('include', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should fetch Passports with include scope on Posts', function (done) {
|
||||
it('should fetch Passports with include scope on Posts', function(done) {
|
||||
Passport.find({
|
||||
include: {owner: {relation: 'posts', scope:{
|
||||
include: {owner: {relation: 'posts', scope: {
|
||||
fields: ['title'], include: ['author'],
|
||||
order: 'title DESC'
|
||||
}}}
|
||||
}, function (err, passports) {
|
||||
order: 'title DESC',
|
||||
}}},
|
||||
}, function(err, passports) {
|
||||
should.not.exist(err);
|
||||
should.exist(passports);
|
||||
passports.length.should.equal(4);
|
||||
|
@ -190,11 +195,11 @@ describe('include', function () {
|
|||
relation: 'posts', scope: {
|
||||
fields: ['title'], include: ['author'],
|
||||
order: 'title DESC',
|
||||
limit: 2
|
||||
}
|
||||
}
|
||||
limit: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
limit: 1
|
||||
limit: 1,
|
||||
}, function(err, passports) {
|
||||
if (err) return done(err);
|
||||
passports.length.should.equal(1);
|
||||
|
@ -203,29 +208,32 @@ describe('include', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should fetch Users with include scope on Posts - belongsTo', function (done) {
|
||||
Post.find({
|
||||
include: { relation: 'author', scope:{ fields: ['name'] }}
|
||||
}, function (err, posts) {
|
||||
should.not.exist(err);
|
||||
should.exist(posts);
|
||||
posts.length.should.equal(5);
|
||||
it('should fetch Users with include scope on Posts - belongsTo', function(done) {
|
||||
Post.find({
|
||||
include: {relation: 'author', scope: {fields: ['name']}},
|
||||
}, function(err, posts) {
|
||||
should.not.exist(err);
|
||||
should.exist(posts);
|
||||
posts.length.should.equal(5);
|
||||
|
||||
var author = posts[0].author();
|
||||
author.name.should.equal('User A');
|
||||
author.should.have.property('id');
|
||||
author.should.have.property('age', undefined);
|
||||
var author = posts[0].author();
|
||||
author.name.should.equal('User A');
|
||||
author.should.have.property('id');
|
||||
author.should.have.property('age', undefined);
|
||||
|
||||
done();
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fetch Users with include scope on Posts - hasMany', function (done) {
|
||||
it('should fetch Users with include scope on Posts - hasMany', function(done) {
|
||||
User.find({
|
||||
include: {relation: 'posts', scope:{
|
||||
order: 'title DESC'
|
||||
}}
|
||||
}, function (err, users) {
|
||||
include: {
|
||||
relation: 'posts',
|
||||
scope: {
|
||||
order: 'title DESC',
|
||||
},
|
||||
},
|
||||
}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
should.exist(users);
|
||||
users.length.should.equal(5);
|
||||
|
@ -250,12 +258,15 @@ describe('include', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should fetch Users with include scope on Passports - hasMany', function (done) {
|
||||
it('should fetch Users with include scope on Passports - hasMany', function(done) {
|
||||
User.find({
|
||||
include: {relation: 'passports', scope:{
|
||||
where: { number: '2' }
|
||||
}}
|
||||
}, function (err, users) {
|
||||
include: {
|
||||
relation: 'passports',
|
||||
scope: {
|
||||
where: {number: '2'},
|
||||
},
|
||||
},
|
||||
}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
should.exist(users);
|
||||
users.length.should.equal(5);
|
||||
|
@ -271,12 +282,12 @@ describe('include', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should fetch User - Posts AND Passports', function (done) {
|
||||
User.find({include: ['posts', 'passports']}, function (err, users) {
|
||||
it('should fetch User - Posts AND Passports', function(done) {
|
||||
User.find({include: ['posts', 'passports']}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
should.exist(users);
|
||||
users.length.should.be.ok;
|
||||
users.forEach(function (user) {
|
||||
users.forEach(function(user) {
|
||||
// The relation should be promoted as the 'owner' property
|
||||
user.should.have.property('posts');
|
||||
user.should.have.property('passports');
|
||||
|
@ -292,10 +303,10 @@ describe('include', function () {
|
|||
|
||||
user.__cachedRelations.should.have.property('posts');
|
||||
user.__cachedRelations.should.have.property('passports');
|
||||
user.__cachedRelations.posts.forEach(function (p) {
|
||||
user.__cachedRelations.posts.forEach(function(p) {
|
||||
p.userId.should.eql(user.id);
|
||||
});
|
||||
user.__cachedRelations.passports.forEach(function (pp) {
|
||||
user.__cachedRelations.passports.forEach(function(pp) {
|
||||
pp.ownerId.should.eql(user.id);
|
||||
});
|
||||
});
|
||||
|
@ -307,9 +318,9 @@ describe('include', function () {
|
|||
function(done) {
|
||||
User.find({include: [
|
||||
{relation: 'posts', scope: {
|
||||
where: {title: 'Post A'}
|
||||
where: {title: 'Post A'},
|
||||
}},
|
||||
'passports'
|
||||
'passports',
|
||||
]}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
should.exist(users);
|
||||
|
@ -342,12 +353,12 @@ describe('include', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should not fetch User - AccessTokens', function (done) {
|
||||
User.find({include: ['accesstokens']}, function (err, users) {
|
||||
it('should not fetch User - AccessTokens', function(done) {
|
||||
User.find({include: ['accesstokens']}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
should.exist(users);
|
||||
users.length.should.be.ok;
|
||||
users.forEach(function (user) {
|
||||
users.forEach(function(user) {
|
||||
var userObj = user.toJSON();
|
||||
userObj.should.not.have.property('accesstokens');
|
||||
});
|
||||
|
@ -355,25 +366,23 @@ describe('include', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should support hasAndBelongsToMany', function (done) {
|
||||
Assembly.create({name: 'car'}, function (err, assembly) {
|
||||
Part.create({partNumber: 'engine'}, function (err, part) {
|
||||
assembly.parts.add(part, function (err, data) {
|
||||
assembly.parts(function (err, parts) {
|
||||
it('should support hasAndBelongsToMany', function(done) {
|
||||
Assembly.create({name: 'car'}, function(err, assembly) {
|
||||
Part.create({partNumber: 'engine'}, function(err, part) {
|
||||
assembly.parts.add(part, function(err, data) {
|
||||
assembly.parts(function(err, parts) {
|
||||
should.not.exist(err);
|
||||
should.exists(parts);
|
||||
parts.length.should.equal(1);
|
||||
parts[0].partNumber.should.equal('engine');
|
||||
|
||||
// Create a part
|
||||
assembly.parts.create({partNumber: 'door'}, function (err, part4) {
|
||||
|
||||
Assembly.find({include: 'parts'}, function (err, assemblies) {
|
||||
assembly.parts.create({partNumber: 'door'}, function(err, part4) {
|
||||
Assembly.find({include: 'parts'}, function(err, assemblies) {
|
||||
assemblies.length.should.equal(1);
|
||||
assemblies[0].parts().length.should.equal(2);
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -381,13 +390,13 @@ describe('include', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should fetch User - Profile (HasOne)', function (done) {
|
||||
User.find({include: ['profile']}, function (err, users) {
|
||||
it('should fetch User - Profile (HasOne)', function(done) {
|
||||
User.find({include: ['profile']}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
should.exist(users);
|
||||
users.length.should.be.ok;
|
||||
var usersWithProfile = 0;
|
||||
users.forEach(function (user) {
|
||||
users.forEach(function(user) {
|
||||
// The relation should be promoted as the 'owner' property
|
||||
user.should.have.property('profile');
|
||||
var userObj = user.toJSON();
|
||||
|
@ -395,8 +404,7 @@ describe('include', function () {
|
|||
if (profile) {
|
||||
profile.should.be.an.instanceOf(Profile);
|
||||
usersWithProfile++;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
(profile === null).should.be.true;
|
||||
}
|
||||
// The __cachedRelations should be removed from json output
|
||||
|
@ -412,13 +420,12 @@ describe('include', function () {
|
|||
});
|
||||
});
|
||||
|
||||
|
||||
// Not implemented correctly, see: loopback-datasource-juggler/issues/166
|
||||
// fixed by DB optimization
|
||||
it('should support include scope on hasAndBelongsToMany', function (done) {
|
||||
Assembly.find({include: { relation: 'parts', scope: {
|
||||
where: { partNumber: 'engine' }
|
||||
}}}, function (err, assemblies) {
|
||||
it('should support include scope on hasAndBelongsToMany', function(done) {
|
||||
Assembly.find({include: {relation: 'parts', scope: {
|
||||
where: {partNumber: 'engine'},
|
||||
}}}, function(err, assemblies) {
|
||||
assemblies.length.should.equal(1);
|
||||
var parts = assemblies[0].parts();
|
||||
parts.should.have.length(1);
|
||||
|
@ -427,7 +434,29 @@ describe('include', function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe('performance', function () {
|
||||
it('should save related items separately', function(done) {
|
||||
User.find({
|
||||
include: 'posts',
|
||||
})
|
||||
.then(function(users) {
|
||||
var posts = users[0].posts();
|
||||
posts.should.have.length(3);
|
||||
return users[0].save();
|
||||
})
|
||||
.then(function(updatedUser) {
|
||||
return User.findById(updatedUser.id, {
|
||||
include: 'posts',
|
||||
});
|
||||
})
|
||||
.then(function(user) {
|
||||
var posts = user.posts();
|
||||
posts.should.have.length(3);
|
||||
})
|
||||
.then(done)
|
||||
.catch(done);
|
||||
});
|
||||
|
||||
describe('performance', function() {
|
||||
var all;
|
||||
beforeEach(function() {
|
||||
this.called = 0;
|
||||
|
@ -441,11 +470,11 @@ describe('include', function () {
|
|||
afterEach(function() {
|
||||
db.connector.all = all;
|
||||
});
|
||||
it('including belongsTo should make only 2 db calls', function (done) {
|
||||
it('including belongsTo should make only 2 db calls', function(done) {
|
||||
var self = this;
|
||||
Passport.find({include: 'owner'}, function (err, passports) {
|
||||
Passport.find({include: 'owner'}, function(err, passports) {
|
||||
passports.length.should.be.ok;
|
||||
passports.forEach(function (p) {
|
||||
passports.forEach(function(p) {
|
||||
p.__cachedRelations.should.have.property('owner');
|
||||
// The relation should be promoted as the 'owner' property
|
||||
p.should.have.property('owner');
|
||||
|
@ -464,16 +493,16 @@ describe('include', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('including hasManyThrough should make only 3 db calls', function (done) {
|
||||
it('including hasManyThrough should make only 3 db calls', function(done) {
|
||||
var self = this;
|
||||
Assembly.create([{name: 'sedan'}, {name: 'hatchback'},
|
||||
{name: 'SUV'}],
|
||||
function (err, assemblies) {
|
||||
function(err, assemblies) {
|
||||
Part.create([{partNumber: 'engine'}, {partNumber: 'bootspace'},
|
||||
{partNumber: 'silencer'}],
|
||||
function (err, parts) {
|
||||
async.each(parts, function (part, next) {
|
||||
async.each(assemblies, function (assembly, next) {
|
||||
function(err, parts) {
|
||||
async.each(parts, function(part, next) {
|
||||
async.each(assemblies, function(assembly, next) {
|
||||
if (assembly.name === 'SUV') {
|
||||
return next();
|
||||
}
|
||||
|
@ -481,20 +510,20 @@ describe('include', function () {
|
|||
part.partNumber === 'bootspace') {
|
||||
return next();
|
||||
}
|
||||
assembly.parts.add(part, function (err, data) {
|
||||
assembly.parts.add(part, function(err, data) {
|
||||
next();
|
||||
});
|
||||
}, next);
|
||||
}, function (err) {
|
||||
}, function(err) {
|
||||
self.called = 0;
|
||||
Assembly.find({
|
||||
where: {
|
||||
name: {
|
||||
inq: ['sedan', 'hatchback', 'SUV']
|
||||
}
|
||||
inq: ['sedan', 'hatchback', 'SUV'],
|
||||
},
|
||||
},
|
||||
include: 'parts'
|
||||
}, function (err, result) {
|
||||
include: 'parts',
|
||||
}, function(err, result) {
|
||||
should.not.exist(err);
|
||||
should.exists(result);
|
||||
result.length.should.equal(3);
|
||||
|
@ -517,13 +546,13 @@ describe('include', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('including hasMany should make only 2 db calls', function (done) {
|
||||
it('including hasMany should make only 2 db calls', function(done) {
|
||||
var self = this;
|
||||
User.find({include: ['posts', 'passports']}, function (err, users) {
|
||||
User.find({include: ['posts', 'passports']}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
should.exist(users);
|
||||
users.length.should.be.ok;
|
||||
users.forEach(function (user) {
|
||||
users.forEach(function(user) {
|
||||
// The relation should be promoted as the 'owner' property
|
||||
user.should.have.property('posts');
|
||||
user.should.have.property('passports');
|
||||
|
@ -539,10 +568,10 @@ describe('include', function () {
|
|||
|
||||
user.__cachedRelations.should.have.property('posts');
|
||||
user.__cachedRelations.should.have.property('passports');
|
||||
user.__cachedRelations.posts.forEach(function (p) {
|
||||
user.__cachedRelations.posts.forEach(function(p) {
|
||||
p.userId.should.eql(user.id);
|
||||
});
|
||||
user.__cachedRelations.passports.forEach(function (pp) {
|
||||
user.__cachedRelations.passports.forEach(function(pp) {
|
||||
pp.ownerId.should.eql(user.id);
|
||||
});
|
||||
});
|
||||
|
@ -551,17 +580,16 @@ describe('include', function () {
|
|||
});
|
||||
});
|
||||
|
||||
|
||||
it('should not make n+1 db calls in relation syntax',
|
||||
function (done) {
|
||||
function(done) {
|
||||
var self = this;
|
||||
User.find({include: [{ relation: 'posts', scope: {
|
||||
where: {title: 'Post A'}
|
||||
}}, 'passports']}, function (err, users) {
|
||||
User.find({include: [{relation: 'posts', scope: {
|
||||
where: {title: 'Post A'},
|
||||
}}, 'passports']}, function(err, users) {
|
||||
should.not.exist(err);
|
||||
should.exist(users);
|
||||
users.length.should.be.ok;
|
||||
users.forEach(function (user) {
|
||||
users.forEach(function(user) {
|
||||
// The relation should be promoted as the 'owner' property
|
||||
user.should.have.property('posts');
|
||||
user.should.have.property('passports');
|
||||
|
@ -577,11 +605,11 @@ describe('include', function () {
|
|||
|
||||
user.__cachedRelations.should.have.property('posts');
|
||||
user.__cachedRelations.should.have.property('passports');
|
||||
user.__cachedRelations.posts.forEach(function (p) {
|
||||
user.__cachedRelations.posts.forEach(function(p) {
|
||||
p.userId.should.eql(user.id);
|
||||
p.title.should.be.equal('Post A');
|
||||
});
|
||||
user.__cachedRelations.passports.forEach(function (pp) {
|
||||
user.__cachedRelations.passports.forEach(function(pp) {
|
||||
pp.ownerId.should.eql(user.id);
|
||||
});
|
||||
});
|
||||
|
@ -590,6 +618,29 @@ describe('include', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should support disableInclude for hasAndBelongsToMany', function() {
|
||||
var Patient = db.define('Patient', {name: String});
|
||||
var Doctor = db.define('Doctor', {name: String});
|
||||
var DoctorPatient = db.define('DoctorPatient');
|
||||
Doctor.hasAndBelongsToMany('patients', {
|
||||
model: 'Patient',
|
||||
options: {disableInclude: true},
|
||||
});
|
||||
|
||||
var doctor;
|
||||
return db.automigrate(['Patient', 'Doctor', 'DoctorPatient']).then(function() {
|
||||
return Doctor.create({name: 'Who'});
|
||||
}).then(function(inst) {
|
||||
doctor = inst;
|
||||
return doctor.patients.create({name: 'Lazarus'});
|
||||
}).then(function() {
|
||||
return Doctor.find({include: ['patients']});
|
||||
}).then(function(list) {
|
||||
list.should.have.length(1);
|
||||
list[0].toJSON().should.not.have.property('patients');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function setup(done) {
|
||||
|
@ -599,19 +650,19 @@ function setup(done) {
|
|||
Building = db.define('Building');
|
||||
User = db.define('User', {
|
||||
name: String,
|
||||
age: Number
|
||||
age: Number,
|
||||
});
|
||||
Profile = db.define('Profile', {
|
||||
profileName: String
|
||||
profileName: String,
|
||||
});
|
||||
AccessToken = db.define('AccessToken', {
|
||||
token: String
|
||||
token: String,
|
||||
});
|
||||
Passport = db.define('Passport', {
|
||||
number: String
|
||||
number: String,
|
||||
});
|
||||
Post = db.define('Post', {
|
||||
title: String
|
||||
title: String,
|
||||
});
|
||||
|
||||
Passport.belongsTo('owner', {model: User});
|
||||
|
@ -619,24 +670,24 @@ function setup(done) {
|
|||
User.hasMany('posts', {foreignKey: 'userId'});
|
||||
User.hasMany('accesstokens', {
|
||||
foreignKey: 'userId',
|
||||
options: {disableInclude: true}
|
||||
options: {disableInclude: true},
|
||||
});
|
||||
Profile.belongsTo('user', {model: User});
|
||||
User.hasOne('profile', {foreignKey: 'userId'});
|
||||
Post.belongsTo('author', {model: User, foreignKey: 'userId'});
|
||||
|
||||
Assembly = db.define('Assembly', {
|
||||
name: String
|
||||
name: String,
|
||||
});
|
||||
|
||||
Part = db.define('Part', {
|
||||
partNumber: String
|
||||
partNumber: String,
|
||||
});
|
||||
|
||||
Assembly.hasAndBelongsToMany(Part);
|
||||
Part.hasAndBelongsToMany(Assembly);
|
||||
|
||||
db.automigrate(function () {
|
||||
db.automigrate(function() {
|
||||
var createdUsers = [];
|
||||
var createdPassports = [];
|
||||
var createdProfiles = [];
|
||||
|
@ -650,9 +701,9 @@ function setup(done) {
|
|||
{name: 'User B', age: 22},
|
||||
{name: 'User C', age: 23},
|
||||
{name: 'User D', age: 24},
|
||||
{name: 'User E', age: 25}
|
||||
{name: 'User E', age: 25},
|
||||
],
|
||||
function (items) {
|
||||
function(items) {
|
||||
createdUsers = items;
|
||||
createPassports();
|
||||
createAccessTokens();
|
||||
|
@ -665,9 +716,9 @@ function setup(done) {
|
|||
AccessToken,
|
||||
[
|
||||
{token: '1', userId: createdUsers[0].id},
|
||||
{token: '2', userId: createdUsers[1].id}
|
||||
{token: '2', userId: createdUsers[1].id},
|
||||
],
|
||||
function (items) {}
|
||||
function(items) {}
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -680,7 +731,7 @@ function setup(done) {
|
|||
{number: '3'},
|
||||
{number: '4', ownerId: createdUsers[2].id},
|
||||
],
|
||||
function (items) {
|
||||
function(items) {
|
||||
createdPassports = items;
|
||||
createPosts();
|
||||
}
|
||||
|
@ -693,10 +744,10 @@ function setup(done) {
|
|||
[
|
||||
{profileName: 'Profile A', userId: createdUsers[0].id},
|
||||
{profileName: 'Profile B', userId: createdUsers[1].id},
|
||||
{profileName: 'Profile Z'}
|
||||
{profileName: 'Profile Z'},
|
||||
],
|
||||
function (items) {
|
||||
createdProfiles = items
|
||||
function(items) {
|
||||
createdProfiles = items;
|
||||
done();
|
||||
}
|
||||
);
|
||||
|
@ -710,21 +761,20 @@ function setup(done) {
|
|||
{title: 'Post B', userId: createdUsers[0].id},
|
||||
{title: 'Post C', userId: createdUsers[0].id},
|
||||
{title: 'Post D', userId: createdUsers[1].id},
|
||||
{title: 'Post E'}
|
||||
{title: 'Post E'},
|
||||
],
|
||||
function (items) {
|
||||
function(items) {
|
||||
createdPosts = items;
|
||||
createProfiles();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function clearAndCreate(model, data, callback) {
|
||||
var createdItems = [];
|
||||
model.destroyAll(function () {
|
||||
model.destroyAll(function() {
|
||||
nextItem(null, null);
|
||||
});
|
||||
|
||||
|
@ -750,35 +800,35 @@ describe('Model instance with included relation .toJSON()', function() {
|
|||
db = new DataSource({connector: 'memory'});
|
||||
ChallengerModel = db.createModel('Challenger',
|
||||
{
|
||||
name: String
|
||||
name: String,
|
||||
},
|
||||
{
|
||||
relations: {
|
||||
gameParticipations: {
|
||||
type: 'hasMany',
|
||||
model: 'GameParticipation',
|
||||
foreignKey: ''
|
||||
}
|
||||
}
|
||||
foreignKey: '',
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
GameParticipationModel = db.createModel('GameParticipation',
|
||||
{
|
||||
date: Date
|
||||
date: Date,
|
||||
},
|
||||
{
|
||||
relations: {
|
||||
challenger: {
|
||||
type: 'belongsTo',
|
||||
model: 'Challenger',
|
||||
foreignKey: ''
|
||||
foreignKey: '',
|
||||
},
|
||||
results: {
|
||||
type: 'hasMany',
|
||||
model: 'Result',
|
||||
foreignKey: ''
|
||||
}
|
||||
}
|
||||
foreignKey: '',
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
ResultModel = db.createModel('Result', {
|
||||
|
@ -788,9 +838,9 @@ describe('Model instance with included relation .toJSON()', function() {
|
|||
gameParticipation: {
|
||||
type: 'belongsTo',
|
||||
model: 'GameParticipation',
|
||||
foreignKey: ''
|
||||
}
|
||||
}
|
||||
foreignKey: '',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
async.waterfall([
|
||||
|
@ -800,7 +850,6 @@ describe('Model instance with included relation .toJSON()', function() {
|
|||
function(err) {
|
||||
done(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function createChallengers(callback) {
|
||||
|
@ -810,21 +859,20 @@ describe('Model instance with included relation .toJSON()', function() {
|
|||
function createGameParticipations(challengers, callback) {
|
||||
GameParticipationModel.create([
|
||||
{challengerId: challengers[0].id, date: Date.now()},
|
||||
{challengerId: challengers[0].id, date: Date.now()}
|
||||
{challengerId: challengers[0].id, date: Date.now()},
|
||||
], callback);
|
||||
}
|
||||
|
||||
function createResults(gameParticipations, callback) {
|
||||
ResultModel.create([
|
||||
{gameParticipationId: gameParticipations[0].id, points: 10},
|
||||
{gameParticipationId: gameParticipations[0].id, points: 20}
|
||||
{gameParticipationId: gameParticipations[0].id, points: 20},
|
||||
], callback);
|
||||
}
|
||||
|
||||
it('should recursively serialize objects', function(done) {
|
||||
var filter = {include: {gameParticipations: 'results'}};
|
||||
ChallengerModel.find(filter, function(err, challengers) {
|
||||
|
||||
var levelOneInclusion = challengers[0].toJSON().gameParticipations[0];
|
||||
assert(levelOneInclusion.__data === undefined, '.__data of a level 1 inclusion is undefined.');
|
||||
|
||||
|
|
|
@ -1,41 +1,49 @@
|
|||
var assert = require("assert");
|
||||
var should = require("should");
|
||||
// Copyright IBM Corp. 2015,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var includeUtils = require("../lib/include_utils");
|
||||
/* eslint-disable camelcase */
|
||||
|
||||
describe('include_util', function(){
|
||||
describe('#buildOneToOneIdentityMapWithOrigKeys', function(){
|
||||
it('should return an object with keys', function(){
|
||||
var assert = require('assert');
|
||||
var should = require('should');
|
||||
|
||||
var includeUtils = require('../lib/include_utils');
|
||||
|
||||
describe('include_util', function() {
|
||||
describe('#buildOneToOneIdentityMapWithOrigKeys', function() {
|
||||
it('should return an object with keys', function() {
|
||||
var objs = [
|
||||
{id: 11, letter: "A"},
|
||||
{id: 22, letter: "B"}
|
||||
{id: 11, letter: 'A'},
|
||||
{id: 22, letter: 'B'},
|
||||
];
|
||||
var result = includeUtils.buildOneToOneIdentityMapWithOrigKeys(objs, "id");
|
||||
var result = includeUtils.buildOneToOneIdentityMapWithOrigKeys(objs, 'id');
|
||||
result.get(11).should.be.ok;
|
||||
result.get(22).should.be.ok;
|
||||
});
|
||||
|
||||
it('should overwrite keys in case of collision', function(){
|
||||
var objs = [
|
||||
{id: 11, letter: "A"},
|
||||
{id: 22, letter: "B"},
|
||||
{id: 33, letter: "C"},
|
||||
{id: 11, letter: "HA!"}
|
||||
];
|
||||
it('should overwrite keys in case of collision', function() {
|
||||
var objs = [
|
||||
{id: 11, letter: 'A'},
|
||||
{id: 22, letter: 'B'},
|
||||
{id: 33, letter: 'C'},
|
||||
{id: 11, letter: 'HA!'},
|
||||
];
|
||||
|
||||
var result = includeUtils.buildOneToOneIdentityMapWithOrigKeys(objs, "id");
|
||||
result.getKeys().should.containEql(11);
|
||||
result.getKeys().should.containEql(22);
|
||||
result.getKeys().should.containEql(33);
|
||||
result.get(11)["letter"].should.equal("HA!");
|
||||
result.get(33)["letter"].should.equal("C");
|
||||
var result = includeUtils.buildOneToOneIdentityMapWithOrigKeys(objs, 'id');
|
||||
result.getKeys().should.containEql(11);
|
||||
result.getKeys().should.containEql(22);
|
||||
result.getKeys().should.containEql(33);
|
||||
result.get(11)['letter'].should.equal('HA!');
|
||||
result.get(33)['letter'].should.equal('C');
|
||||
});
|
||||
});
|
||||
describe('#buildOneToOneIdentityMapWithOrigKeys', function(){
|
||||
it('should return an object with keys', function(){
|
||||
describe('#buildOneToOneIdentityMapWithOrigKeys', function() {
|
||||
it('should return an object with keys', function() {
|
||||
var objs = [
|
||||
{id: 11, letter: "A"},
|
||||
{id: 22, letter: "B"}
|
||||
{id: 11, letter: 'A'},
|
||||
{id: 22, letter: 'B'},
|
||||
];
|
||||
var result = includeUtils.buildOneToOneIdentityMapWithOrigKeys(objs, 'id');
|
||||
result.get(11).should.be.ok;
|
||||
|
@ -43,36 +51,35 @@ describe('include_util', function(){
|
|||
result.getKeys().should.have.lengthOf(2); // no additional properties
|
||||
});
|
||||
});
|
||||
describe('#buildOneToManyIdentityMap', function(){
|
||||
it('should return an object with keys', function(){
|
||||
var objs = [
|
||||
{id: 11, letter: "A"},
|
||||
{id: 22, letter: "B"}
|
||||
];
|
||||
var result = includeUtils.buildOneToManyIdentityMapWithOrigKeys(objs, "id");
|
||||
result.exist(11).should.be.true;
|
||||
result.exist(22).should.be.true;
|
||||
});
|
||||
|
||||
it('should collect keys in case of collision', function(){
|
||||
var objs = [
|
||||
{fk_id: 11, letter: "A"},
|
||||
{fk_id: 22, letter: "B"},
|
||||
{fk_id: 33, letter: "C"},
|
||||
{fk_id: 11, letter: "HA!"}
|
||||
];
|
||||
|
||||
var result = includeUtils.buildOneToManyIdentityMapWithOrigKeys(objs, "fk_id");
|
||||
result.get(11)[0]["letter"].should.equal("A");
|
||||
result.get(11)[1]["letter"].should.equal("HA!");
|
||||
result.get(33)[0]["letter"].should.equal("C");
|
||||
});
|
||||
describe('#buildOneToManyIdentityMap', function() {
|
||||
it('should return an object with keys', function() {
|
||||
var objs = [
|
||||
{id: 11, letter: 'A'},
|
||||
{id: 22, letter: 'B'},
|
||||
];
|
||||
var result = includeUtils.buildOneToManyIdentityMapWithOrigKeys(objs, 'id');
|
||||
result.exist(11).should.be.true;
|
||||
result.exist(22).should.be.true;
|
||||
});
|
||||
|
||||
it('should collect keys in case of collision', function() {
|
||||
var objs = [
|
||||
{fk_id: 11, letter: 'A'},
|
||||
{fk_id: 22, letter: 'B'},
|
||||
{fk_id: 33, letter: 'C'},
|
||||
{fk_id: 11, letter: 'HA!'},
|
||||
];
|
||||
|
||||
var result = includeUtils.buildOneToManyIdentityMapWithOrigKeys(objs, 'fk_id');
|
||||
result.get(11)[0]['letter'].should.equal('A');
|
||||
result.get(11)[1]['letter'].should.equal('HA!');
|
||||
result.get(33)[0]['letter'].should.equal('C');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('KVMap', function(){
|
||||
it('should allow to set and get value with key string', function(){
|
||||
describe('KVMap', function() {
|
||||
it('should allow to set and get value with key string', function() {
|
||||
var map = new includeUtils.KVMap();
|
||||
map.set('name', 'Alex');
|
||||
map.set('gender', true);
|
||||
|
@ -81,7 +88,7 @@ describe('KVMap', function(){
|
|||
map.get('gender').should.be.equal(true);
|
||||
map.get('age').should.be.equal(25);
|
||||
});
|
||||
it('should allow to set and get value with arbitrary key type', function(){
|
||||
it('should allow to set and get value with arbitrary key type', function() {
|
||||
var map = new includeUtils.KVMap();
|
||||
map.set('name', 'Alex');
|
||||
map.set(true, 'male');
|
||||
|
@ -92,12 +99,12 @@ describe('KVMap', function(){
|
|||
map.get(false).should.be.equal(false);
|
||||
map.get({isTrue: 'yes'}).should.be.equal(25);
|
||||
});
|
||||
it('should not allow to get values with [] operator', function(){
|
||||
it('should not allow to get values with [] operator', function() {
|
||||
var map = new includeUtils.KVMap();
|
||||
map.set('name', 'Alex');
|
||||
(map['name'] === undefined).should.be.equal(true);
|
||||
});
|
||||
it('should provide .exist() method for checking if key presented', function(){
|
||||
it('should provide .exist() method for checking if key presented', function() {
|
||||
var map = new includeUtils.KVMap();
|
||||
map.set('one', 1);
|
||||
map.set(2, 'two');
|
||||
|
@ -107,7 +114,7 @@ describe('KVMap', function(){
|
|||
map.exist(true).should.be.true;
|
||||
map.exist('two').should.be.false;
|
||||
});
|
||||
it('should return array of original keys with .getKeys()', function(){
|
||||
it('should return array of original keys with .getKeys()', function() {
|
||||
var map = new includeUtils.KVMap();
|
||||
map.set('one', 1);
|
||||
map.set(2, 'two');
|
||||
|
@ -117,7 +124,7 @@ describe('KVMap', function(){
|
|||
keys.should.containEql(2);
|
||||
keys.should.containEql(true);
|
||||
});
|
||||
it('should allow to store and fetch arrays', function(){
|
||||
it('should allow to store and fetch arrays', function() {
|
||||
var map = new includeUtils.KVMap();
|
||||
map.set(1, [1, 2, 3]);
|
||||
map.set(2, [2, 3, 4]);
|
||||
|
|
14
test/init.js
14
test/init.js
|
@ -1,3 +1,9 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
module.exports = require('should');
|
||||
|
||||
/*
|
||||
|
@ -16,13 +22,13 @@ var ModelBuilder = require('../').ModelBuilder;
|
|||
var Schema = require('../').Schema;
|
||||
|
||||
if (!('getSchema' in global)) {
|
||||
global.getSchema = function (connector, settings) {
|
||||
global.getSchema = function(connector, settings) {
|
||||
return new Schema(connector || 'memory', settings);
|
||||
};
|
||||
}
|
||||
|
||||
if (!('getModelBuilder' in global)) {
|
||||
global.getModelBuilder = function () {
|
||||
global.getModelBuilder = function() {
|
||||
return new ModelBuilder();
|
||||
};
|
||||
}
|
||||
|
@ -30,3 +36,7 @@ if (!('getModelBuilder' in global)) {
|
|||
if (!('Promise' in global)) {
|
||||
global.Promise = require('bluebird');
|
||||
}
|
||||
|
||||
if (!('connectorCapabilities' in global)) {
|
||||
global.connectorCapabilities = {};
|
||||
}
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
var assert = require('assert');
|
||||
var ModelBuilder = require('..').ModelBuilder;
|
||||
var DataSource = require('../').DataSource;
|
||||
|
@ -14,19 +20,18 @@ var json = {
|
|||
city: 'San Jose',
|
||||
state: 'CA',
|
||||
zipcode: '95131',
|
||||
country: 'US'
|
||||
country: 'US',
|
||||
},
|
||||
friends: ['John', 'Mary'],
|
||||
emails: [
|
||||
{label: 'work', id: 'x@sample.com'},
|
||||
{label: 'home', id: 'x@home.com'}
|
||||
{label: 'home', id: 'x@home.com'},
|
||||
],
|
||||
tags: []
|
||||
tags: [],
|
||||
};
|
||||
|
||||
describe('Introspection of model definitions from JSON', function () {
|
||||
|
||||
it('should handle simple types', function () {
|
||||
describe('Introspection of model definitions from JSON', function() {
|
||||
it('should handle simple types', function() {
|
||||
assert.equal(introspectType('123'), 'string');
|
||||
assert.equal(introspectType(true), 'boolean');
|
||||
assert.equal(introspectType(false), 'boolean');
|
||||
|
@ -34,7 +39,7 @@ describe('Introspection of model definitions from JSON', function () {
|
|||
assert.equal(introspectType(new Date()), 'date');
|
||||
});
|
||||
|
||||
it('should handle array types', function () {
|
||||
it('should handle array types', function() {
|
||||
var type = introspectType(['123']);
|
||||
assert.deepEqual(type, ['string'], 'type should be ["string"]');
|
||||
type = introspectType([1]);
|
||||
|
@ -49,12 +54,12 @@ describe('Introspection of model definitions from JSON', function () {
|
|||
assert.equal(type, 'array');
|
||||
});
|
||||
|
||||
it('should return Any for null or undefined', function () {
|
||||
it('should return Any for null or undefined', function() {
|
||||
assert.equal(introspectType(null), ModelBuilder.Any);
|
||||
assert.equal(introspectType(undefined), ModelBuilder.Any);
|
||||
});
|
||||
|
||||
it('should return a schema for object', function () {
|
||||
it('should return a schema for object', function() {
|
||||
var json = {a: 'str', b: 0, c: true};
|
||||
var type = introspectType(json);
|
||||
assert.equal(type.a, 'string');
|
||||
|
@ -62,7 +67,7 @@ describe('Introspection of model definitions from JSON', function () {
|
|||
assert.equal(type.c, 'boolean');
|
||||
});
|
||||
|
||||
it('should handle nesting objects', function () {
|
||||
it('should handle nesting objects', function() {
|
||||
var json = {a: 'str', b: 0, c: true, d: {x: 10, y: 5}};
|
||||
var type = introspectType(json);
|
||||
assert.equal(type.a, 'string');
|
||||
|
@ -72,7 +77,7 @@ describe('Introspection of model definitions from JSON', function () {
|
|||
assert.equal(type.d.y, 'number');
|
||||
});
|
||||
|
||||
it('should handle nesting arrays', function () {
|
||||
it('should handle nesting arrays', function() {
|
||||
var json = {a: 'str', b: 0, c: true, d: [1, 2]};
|
||||
var type = introspectType(json);
|
||||
assert.equal(type.a, 'string');
|
||||
|
@ -81,7 +86,7 @@ describe('Introspection of model definitions from JSON', function () {
|
|||
assert.deepEqual(type.d, ['number']);
|
||||
});
|
||||
|
||||
it('should build a model from the introspected schema', function (done) {
|
||||
it('should build a model from the introspected schema', function(done) {
|
||||
var copy = traverse(json).clone();
|
||||
|
||||
var schema = introspectType(json);
|
||||
|
@ -98,7 +103,7 @@ describe('Introspection of model definitions from JSON', function () {
|
|||
done();
|
||||
});
|
||||
|
||||
it('should build a model using buildModelFromInstance', function (done) {
|
||||
it('should build a model using buildModelFromInstance', function(done) {
|
||||
var copy = traverse(json).clone();
|
||||
|
||||
var builder = new ModelBuilder();
|
||||
|
@ -110,7 +115,7 @@ describe('Introspection of model definitions from JSON', function () {
|
|||
done();
|
||||
});
|
||||
|
||||
it('should build a model using DataSource.buildModelFromInstance', function (done) {
|
||||
it('should build a model using DataSource.buildModelFromInstance', function(done) {
|
||||
var copy = traverse(json).clone();
|
||||
|
||||
var builder = new DataSource('memory');
|
||||
|
@ -124,6 +129,5 @@ describe('Introspection of model definitions from JSON', function () {
|
|||
assert.deepEqual(obj, copy);
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
|
|
@ -1,13 +1,19 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
// This test written in mocha+should.js
|
||||
var should = require('./init.js');
|
||||
|
||||
var Schema = require('../').Schema;
|
||||
var ModelBuilder = require('../').ModelBuilder;
|
||||
|
||||
describe('JSON property', function () {
|
||||
describe('JSON property', function() {
|
||||
var dataSource, Model;
|
||||
|
||||
it('should be defined', function () {
|
||||
it('should be defined', function() {
|
||||
dataSource = getSchema();
|
||||
Model = dataSource.define('Model', {propertyName: ModelBuilder.JSON});
|
||||
var m = new Model;
|
||||
|
@ -15,22 +21,22 @@ describe('JSON property', function () {
|
|||
should.not.exist(m.propertyName);
|
||||
});
|
||||
|
||||
it('should accept JSON in constructor and return object', function () {
|
||||
it('should accept JSON in constructor and return object', function() {
|
||||
var m = new Model({
|
||||
propertyName: '{"foo": "bar"}'
|
||||
propertyName: '{"foo": "bar"}',
|
||||
});
|
||||
m.propertyName.should.be.an.Object;
|
||||
m.propertyName.foo.should.equal('bar');
|
||||
});
|
||||
|
||||
it('should accept object in setter and return object', function () {
|
||||
it('should accept object in setter and return object', function() {
|
||||
var m = new Model;
|
||||
m.propertyName = {"foo": "bar"};
|
||||
m.propertyName = {'foo': 'bar'};
|
||||
m.propertyName.should.be.an.Object;
|
||||
m.propertyName.foo.should.equal('bar');
|
||||
});
|
||||
|
||||
it('should accept string in setter and return string', function () {
|
||||
it('should accept string in setter and return string', function() {
|
||||
var m = new Model;
|
||||
m.propertyName = '{"foo": "bar"}';
|
||||
m.propertyName.should.be.a.String;
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
'use strict';
|
||||
|
||||
var kvMemory = require('../lib/connectors/kv-memory');
|
||||
var DataSource = require('..').DataSource;
|
||||
|
||||
describe('KeyValue-Memory connector', function() {
|
||||
var dataSourceFactory = function() {
|
||||
return new DataSource({connector: kvMemory});
|
||||
};
|
||||
|
||||
require('./kvao.suite')(dataSourceFactory);
|
||||
});
|
|
@ -0,0 +1,33 @@
|
|||
'use strict';
|
||||
|
||||
var debug = require('debug')('test');
|
||||
var extend = require('util')._extend;
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
if (!global.Promise)
|
||||
global.Promise = require('bluebird');
|
||||
|
||||
module.exports = function(dataSourceFactory, connectorCapabilities) {
|
||||
connectorCapabilities = extend({
|
||||
// Even when the backend supports millisecond precision,
|
||||
// it's better to use intervals at least 10ms long in the tests
|
||||
ttlPrecision: 10,
|
||||
}, connectorCapabilities);
|
||||
|
||||
describe('KeyValue API', function loadAllTestFiles() {
|
||||
var testRoot = path.resolve(__dirname, 'kvao');
|
||||
var testFiles = fs.readdirSync(testRoot);
|
||||
testFiles = testFiles.filter(function(it) {
|
||||
return !!require.extensions[path.extname(it).toLowerCase()] &&
|
||||
/\.suite\.[^.]+$/.test(it);
|
||||
});
|
||||
|
||||
for (var ix in testFiles) {
|
||||
var name = testFiles[ix];
|
||||
var fullPath = path.resolve(testRoot, name);
|
||||
debug('Loading test suite %s (%s)', name, fullPath);
|
||||
require(fullPath)(dataSourceFactory, connectorCapabilities);
|
||||
}
|
||||
});
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
'use strict';
|
||||
|
||||
var Promise = require('bluebird');
|
||||
|
||||
exports.givenCacheItem = function(dataSourceFactory) {
|
||||
var dataSource = dataSourceFactory();
|
||||
return dataSource.createModel('CacheItem', {
|
||||
key: String,
|
||||
value: 'any',
|
||||
});
|
||||
};
|
||||
|
||||
exports.givenKeys = function(Model, keys, cb) {
|
||||
var p = Promise.all(
|
||||
keys.map(function(k) {
|
||||
return Model.set(k, 'value-' + k);
|
||||
})
|
||||
);
|
||||
if (cb) {
|
||||
p = p.then(function(r) { cb(null, r); }, cb);
|
||||
}
|
||||
return p;
|
||||
};
|
|
@ -0,0 +1,66 @@
|
|||
'use strict';
|
||||
|
||||
var bdd = require('../helpers/bdd-if');
|
||||
var should = require('should');
|
||||
var helpers = require('./_helpers');
|
||||
var Promise = require('bluebird');
|
||||
|
||||
module.exports = function(dataSourceFactory, connectorCapabilities) {
|
||||
// While we support millisecond precision, for the purpose of tests
|
||||
// it's better to use intervals at least 10ms long.
|
||||
var ttlPrecision = connectorCapabilities.ttlPrecision || 10;
|
||||
|
||||
var canExpire = connectorCapabilities.canExpire !== false;
|
||||
|
||||
bdd.describeIf(canExpire, 'expire', function() {
|
||||
var CacheItem;
|
||||
beforeEach(function unpackContext() {
|
||||
CacheItem = helpers.givenCacheItem(dataSourceFactory);
|
||||
});
|
||||
|
||||
it('sets key ttl - Callback API', function(done) {
|
||||
CacheItem.set('a-key', 'a-value', function(err) {
|
||||
if (err) return done(err);
|
||||
CacheItem.expire('a-key', ttlPrecision, function(err) {
|
||||
if (err) return done(err);
|
||||
setTimeout(function() {
|
||||
CacheItem.get('a-key', function(err, value) {
|
||||
if (err) return done(err);
|
||||
should.equal(value, null);
|
||||
done();
|
||||
});
|
||||
}, 2 * ttlPrecision);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('sets key ttl - Promise API', function() {
|
||||
return Promise.resolve(CacheItem.set('a-key', 'a-value'))
|
||||
.then(function() { return CacheItem.expire('a-key', ttlPrecision); })
|
||||
.delay(2 * ttlPrecision)
|
||||
.then(function() { return CacheItem.get('a-key'); })
|
||||
.then(function(value) { should.equal(value, null); });
|
||||
});
|
||||
|
||||
it('returns error when expiring a key that has expired', function() {
|
||||
return Promise.resolve(CacheItem.set('expired-key', 'a-value', ttlPrecision))
|
||||
.delay(2 * ttlPrecision)
|
||||
.then(function() { return CacheItem.expire('expired-key', 1000); })
|
||||
.then(
|
||||
function() { throw new Error('expire() should have failed'); },
|
||||
function(err) {
|
||||
err.message.should.match(/expired-key/);
|
||||
err.should.have.property('statusCode', 404);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns error when key does not exist', function() {
|
||||
return CacheItem.expire('key-does-not-exist', ttlPrecision).then(
|
||||
function() { throw new Error('expire() should have failed'); },
|
||||
function(err) {
|
||||
err.message.should.match(/key-does-not-exist/);
|
||||
err.should.have.property('statusCode', 404);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
|
@ -0,0 +1,105 @@
|
|||
'use strict';
|
||||
|
||||
var should = require('should');
|
||||
var helpers = require('./_helpers');
|
||||
var Promise = require('bluebird');
|
||||
|
||||
module.exports = function(dataSourceFactory, connectorCapabilities) {
|
||||
var TTL_PRECISION = connectorCapabilities.ttlPrecision;
|
||||
|
||||
describe('get/set', function() {
|
||||
var CacheItem;
|
||||
beforeEach(function unpackContext() {
|
||||
CacheItem = helpers.givenCacheItem(dataSourceFactory);
|
||||
});
|
||||
|
||||
it('works for string values - Callback API', function(done) {
|
||||
CacheItem.set('a-key', 'a-value', function(err) {
|
||||
if (err) return done(err);
|
||||
CacheItem.get('a-key', function(err, value) {
|
||||
if (err) return done(err);
|
||||
should.equal(value, 'a-value');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('works for string values - Promise API', function() {
|
||||
return CacheItem.set('a-key', 'a-value')
|
||||
.then(function() { return CacheItem.get('a-key'); })
|
||||
.then(function(value) { should.equal(value, 'a-value'); });
|
||||
});
|
||||
|
||||
it('works for Object values', function() {
|
||||
return CacheItem.set('a-key', {a: 1, b: 2})
|
||||
.then(function() { return CacheItem.get('a-key'); })
|
||||
.then(function(value) { value.should.eql({a: 1, b: 2}); });
|
||||
});
|
||||
|
||||
it('works for Buffer values', function() {
|
||||
return CacheItem.set('a-key', new Buffer([1, 2, 3]))
|
||||
.then(function() { return CacheItem.get('a-key'); })
|
||||
.then(function(value) { value.should.eql(new Buffer([1, 2, 3])); });
|
||||
});
|
||||
|
||||
it('works for Date values', function() {
|
||||
return CacheItem.set('a-key', new Date('2016-08-03T11:53:03.470Z'))
|
||||
.then(function() { return CacheItem.get('a-key'); })
|
||||
.then(function(value) {
|
||||
value.should.be.instanceOf(Date);
|
||||
value.toISOString().should.equal('2016-08-03T11:53:03.470Z');
|
||||
});
|
||||
});
|
||||
|
||||
it('works for Number values - integers', function() {
|
||||
return CacheItem.set('a-key', 12345)
|
||||
.then(function() { return CacheItem.get('a-key'); })
|
||||
.then(function(value) { value.should.equal(12345); });
|
||||
});
|
||||
|
||||
it('works for Number values - floats', function() {
|
||||
return CacheItem.set('a-key', 12.345)
|
||||
.then(function() { return CacheItem.get('a-key'); })
|
||||
.then(function(value) { value.should.equal(12.345); });
|
||||
});
|
||||
|
||||
it('works for Boolean values', function() {
|
||||
return CacheItem.set('a-key', false)
|
||||
.then(function() { return CacheItem.get('a-key'); })
|
||||
.then(function(value) { value.should.equal(false); });
|
||||
});
|
||||
|
||||
it('honours options.ttl', function() {
|
||||
return Promise.resolve(CacheItem.set('a-key', 'a-value', {ttl: TTL_PRECISION}))
|
||||
.delay(2 * TTL_PRECISION)
|
||||
.then(function() { return CacheItem.get('a-key'); })
|
||||
.then(function(value) { should.equal(value, null); });
|
||||
});
|
||||
|
||||
describe('get', function() {
|
||||
it('returns "null" when key does not exist', function() {
|
||||
return CacheItem.get('key-does-not-exist')
|
||||
.then(function(value) { should.equal(value, null); });
|
||||
});
|
||||
});
|
||||
|
||||
describe('set', function() {
|
||||
it('converts numeric options arg to options.ttl', function() {
|
||||
return Promise.resolve(CacheItem.set('a-key', 'a-value', TTL_PRECISION))
|
||||
.delay(2 * TTL_PRECISION)
|
||||
.then(function() { return CacheItem.get('a-key'); })
|
||||
.then(function(value) { should.equal(value, null); });
|
||||
});
|
||||
|
||||
it('resets TTL timer', function() {
|
||||
return Promise.resolve(CacheItem.set('a-key', 'a-value', {ttl: TTL_PRECISION}))
|
||||
.then(function() {
|
||||
return CacheItem.set('a-key', 'another-value'); // no TTL
|
||||
})
|
||||
.delay(2 * TTL_PRECISION)
|
||||
.then(function() { return CacheItem.get('a-key'); })
|
||||
.then(function(value) { should.equal(value, 'another-value'); });
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
|
@ -0,0 +1,51 @@
|
|||
'use strict';
|
||||
|
||||
var asyncIterators = require('async-iterators');
|
||||
var bdd = require('../helpers/bdd-if');
|
||||
var helpers = require('./_helpers');
|
||||
var Promise = require('bluebird');
|
||||
var should = require('should');
|
||||
var toArray = Promise.promisify(asyncIterators.toArray);
|
||||
|
||||
module.exports = function(dataSourceFactory, connectorCapabilities) {
|
||||
var canIterateKeys = connectorCapabilities.canIterateKeys !== false;
|
||||
|
||||
bdd.describeIf(canIterateKeys, 'iterateKeys', function() {
|
||||
var CacheItem;
|
||||
beforeEach(function unpackContext() {
|
||||
CacheItem = helpers.givenCacheItem(dataSourceFactory);
|
||||
});
|
||||
|
||||
it('returns AsyncIterator covering all keys', function() {
|
||||
return helpers.givenKeys(CacheItem, ['key1', 'key2'])
|
||||
.then(function() {
|
||||
var it = CacheItem.iterateKeys();
|
||||
should(it).have.property('next');
|
||||
return toArray(it);
|
||||
})
|
||||
.then(function(keys) {
|
||||
keys.sort();
|
||||
should(keys).eql(['key1', 'key2']);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns AsyncIterator supporting Promises', function() {
|
||||
var iterator;
|
||||
return helpers.givenKeys(CacheItem, ['key'])
|
||||
.then(function() {
|
||||
iterator = CacheItem.iterateKeys();
|
||||
return iterator.next();
|
||||
})
|
||||
.then(function(key) {
|
||||
should(key).equal('key');
|
||||
return iterator.next();
|
||||
})
|
||||
.then(function(key) {
|
||||
// Note: AsyncIterator contract requires `undefined` to signal
|
||||
// the end of the sequence. Other false-y values like `null`
|
||||
// don't work.
|
||||
should(key).equal(undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
|
@ -0,0 +1,109 @@
|
|||
'use strict';
|
||||
|
||||
var bdd = require('../helpers/bdd-if');
|
||||
var helpers = require('./_helpers');
|
||||
var Promise = require('bluebird');
|
||||
var should = require('should');
|
||||
|
||||
module.exports = function(dataSourceFactory, connectorCapabilities) {
|
||||
var canIterateKeys = connectorCapabilities.canIterateKeys !== false;
|
||||
|
||||
bdd.describeIf(canIterateKeys, 'keys', function() {
|
||||
var CacheItem;
|
||||
beforeEach(function unpackContext() {
|
||||
CacheItem = helpers.givenCacheItem(dataSourceFactory);
|
||||
CacheItem.sortedKeys = function(filter, options) {
|
||||
return this.keys(filter, options).then(function(keys) {
|
||||
keys.sort();
|
||||
return keys;
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
it('returns all keys - Callback API', function(done) {
|
||||
helpers.givenKeys(CacheItem, ['key1', 'key2'], function(err) {
|
||||
if (err) return done(err);
|
||||
CacheItem.keys(function(err, keys) {
|
||||
if (err) return done(err);
|
||||
keys.sort();
|
||||
should(keys).eql(['key1', 'key2']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('returns all keys - Promise API', function() {
|
||||
return helpers.givenKeys(CacheItem, ['key1', 'key2'])
|
||||
.then(function() {
|
||||
return CacheItem.keys();
|
||||
})
|
||||
.then(function(keys) {
|
||||
keys.sort();
|
||||
should(keys).eql(['key1', 'key2']);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns keys of the given model only', function() {
|
||||
var AnotherModel = CacheItem.dataSource.createModel('AnotherModel');
|
||||
return helpers.givenKeys(CacheItem, ['key1', 'key2'])
|
||||
.then(function() {
|
||||
return helpers.givenKeys(AnotherModel, ['otherKey1', 'otherKey2']);
|
||||
})
|
||||
.then(function() {
|
||||
return CacheItem.sortedKeys();
|
||||
})
|
||||
.then(function(keys) {
|
||||
should(keys).eql(['key1', 'key2']);
|
||||
});
|
||||
});
|
||||
|
||||
var largeKeySets = connectorCapabilities.canIterateLargeKeySets !== false;
|
||||
bdd.itIf(largeKeySets, 'handles large key set', function() {
|
||||
var expectedKeys = [];
|
||||
for (var ix = 0; ix < 1000; ix++)
|
||||
expectedKeys.push('key-' + ix);
|
||||
expectedKeys.sort();
|
||||
|
||||
return helpers.givenKeys(CacheItem, expectedKeys)
|
||||
.then(function() {
|
||||
return CacheItem.sortedKeys();
|
||||
})
|
||||
.then(function(keys) {
|
||||
should(keys).eql(expectedKeys);
|
||||
});
|
||||
});
|
||||
|
||||
context('with "filter.match"', function() {
|
||||
beforeEach(function createTestData() {
|
||||
return helpers.givenKeys(CacheItem, [
|
||||
'hallo',
|
||||
'hello',
|
||||
'hxllo',
|
||||
'hllo',
|
||||
'heeello',
|
||||
'foo',
|
||||
'bar',
|
||||
]);
|
||||
});
|
||||
|
||||
it('supports "?" operator', function() {
|
||||
return CacheItem.sortedKeys({match: 'h?llo'}).then(function(keys) {
|
||||
should(keys).eql(['hallo', 'hello', 'hxllo']);
|
||||
});
|
||||
});
|
||||
|
||||
it('supports "*" operator', function() {
|
||||
return CacheItem.sortedKeys({match: 'h*llo'}).then(function(keys) {
|
||||
should(keys).eql(['hallo', 'heeello', 'hello', 'hllo', 'hxllo']);
|
||||
});
|
||||
});
|
||||
|
||||
it('handles no matches found', function() {
|
||||
return CacheItem.sortedKeys({match: 'not-found'})
|
||||
.then(function(keys) {
|
||||
should(keys).eql([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
|
@ -0,0 +1,79 @@
|
|||
'use strict';
|
||||
|
||||
var bdd = require('../helpers/bdd-if');
|
||||
var should = require('should');
|
||||
var helpers = require('./_helpers');
|
||||
var Promise = require('bluebird');
|
||||
|
||||
module.exports = function(dataSourceFactory, connectorCapabilities) {
|
||||
var TTL_PRECISION = connectorCapabilities.ttlPrecision;
|
||||
|
||||
// Use ~1s for stores with precision of 1 ms,
|
||||
// about 3s for stores with precision of 1s.
|
||||
var INITIAL_TTL = Math.max(TTL_PRECISION + 1000, TTL_PRECISION * 3);
|
||||
|
||||
// A small delay to allow the backend to process the request, run any
|
||||
// TTL/expire checks, etc. Use 1ms for backends supporting sub-10ms
|
||||
// resolution to ensure the delay is not too short..
|
||||
var SMALL_DELAY = Math.max(1, Math.floor(TTL_PRECISION / 10));
|
||||
|
||||
var canQueryTtl = connectorCapabilities.canQueryTtl !== false;
|
||||
|
||||
bdd.describeIf(canQueryTtl, 'ttl', function() {
|
||||
var CacheItem;
|
||||
beforeEach(function unpackContext() {
|
||||
CacheItem = helpers.givenCacheItem(dataSourceFactory);
|
||||
});
|
||||
|
||||
it('gets TTL when key with unexpired TTL exists - Promise API',
|
||||
function() {
|
||||
return Promise.resolve(
|
||||
CacheItem.set('a-key', 'a-value', {ttl: INITIAL_TTL}))
|
||||
.delay(SMALL_DELAY)
|
||||
.then(function() { return CacheItem.ttl('a-key'); })
|
||||
.then(function(ttl) { ttl.should.be.within(1, INITIAL_TTL); });
|
||||
});
|
||||
|
||||
it('gets TTL when key with unexpired TTL exists - Callback API',
|
||||
function(done) {
|
||||
CacheItem.set('a-key', 'a-value', {ttl: INITIAL_TTL}, function(err) {
|
||||
if (err) return done(err);
|
||||
CacheItem.ttl('a-key', function(err, ttl) {
|
||||
if (err) return done(err);
|
||||
ttl.should.be.within(1, INITIAL_TTL);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('succeeds when key without TTL exists', function() {
|
||||
return CacheItem.set('a-key', 'a-value')
|
||||
.then(function() { return CacheItem.ttl('a-key'); })
|
||||
.then(function(ttl) { should.not.exist(ttl); });
|
||||
});
|
||||
|
||||
it('fails when getting TTL for a key with expired TTL', function() {
|
||||
return Promise.resolve(
|
||||
CacheItem.set('expired-key', 'a-value', {ttl: TTL_PRECISION}))
|
||||
.delay(2 * TTL_PRECISION)
|
||||
.then(function() {
|
||||
return CacheItem.ttl('expired-key');
|
||||
})
|
||||
.then(
|
||||
function() { throw new Error('ttl() should have failed'); },
|
||||
function(err) {
|
||||
err.message.should.match(/expired-key/);
|
||||
err.should.have.property('statusCode', 404);
|
||||
});
|
||||
});
|
||||
|
||||
it('fails when key does not exist', function() {
|
||||
return CacheItem.ttl('key-does-not-exist').then(
|
||||
function() { throw new Error('ttl() should have failed'); },
|
||||
function(err) {
|
||||
err.message.should.match(/key-does-not-exist/);
|
||||
err.should.have.property('statusCode', 404);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
|
@ -1,10 +1,16 @@
|
|||
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
||||
// Node module: loopback-datasource-juggler
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
'use strict';
|
||||
|
||||
// This test written in mocha+should.js
|
||||
var should = require('./init.js');
|
||||
|
||||
var loopbackData = require('../');
|
||||
|
||||
describe('loopback-datasource-juggler', function () {
|
||||
it('should expose version', function () {
|
||||
describe('loopback-datasource-juggler', function() {
|
||||
it('should expose version', function() {
|
||||
loopbackData.version.should.equal(require('../package.json').version);
|
||||
});
|
||||
});
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue