├── .bithoundrc ├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── dist ├── MeteorObservable.d.ts ├── MeteorObservable.js ├── MeteorObservable.js.map ├── ObservableCollection.d.ts ├── ObservableCollection.js ├── ObservableCollection.js.map ├── ObservableCursor.d.ts ├── ObservableCursor.js ├── ObservableCursor.js.map ├── bundles │ └── index.umd.js ├── index.d.ts ├── index.js ├── index.js.map ├── utils.d.ts ├── utils.js ├── utils.js.map ├── zone.d.ts ├── zone.js └── zone.js.map ├── docs ├── MeteorObservable.md ├── ObservableCollection.md └── ObservableCursor.md ├── examples └── angular2 │ ├── .gitignore │ ├── .meteor │ ├── .finished-upgraders │ ├── .gitignore │ ├── .id │ ├── packages │ ├── platforms │ ├── release │ └── versions │ ├── both │ ├── collections │ │ └── demo.collection.ts │ └── models │ │ └── demo.model.ts │ ├── client │ ├── imports │ │ └── app │ │ │ ├── app.component.html │ │ │ ├── app.component.scss │ │ │ ├── app.component.ts │ │ │ ├── app.module.ts │ │ │ └── index.ts │ ├── index.html │ ├── main.ts │ └── styles │ │ └── main.scss │ ├── package.json │ ├── server │ ├── imports │ │ └── server-main │ │ │ └── main.ts │ └── main.ts │ ├── tsconfig.json │ └── typings.d.ts ├── generate-docs.sh ├── package.json ├── rollup.config.js ├── src ├── MeteorObservable.ts ├── ObservableCollection.ts ├── ObservableCursor.ts ├── index.ts ├── utils.ts └── zone.ts ├── tests ├── .meteor │ ├── .finished-upgraders │ ├── .gitignore │ ├── .id │ ├── packages │ ├── platforms │ ├── release │ └── versions ├── client │ └── unit │ │ ├── meteor-observable.spec.ts │ │ ├── observable-collection.spec.ts │ │ ├── observable-cursor.spec.ts │ │ └── zone-operator.spec.ts ├── package-lock.json ├── package.json ├── server │ └── lib │ │ └── create-test-method.spec.ts ├── tsconfig.json └── yarn.lock ├── tsconfig.json ├── tslint.json └── yarn.lock /.bithoundrc: -------------------------------------------------------------------------------- 1 | { 2 | "ignore": [ 3 | "**/node_modules/**", 4 | "**/dist/**", 5 | "**/docs/**", 6 | "**/examples/**" 7 | ], 8 | "test": [ 9 | "**/test/**", 10 | "**/tests/**", 11 | "**/spec/**", 12 | "**/specs/**", 13 | "**/*.test.ts", 14 | "**/*.test.js", 15 | "**/*.spec.js", 16 | "**/*.spec.ts" 17 | ], 18 | "critics": { 19 | "lint": {"engine": "tslint"} 20 | }, 21 | "dependencies": { 22 | "mute": [ 23 | "rxjs", 24 | "zone.js", 25 | "jsdoc-to-markdown" 26 | ], 27 | "unused-ignores": [ 28 | "tslint", 29 | "validate-commit-msg", 30 | "typescript", 31 | "rollup", 32 | "ghooks", 33 | "es6-shim", 34 | "conventional-changelog", 35 | "conventional-changelog-cli", 36 | "zone.js", 37 | "reflect-metadata", 38 | "@types/*" 39 | ] 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .node_modules 3 | .idea 4 | typings 5 | .npm 6 | npm-debug.log 7 | package-lock.json 8 | *.log 9 | 10 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | examples 2 | tests 3 | typings 4 | src 5 | rollup.config.js 6 | run_tests.sh 7 | tsconfig.json 8 | tslint.json 9 | typings.d.ts 10 | generate-docs.sh 11 | .travis.yml 12 | .bithoundrc -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | language: node_js 3 | node_js: 4 | - "6" 5 | services: 6 | - mongodb 7 | before_install: 8 | - curl https://install.meteor.com | /bin/sh 9 | - rm -rf node_modules 10 | 11 | install: 12 | - git clean -fXd 13 | - npm install -g phantomjs-prebuilt tslint typescript rollup 14 | - npm install 15 | - cd tests && meteor npm rebuild && cd .. 16 | 17 | script: 18 | - npm run test-ci 19 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ## 0.4.9 (2018-03-17) 3 | 4 | * bug fixes ([85383ed](https://github.com/Urigo/mongo-rxjs-observable/commit/85383ed)) 5 | * bump version ([da88a37](https://github.com/Urigo/mongo-rxjs-observable/commit/da88a37)) 6 | * change rxjs imports to best practice for better performance ([f4887a5](https://github.com/Urigo/mongo-rxjs-observable/commit/f4887a5)) 7 | * fix version bump ([6b8fead](https://github.com/Urigo/mongo-rxjs-observable/commit/6b8fead)) 8 | * fixes ([05d1e67](https://github.com/Urigo/mongo-rxjs-observable/commit/05d1e67)) 9 | * make dependencies compatible with both angular and meteor ([bcdc720](https://github.com/Urigo/mongo-rxjs-observable/commit/bcdc720)) 10 | * removed old tslint config ([e6530b2](https://github.com/Urigo/mongo-rxjs-observable/commit/e6530b2)) 11 | * Replace 'meteor-typings' with '@types/meteor' ([791ba31](https://github.com/Urigo/mongo-rxjs-observable/commit/791ba31)) 12 | * rollup configuration fixed ([23d1ea5](https://github.com/Urigo/mongo-rxjs-observable/commit/23d1ea5)) 13 | * Store subscriptionIds to handle re-subscriptions ([8ddd5f1](https://github.com/Urigo/mongo-rxjs-observable/commit/8ddd5f1)) 14 | * try to fix meteor typings issue ([e1eb411](https://github.com/Urigo/mongo-rxjs-observable/commit/e1eb411)) 15 | * Update documentation for MeteorObservable ([c7816ba](https://github.com/Urigo/mongo-rxjs-observable/commit/c7816ba)) 16 | * update README.md ([a67078c](https://github.com/Urigo/mongo-rxjs-observable/commit/a67078c)) 17 | * update rollup.config.js ([a5c4565](https://github.com/Urigo/mongo-rxjs-observable/commit/a5c4565)) 18 | * update test script ([e0ff15c](https://github.com/Urigo/mongo-rxjs-observable/commit/e0ff15c)) 19 | * updated all deps and some minor fixes ([58b0fda](https://github.com/Urigo/mongo-rxjs-observable/commit/58b0fda)) 20 | * updated changelog ([cb9697f](https://github.com/Urigo/mongo-rxjs-observable/commit/cb9697f)) 21 | * refactor(deps): renovate pin dependencies packages ([b967636](https://github.com/Urigo/mongo-rxjs-observable/commit/b967636)) 22 | * fix: return empty array when find yield no results ([b09c6af](https://github.com/Urigo/mongo-rxjs-observable/commit/b09c6af)) 23 | 24 | 25 | ## 0.4.8 (2017-09-13) 26 | * updated all dependencies 27 | * updated tests project to latest Meteor version 28 | * Fix: return empty array when find yield no results [#103](https://github.com/Urigo/meteor-rxjs/pull/103) 29 | * Fix multiple MeteorObservable.subscribe calls with identical arguments [#76](https://github.com/Urigo/meteor-rxjs/pull/76) 30 | 31 | 32 | ## 0.4.7 (2016-12-21) 33 | 34 | * chore: add ref to the main ES6 module in package.json (for bundling) ([b5f7bab](https://github.com/Urigo/mongo-rxjs-observable/commit/b5f7bab)) 35 | * chore: remove browser from package.json (not needed) ([6b30a15](https://github.com/Urigo/mongo-rxjs-observable/commit/6b30a15)) 36 | * chore(bithound): fixed unused ([7353c76](https://github.com/Urigo/mongo-rxjs-observable/commit/7353c76)) 37 | * chore(bithound): ignore examples directory ([00f6712](https://github.com/Urigo/mongo-rxjs-observable/commit/00f6712)) 38 | * chore(bithound): ignore zone.js ([2364061](https://github.com/Urigo/mongo-rxjs-observable/commit/2364061)) 39 | * chore(build): fixed build ([28ac86a](https://github.com/Urigo/mongo-rxjs-observable/commit/28ac86a)) 40 | * chore(dependencies): cleanup and generated dist ([f4debe4](https://github.com/Urigo/mongo-rxjs-observable/commit/f4debe4)) 41 | * chore(dependencies): updated tslint ([d979b06](https://github.com/Urigo/mongo-rxjs-observable/commit/d979b06)) 42 | * chore(deps): update rxjs ([48967df](https://github.com/Urigo/mongo-rxjs-observable/commit/48967df)) 43 | * chore(license): add license file ([edf365c](https://github.com/Urigo/mongo-rxjs-observable/commit/edf365c)) 44 | * chore(package): update @types/mocha to version 2.2.34 ([5de0f13](https://github.com/Urigo/mongo-rxjs-observable/commit/5de0f13)) 45 | * chore(package): update @types/underscore to version 1.7.34 ([54b6e15](https://github.com/Urigo/mongo-rxjs-observable/commit/54b6e15)) 46 | * chore(package): update @types/underscore to version 1.7.35 ([2962f0e](https://github.com/Urigo/mongo-rxjs-observable/commit/2962f0e)) 47 | * chore(package): update @types/underscore to version 1.7.36 ([f863cc9](https://github.com/Urigo/mongo-rxjs-observable/commit/f863cc9)) 48 | * chore(package): update es6-shim to version 0.35.2 ([7a69239](https://github.com/Urigo/mongo-rxjs-observable/commit/7a69239)) 49 | * chore(package): update rollup to version 0.36.4 ([5f727a5](https://github.com/Urigo/mongo-rxjs-observable/commit/5f727a5)) 50 | * chore(package): update rollup to version 0.37.0 ([d00522e](https://github.com/Urigo/mongo-rxjs-observable/commit/d00522e)) 51 | * chore(package): update rollup to version 0.37.1 ([24cd297](https://github.com/Urigo/mongo-rxjs-observable/commit/24cd297)) 52 | * chore(package): update tslint to version 4.0.1 ([36aecea](https://github.com/Urigo/mongo-rxjs-observable/commit/36aecea)) 53 | * chore(package): update tslint to version 4.1.0 ([cb0d60a](https://github.com/Urigo/mongo-rxjs-observable/commit/cb0d60a)) 54 | * chore(package): update typescript to version 2.0.10 ([daacf21](https://github.com/Urigo/mongo-rxjs-observable/commit/daacf21)) 55 | * chore(package): update typescript to version 2.1.4 ([1226d43](https://github.com/Urigo/mongo-rxjs-observable/commit/1226d43)) 56 | * chore(package): update zone.js to version 0.7.3 ([4aec29a](https://github.com/Urigo/mongo-rxjs-observable/commit/4aec29a)) 57 | * chore(package): update zone.js to version 0.7.4 ([4a322e3](https://github.com/Urigo/mongo-rxjs-observable/commit/4a322e3)) 58 | * chore(sourcemap): added missing source map files ([4d62b9c](https://github.com/Urigo/mongo-rxjs-observable/commit/4d62b9c)) 59 | * chore(types): some minor fixes for new typings ([cc7215c](https://github.com/Urigo/mongo-rxjs-observable/commit/cc7215c)) 60 | * release(0.4.6): release new version ([e7210b3](https://github.com/Urigo/mongo-rxjs-observable/commit/e7210b3)) 61 | * tests(version): updated meteor version for tests project ([a041b6d](https://github.com/Urigo/mongo-rxjs-observable/commit/a041b6d)) 62 | * removed old tslint config ([e6530b2](https://github.com/Urigo/mongo-rxjs-observable/commit/e6530b2)) 63 | * Replace 'meteor-typings' with '@types/meteor' ([b0d35e1](https://github.com/Urigo/mongo-rxjs-observable/commit/b0d35e1)) 64 | * Update documentation for MeteorObservable ([c7816ba](https://github.com/Urigo/mongo-rxjs-observable/commit/c7816ba)) 65 | * docs(MeteorObservable): Generated new docs ([0b56dd6](https://github.com/Urigo/mongo-rxjs-observable/commit/0b56dd6)) 66 | 67 | 68 | 69 | 70 | ## 0.4.5 (2016-11-15) 71 | 72 | * chore(changelog): Minor fix ([49049a9](https://github.com/Urigo/mongo-rxjs-observable/commit/49049a9)) 73 | * chore(changelog): updated changelog ([ec411b5](https://github.com/Urigo/mongo-rxjs-observable/commit/ec411b5)) 74 | * chore(changelog): Updated changelog files ([025e825](https://github.com/Urigo/mongo-rxjs-observable/commit/025e825)) 75 | * chore(compiler): fixed compiler version ([1d9cb43](https://github.com/Urigo/mongo-rxjs-observable/commit/1d9cb43)) 76 | * chore(package): added greenkeeper config ([385c8c5](https://github.com/Urigo/mongo-rxjs-observable/commit/385c8c5)) 77 | * chore(package): update @types/mocha to version 2.2.33 ([947f930](https://github.com/Urigo/mongo-rxjs-observable/commit/947f930)) 78 | * chore(package): update typescript to version 2.0.9 ([05e2320](https://github.com/Urigo/mongo-rxjs-observable/commit/05e2320)) 79 | * chore(README): Added npm version badge ([5e142cf](https://github.com/Urigo/mongo-rxjs-observable/commit/5e142cf)) 80 | * chore(tests): added yarn lock file to tests app ([8edbe83](https://github.com/Urigo/mongo-rxjs-observable/commit/8edbe83)) 81 | * chore(tests): fixes for missing package dependency ([572db5a](https://github.com/Urigo/mongo-rxjs-observable/commit/572db5a)) 82 | * chore(tests): reverted yarn from tests app ([ab7da65](https://github.com/Urigo/mongo-rxjs-observable/commit/ab7da65)) 83 | * chore(tests): updated tests application to use latest Meteor ([c3e40f6](https://github.com/Urigo/mongo-rxjs-observable/commit/c3e40f6)) 84 | * chore(version): bump ([fbdddb9](https://github.com/Urigo/mongo-rxjs-observable/commit/fbdddb9)) 85 | * chore(yarn): use yarn and added missing typings file ([ffdaa8f](https://github.com/Urigo/mongo-rxjs-observable/commit/ffdaa8f)) 86 | 87 | 88 | 89 | 90 | ## 0.4.4 (2016-11-09) 91 | 92 | * chore(changelog): update CHANGELOG ([b3584de](https://github.com/Urigo/mongo-rxjs-observable/commit/b3584de)) 93 | * chore(changelog): updated based on commits ([88e11a6](https://github.com/Urigo/mongo-rxjs-observable/commit/88e11a6)) 94 | * chore(npmignore): Added npm ignore file ([b914e13](https://github.com/Urigo/mongo-rxjs-observable/commit/b914e13)) 95 | * chore(package): update dependencies ([2296123](https://github.com/Urigo/mongo-rxjs-observable/commit/2296123)) 96 | 97 | 98 | 99 | 100 | ## 0.4.3 (2016-11-03) 101 | 102 | * chore(changelog): Added auto generated changelog ([80dfa46](https://github.com/Urigo/mongo-rxjs-observable/commit/80dfa46)) 103 | * chore(lint): Added bitHound badges ([7c034f1](https://github.com/Urigo/mongo-rxjs-observable/commit/7c034f1)) 104 | * chore(lint): Added bitHound, Updated dependencies and lint issues ([36dfe7f](https://github.com/Urigo/mongo-rxjs-observable/commit/36dfe7f)) 105 | * chore(package.json): bump version ([21ccc90](https://github.com/Urigo/mongo-rxjs-observable/commit/21ccc90)) 106 | * chore(README): Updated badge ([efbd509](https://github.com/Urigo/mongo-rxjs-observable/commit/efbd509)) 107 | * chore(release): bump ([c6f9bba](https://github.com/Urigo/mongo-rxjs-observable/commit/c6f9bba)) 108 | * chore(scripts): Added build and clean before tests ([bd889de](https://github.com/Urigo/mongo-rxjs-observable/commit/bd889de)) 109 | * chore(scripts): Added changelog script ([094b688](https://github.com/Urigo/mongo-rxjs-observable/commit/094b688)) 110 | * chore(scripts): Removed typings script ([3060b1e](https://github.com/Urigo/mongo-rxjs-observable/commit/3060b1e)) 111 | * chore(travis): Fixes for global modules ([0528ac0](https://github.com/Urigo/mongo-rxjs-observable/commit/0528ac0)) 112 | * chore(typescript): Removed typings from travis script ([424001c](https://github.com/Urigo/mongo-rxjs-observable/commit/424001c)) 113 | * chore(typescript): Replace typings with @types and fixed TS issues ([ae96888](https://github.com/Urigo/mongo-rxjs-observable/commit/ae96888)) 114 | * bugfix(types): Fixes array type of Observable in find() ([7a3f0f5](https://github.com/Urigo/mongo-rxjs-observable/commit/7a3f0f5)) 115 | * ci(README): Added ci badge to README ([bb2f480](https://github.com/Urigo/mongo-rxjs-observable/commit/bb2f480)) 116 | * ci(travis): Added missing npm globals ([3c92baa](https://github.com/Urigo/mongo-rxjs-observable/commit/3c92baa)) 117 | * ci(travis): Added missing npm install ([cad2a94](https://github.com/Urigo/mongo-rxjs-observable/commit/cad2a94)) 118 | * ci(travis): Added missing package ([3802b70](https://github.com/Urigo/mongo-rxjs-observable/commit/3802b70)) 119 | * ci(travis): Added pre test to the ci script ([5ba3396](https://github.com/Urigo/mongo-rxjs-observable/commit/5ba3396)) 120 | * ci(travis): remove cache ([9b566ca](https://github.com/Urigo/mongo-rxjs-observable/commit/9b566ca)) 121 | * ci(travis): Updated travis file ([a12f42d](https://github.com/Urigo/mongo-rxjs-observable/commit/a12f42d)) 122 | * ci(travis): Updated travis file ([34dcc3e](https://github.com/Urigo/mongo-rxjs-observable/commit/34dcc3e)) 123 | * docs(script): small fix ([02306d8](https://github.com/Urigo/mongo-rxjs-observable/commit/02306d8)) 124 | * examples(angular2): Added angular2+meteor-ngrx with OnPush example ([9d97b51](https://github.com/Urigo/mongo-rxjs-observable/commit/9d97b51)) 125 | * feat(multiple-subscribers): Applied another solution ([bc789db](https://github.com/Urigo/mongo-rxjs-observable/commit/bc789db)) 126 | * feat(multiple-subscribers): Updated dist version and docs ([82b8a09](https://github.com/Urigo/mongo-rxjs-observable/commit/82b8a09)) 127 | * feat(multiple-subscribers): Added publishReplay to the created Observable ([31f7698](https://github.com/Urigo/mongo-rxjs-observable/commit/31f7698)) 128 | 129 | 130 | 131 | 132 | ## 0.4.1 (2016-11-01) 133 | 134 | * chore: bump rxjs dep ([de35ef9](https://github.com/Urigo/mongo-rxjs-observable/commit/de35ef9)) 135 | * chore: ship NPM with ES6 modules and UMD bundle (which is referenced in package.json) ([afd95f1](https://github.com/Urigo/mongo-rxjs-observable/commit/afd95f1)) 136 | * chore: tests, ts 2.0, types, ci ([e65fefa](https://github.com/Urigo/mongo-rxjs-observable/commit/e65fefa)) 137 | * chore(bugfix): Added Tracker.autorun, and fixed issue with "subscribe" and the complete ([55dc88b](https://github.com/Urigo/mongo-rxjs-observable/commit/55dc88b)) 138 | * chore(bugfix): Small fix in autorun ([106ffd4](https://github.com/Urigo/mongo-rxjs-observable/commit/106ffd4)) 139 | * chore(collection): Added ability to wrap existing Mongo.Collection ([18c384f](https://github.com/Urigo/mongo-rxjs-observable/commit/18c384f)) 140 | * chore(collection): Added ability to wrap existing Mongo.Collection ([d49e7bb](https://github.com/Urigo/mongo-rxjs-observable/commit/d49e7bb)) 141 | * chore(collection): Changed the method name ([de33898](https://github.com/Urigo/mongo-rxjs-observable/commit/de33898)) 142 | * chore(README): Added link to the API docs ([02d6f45](https://github.com/Urigo/mongo-rxjs-observable/commit/02d6f45)) 143 | * chore(release): publish 0.2.3 ([17ed794](https://github.com/Urigo/mongo-rxjs-observable/commit/17ed794)) 144 | * chore(release): publish 0.4.0 ([3b5bbf6](https://github.com/Urigo/mongo-rxjs-observable/commit/3b5bbf6)) 145 | * chore(release): release 0.2.0 ([20f36f7](https://github.com/Urigo/mongo-rxjs-observable/commit/20f36f7)) 146 | * chore(release): Release 0.3.0 ([68bc3b6](https://github.com/Urigo/mongo-rxjs-observable/commit/68bc3b6)) 147 | * chore(tests): Added npm script for test and test:ci ([d275404](https://github.com/Urigo/mongo-rxjs-observable/commit/d275404)) 148 | * chore(tests): Added unit tests for movedTo ([a254b96](https://github.com/Urigo/mongo-rxjs-observable/commit/a254b96)) 149 | * chore(tests): Updated tests Meteor version to the latest ([703708f](https://github.com/Urigo/mongo-rxjs-observable/commit/703708f)) 150 | * chore(tests): Updated tests scripts ([4beae33](https://github.com/Urigo/mongo-rxjs-observable/commit/4beae33)) 151 | * chore(version): bump ([59772ff](https://github.com/Urigo/mongo-rxjs-observable/commit/59772ff)) 152 | * feat: initial course code ([e163f52](https://github.com/Urigo/mongo-rxjs-observable/commit/e163f52)) 153 | * feat: run subscriber callbacks in the current zone, i.e. zone operator can use most outer zone propa ([ec08c91](https://github.com/Urigo/mongo-rxjs-observable/commit/ec08c91)) 154 | * feat(count): Added collectionCount Observable and it's tests ([4b027c6](https://github.com/Urigo/mongo-rxjs-observable/commit/4b027c6)) 155 | * feat(jsdoc): Added documentation and build version, and docs generation script ([00e546a](https://github.com/Urigo/mongo-rxjs-observable/commit/00e546a)) 156 | * feat(jsdoc): document MeteorObservable class ([c63917d](https://github.com/Urigo/mongo-rxjs-observable/commit/c63917d)) 157 | * feat(jsdoc): Document ObservableCollection and ObservableCursor ([4b7391a](https://github.com/Urigo/mongo-rxjs-observable/commit/4b7391a)) 158 | * feat(jsdoc): Fixed a typo ([50deb25](https://github.com/Urigo/mongo-rxjs-observable/commit/50deb25)) 159 | * feat(jsdoc): Minor fixes for docs generation scripts ([ec051df](https://github.com/Urigo/mongo-rxjs-observable/commit/ec051df)) 160 | * feat(jsdoc): Updated docs generation scripts and updated docs ([ded2eff](https://github.com/Urigo/mongo-rxjs-observable/commit/ded2eff)) 161 | * feat(jsdoc): Updated documentation ([32413d2](https://github.com/Urigo/mongo-rxjs-observable/commit/32413d2)) 162 | * bugfix(moved-to): Added missing callback and handler for moving items inside a collection ([e79af51](https://github.com/Urigo/mongo-rxjs-observable/commit/e79af51)) 163 | * bugfix(multiple-subscribers): Attempt to fix the multiple subscribers issue ([ace9c78](https://github.com/Urigo/mongo-rxjs-observable/commit/ace9c78)) 164 | * bugfix(multiple-subscribers): Revert :( ([f65a5e4](https://github.com/Urigo/mongo-rxjs-observable/commit/f65a5e4)) 165 | * docs: correct readme ([58d9b8f](https://github.com/Urigo/mongo-rxjs-observable/commit/58d9b8f)) 166 | * docs: readme ([24dc190](https://github.com/Urigo/mongo-rxjs-observable/commit/24dc190)) 167 | * docs: readme ([2830da3](https://github.com/Urigo/mongo-rxjs-observable/commit/2830da3)) 168 | * docs: readme ([a7ba861](https://github.com/Urigo/mongo-rxjs-observable/commit/a7ba861)) 169 | * docs: readme ([d91c202](https://github.com/Urigo/mongo-rxjs-observable/commit/d91c202)) 170 | * docs: readme ([6dda077](https://github.com/Urigo/mongo-rxjs-observable/commit/6dda077)) 171 | * docs: readme ([1a7d6d2](https://github.com/Urigo/mongo-rxjs-observable/commit/1a7d6d2)) 172 | * docs: readme ([7b43e16](https://github.com/Urigo/mongo-rxjs-observable/commit/7b43e16)) 173 | * fix: #14 ([21b1a39](https://github.com/Urigo/mongo-rxjs-observable/commit/21b1a39)) 174 | * .gitignore, useful. ([db1fe79](https://github.com/Urigo/mongo-rxjs-observable/commit/db1fe79)) 175 | * Add complete() support to zone operator ([dc05322](https://github.com/Urigo/mongo-rxjs-observable/commit/dc05322)) 176 | * Correctly reference the typings in package.json to enable imports. ([c836860](https://github.com/Urigo/mongo-rxjs-observable/commit/c836860)) 177 | * Fix devDep of rxjs - use beta.12 ([801b134](https://github.com/Urigo/mongo-rxjs-observable/commit/801b134)) 178 | * Fixed typo. ([5c7c3a5](https://github.com/Urigo/mongo-rxjs-observable/commit/5c7c3a5)) 179 | * refactor: rename package to meteor-rxjs ([aff3619](https://github.com/Urigo/mongo-rxjs-observable/commit/aff3619)) 180 | 181 | 182 | 183 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Uri Goldshtein 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Meteor + RxJS 2 | 3 | [![npm version](https://badge.fury.io/js/meteor-rxjs.svg)](https://badge.fury.io/js/meteor-rxjs) [![Build Status](https://travis-ci.org/Urigo/meteor-rxjs.svg?branch=master)](https://travis-ci.org/Urigo/meteor-rxjs) [![bitHound Overall Score](https://www.bithound.io/github/Urigo/meteor-rxjs/badges/score.svg)](https://www.bithound.io/github/Urigo/meteor-rxjs) [![bitHound Code](https://www.bithound.io/github/Urigo/meteor-rxjs/badges/code.svg)](https://www.bithound.io/github/Urigo/meteor-rxjs) [![bitHound Dev Dependencies](https://www.bithound.io/github/Urigo/meteor-rxjs/badges/devDependencies.svg)](https://www.bithound.io/github/Urigo/meteor-rxjs/master/dependencies/npm) 4 | 5 | Harness Meteor reactivity with RxJS. 6 | 7 | RxJS is built to simplify complexity dealing with reactive data flows. At the same time, Meteor's Minimongo cursors are a good target for RxJS API due to their reactivity. Thus, combining RxJS and Meteor, we bring together best parts of two worlds. 8 | 9 | # API Documentation 10 | 11 | API documentation is available inside this repository, [here](https://github.com/Urigo/meteor-rxjs/tree/master/docs). 12 | 13 | ## Mongo Cursor Observable 14 | As soon as you install this package (`npm install meteor-rxjs`), you have ability to use a special Mongo collection class that works 15 | with cursor observables instead of the ordinary Mongo cursors. In other words, one can subscribe on the Mongo cursor's data updates now as follows: 16 | 17 | ```ts 18 | 19 | import {MongoObservable} from 'meteor-rxjs'; 20 | 21 | const Tasks = new MongoObservable.Collection('tasks'); 22 | 23 | Tasks.find({checked: false}) 24 | .map(tasks => tasks.length) 25 | .subscribe(todoCount => console.log(todoCount)); 26 | 27 | ``` 28 | 29 | Since this cursor observable is of RxJS’s type, every other methods and operators available to the observables as part of the RxJS API are also now available to the users, e.g., one can debounce data updates using RxJS’s debouncing operator: 30 | 31 | ```ts 32 | 33 | import {Observable} from 'rxjs'; 34 | 35 | import {debounce, map} from 'rxjs/operators'; 36 | 37 | Tasks.find({checked: false}) 38 | .pipe(debounce(() => Observable.interval(50))) 39 | .pipe(map(tasks => tasks.length)) 40 | .subscribe(todoCount => console.log(todoCount)); 41 | 42 | ``` 43 | 44 | ## Usage with Meteor packages 45 | 46 | Meteor has a lot of packages that extend `Mongo.Collection` with new methods. Since `MongoObservable.Collection` is a wrapper over `Mongo.Collection`, you can't use new methods on observable instances directly. The solution here is to pass `Mongo.Collection`'s instance to the observable constructor, and use them whenever you need after separately: 47 | ```ts 48 | let collection = new Mongo.Collection('foo'); 49 | let observable = new MongoObservable.Collection(collection); 50 | collection.attachSchema(...); // with SimpleSchema package 51 | ``` 52 | 53 | ## Usage in Angular 54 | 55 | Angular has tight integration with RxJS since Angular is desinged to support reactive UI updates. 56 | One of the realizations of this integration is `AsyncPipe`, which is supposed to be used with RxJS observables. 57 | 58 | In order to subscribe on the Mongo cursor observable's updates and iterate through the returned list of docs in Angular, one can use `AsyncPipe` in an Angular component as follows: 59 | 60 | ```ts 61 | import { MongoObservable, zoneOperator } from 'rxjs'; 62 | 63 | const Tasks = new MongoObservable.Collection('tasks'); 64 | 65 | @Component({ 66 | selector: 'task-list', 67 | template: `` 68 | }) 69 | class Tasks { 70 | tasks = Tasks.find().pipe(zoneOperator()); 71 | } 72 | 73 | ```` 74 | 75 | ### Zone operator 76 | 77 | As you can see above we called `zoneOperator` operator of the cursor observable. This is a special 78 | Zone operator that is implemeted by `meteor-rxjs` for the Angular users' convenience. 79 | This operator runs ngZone each time when new data arrives to the Mongo cursor observable, 80 | thus we force UI updates at the right time using it. 81 | 82 | It makes sense to improve performance of the above `Tasks` component by debouncing UI updates. 83 | In this case we are using Zone operator as well: 84 | 85 | ```ts 86 | 87 | class List { 88 | tasks = Tasks.find() 89 | .pipe(zoneOperator()) 90 | .pipe(debounce(() => Observable.interval(50))) 91 | .zone(); 92 | } 93 | 94 | ``` 95 | 96 | ##License 97 | MIT 98 | -------------------------------------------------------------------------------- /dist/MeteorObservable.d.ts: -------------------------------------------------------------------------------- 1 | import { Observable } from 'rxjs'; 2 | /** 3 | * This is a class with static methods that wrap Meteor's API and return RxJS 4 | * Observables. The methods' signatures are the same as Meteor's, with the ] 5 | * exception that the callbacks are handled by Meteor-rxjs. Instead of 6 | * providing callbacks, you need to subscribe to the observables that are 7 | * returned. The methods that are wrapped in MeteorObservable are 8 | * [Meteor.call](https://docs.meteor.com/api/methods.html#Meteor-call), 9 | * [Meteor.autorun](https://docs.meteor.com/api/tracker.html#Tracker-autorun) 10 | * and [Meteor.subscribe](https://docs.meteor.com/api/pubsub.html#Meteor-subscribe). 11 | */ 12 | export declare class MeteorObservable { 13 | /** 14 | * Invokes a [Meteor Method](https://docs.meteor.com/api/methods.html) 15 | * defined on the server, passing any number of arguments. This method has 16 | * the same signature as 17 | * [Meteor.call](https://docs.meteor.com/api/methods.html#Meteor-call), only 18 | * without the callbacks: 19 | * MeteorObservable.call(name, [...args]) 20 | * 21 | * 22 | * @param {string} name - Name of the method in the Meteor server 23 | * @param {any} args - Parameters that will be forwarded to the method. 24 | * after the func call to initiate change detection. 25 | * @returns {Observable} - RxJS Observable, which completes when the 26 | * server returns a response. 27 | * 28 | * @example Example using Angular2 Component 29 | * class MyComponent { 30 | * constructor() { 31 | * 32 | * } 33 | * 34 | * doAction(payload) { 35 | * MeteorObservable.call("myData", payload).subscribe((response) => { 36 | * // Handle success and response from server! 37 | * }, (err) => { 38 | * // Handle error 39 | * }); 40 | * } 41 | * } 42 | */ 43 | static call(name: string, ...args: any[]): Observable; 44 | /** 45 | * When you subscribe to a collection, it tells the server to send records to 46 | * the client. This method has the same signature as 47 | * [Meteor.subscribe](https://docs.meteor.com/api/pubsub.html#Meteor-subscribe), 48 | * except without the callbacks again: 49 | * subscribe(name, [...args]) 50 | * 51 | * You can use this method from any Angular2 element - such as Component, 52 | * Pipe or Service. 53 | * 54 | * @param {string} name - Name of the publication in the Meteor server 55 | * @param {any} args - Parameters that will be forwarded to the publication. 56 | * after the func call to initiate change detection. 57 | * @returns {Observable} - RxJS Observable, which completes when the 58 | * subscription is ready. 59 | * 60 | * @example Example using Angular2 Service 61 | * class MyService { 62 | * private meteorSubscription: Observable; 63 | * 64 | * constructor() { 65 | * 66 | * } 67 | * 68 | * subscribeToData() { 69 | * this.meteorSubscription = MeteorObservable.subscribe("myData").subscribe(() => { 70 | * // Subscription is ready! 71 | * }); 72 | * } 73 | * 74 | * unsubscribeToData() { 75 | * this.meteorSubscription.unsubscribe(); 76 | * } 77 | * } 78 | * 79 | * @example Example using Angular2 Component 80 | * class MyComponent implements OnInit, OnDestroy { 81 | * private meteorSubscription: Observable; 82 | * 83 | * constructor() { 84 | * 85 | * } 86 | * 87 | * ngOnInit() { 88 | * this.meteorSubscription = MeteorObservable.subscribe("myData").subscribe(() => { 89 | * // Subscription is ready! 90 | * }); 91 | * } 92 | * 93 | * ngOnDestroy() { 94 | * this.meteorSubscription.unsubscribe(); 95 | * } 96 | * } 97 | * 98 | * @see {@link http://docs.meteor.com/api/pubsub.html|Publications in Meteor documentation} 99 | */ 100 | static subscribe(name: string, ...args: any[]): Observable; 101 | /** 102 | * Allows you to run a function every time there is a change is a reactive 103 | * data sources. This method has the same signature as 104 | * [Meteor.autorun](https://docs.meteor.com/api/tracker.html#Tracker-autorun), 105 | * only without the callback: 106 | * MeteorObservable.autorun() 107 | * 108 | * @returns {Observable} - RxJS Observable, which trigger the subscription callback 109 | * each time that Meteor Tracker detects a change. 110 | * @example Example using Angular2 Component 111 | * class MyComponent { 112 | * constructor() { 113 | * 114 | * } 115 | * 116 | * doAction(payload) { 117 | * MeteorObservable.autorun().subscribe(() => { 118 | * // Handle Tracker autorun change 119 | * }); 120 | * } 121 | * } 122 | */ 123 | static autorun(): Observable; 124 | } 125 | -------------------------------------------------------------------------------- /dist/MeteorObservable.js: -------------------------------------------------------------------------------- 1 | import { Observable } from 'rxjs'; 2 | import { isMeteorCallbacks, forkZone, removeObserver } from './utils'; 3 | var liveSubscriptions = []; 4 | function throwInvalidCallback(method) { 5 | throw new Error("Invalid " + method + " arguments:\n your last param can't be a callback function,\n please remove it and use \".subscribe\" of the Observable!"); 6 | } 7 | /** 8 | * This is a class with static methods that wrap Meteor's API and return RxJS 9 | * Observables. The methods' signatures are the same as Meteor's, with the ] 10 | * exception that the callbacks are handled by Meteor-rxjs. Instead of 11 | * providing callbacks, you need to subscribe to the observables that are 12 | * returned. The methods that are wrapped in MeteorObservable are 13 | * [Meteor.call](https://docs.meteor.com/api/methods.html#Meteor-call), 14 | * [Meteor.autorun](https://docs.meteor.com/api/tracker.html#Tracker-autorun) 15 | * and [Meteor.subscribe](https://docs.meteor.com/api/pubsub.html#Meteor-subscribe). 16 | */ 17 | var MeteorObservable = /** @class */ (function () { 18 | function MeteorObservable() { 19 | } 20 | /** 21 | * Invokes a [Meteor Method](https://docs.meteor.com/api/methods.html) 22 | * defined on the server, passing any number of arguments. This method has 23 | * the same signature as 24 | * [Meteor.call](https://docs.meteor.com/api/methods.html#Meteor-call), only 25 | * without the callbacks: 26 | * MeteorObservable.call(name, [...args]) 27 | * 28 | * 29 | * @param {string} name - Name of the method in the Meteor server 30 | * @param {any} args - Parameters that will be forwarded to the method. 31 | * after the func call to initiate change detection. 32 | * @returns {Observable} - RxJS Observable, which completes when the 33 | * server returns a response. 34 | * 35 | * @example Example using Angular2 Component 36 | * class MyComponent { 37 | * constructor() { 38 | * 39 | * } 40 | * 41 | * doAction(payload) { 42 | * MeteorObservable.call("myData", payload).subscribe((response) => { 43 | * // Handle success and response from server! 44 | * }, (err) => { 45 | * // Handle error 46 | * }); 47 | * } 48 | * } 49 | */ 50 | MeteorObservable.call = function (name) { 51 | var args = []; 52 | for (var _i = 1; _i < arguments.length; _i++) { 53 | args[_i - 1] = arguments[_i]; 54 | } 55 | var lastParam = args[args.length - 1]; 56 | if (isMeteorCallbacks(lastParam)) { 57 | throwInvalidCallback('MeteorObservable.call'); 58 | } 59 | var zone = forkZone(); 60 | return Observable.create(function (observer) { 61 | Meteor.call.apply(Meteor, [name].concat(args.concat([ 62 | function (error, result) { 63 | zone.run(function () { 64 | error ? observer.error(error) : 65 | observer.next(result); 66 | observer.complete(); 67 | }); 68 | } 69 | ]))); 70 | }); 71 | }; 72 | /** 73 | * When you subscribe to a collection, it tells the server to send records to 74 | * the client. This method has the same signature as 75 | * [Meteor.subscribe](https://docs.meteor.com/api/pubsub.html#Meteor-subscribe), 76 | * except without the callbacks again: 77 | * subscribe(name, [...args]) 78 | * 79 | * You can use this method from any Angular2 element - such as Component, 80 | * Pipe or Service. 81 | * 82 | * @param {string} name - Name of the publication in the Meteor server 83 | * @param {any} args - Parameters that will be forwarded to the publication. 84 | * after the func call to initiate change detection. 85 | * @returns {Observable} - RxJS Observable, which completes when the 86 | * subscription is ready. 87 | * 88 | * @example Example using Angular2 Service 89 | * class MyService { 90 | * private meteorSubscription: Observable; 91 | * 92 | * constructor() { 93 | * 94 | * } 95 | * 96 | * subscribeToData() { 97 | * this.meteorSubscription = MeteorObservable.subscribe("myData").subscribe(() => { 98 | * // Subscription is ready! 99 | * }); 100 | * } 101 | * 102 | * unsubscribeToData() { 103 | * this.meteorSubscription.unsubscribe(); 104 | * } 105 | * } 106 | * 107 | * @example Example using Angular2 Component 108 | * class MyComponent implements OnInit, OnDestroy { 109 | * private meteorSubscription: Observable; 110 | * 111 | * constructor() { 112 | * 113 | * } 114 | * 115 | * ngOnInit() { 116 | * this.meteorSubscription = MeteorObservable.subscribe("myData").subscribe(() => { 117 | * // Subscription is ready! 118 | * }); 119 | * } 120 | * 121 | * ngOnDestroy() { 122 | * this.meteorSubscription.unsubscribe(); 123 | * } 124 | * } 125 | * 126 | * @see {@link http://docs.meteor.com/api/pubsub.html|Publications in Meteor documentation} 127 | */ 128 | MeteorObservable.subscribe = function (name) { 129 | var args = []; 130 | for (var _i = 1; _i < arguments.length; _i++) { 131 | args[_i - 1] = arguments[_i]; 132 | } 133 | var lastParam = args[args.length - 1]; 134 | if (isMeteorCallbacks(lastParam)) { 135 | throwInvalidCallback('MeteorObservable.subscribe'); 136 | } 137 | var zone = forkZone(); 138 | var observers = []; 139 | var subscribe = function () { 140 | return Meteor.subscribe.apply(Meteor, [name].concat(args.concat([{ 141 | onError: function (error) { 142 | zone.run(function () { 143 | observers.forEach(function (observer) { return observer.error(error); }); 144 | }); 145 | }, 146 | onReady: function () { 147 | zone.run(function () { 148 | observers.forEach(function (observer) { return observer.next(); }); 149 | }); 150 | } 151 | } 152 | ]))); 153 | }; 154 | var subHandler = null; 155 | return Observable.create(function (observer) { 156 | observers.push(observer); 157 | // Execute subscribe lazily. 158 | if (subHandler === null) { 159 | subHandler = subscribe(); 160 | if (liveSubscriptions.find(function (sub) { return sub === subHandler.subscriptionId; })) { 161 | // subscription already exists, call observer.next() since Meteor won't. 162 | observer.next(); 163 | } 164 | else { 165 | liveSubscriptions.push(subHandler.subscriptionId); 166 | } 167 | } 168 | return function () { 169 | removeObserver(observers, observer, function () { 170 | // remove subscription from liveSubscriptions list 171 | var i = liveSubscriptions.findIndex(function (sub) { return sub === subHandler.subscriptionId; }); 172 | if (i > -1) { 173 | liveSubscriptions.splice(i, 1); 174 | } 175 | subHandler.stop(); 176 | }); 177 | }; 178 | }); 179 | }; 180 | /** 181 | * Allows you to run a function every time there is a change is a reactive 182 | * data sources. This method has the same signature as 183 | * [Meteor.autorun](https://docs.meteor.com/api/tracker.html#Tracker-autorun), 184 | * only without the callback: 185 | * MeteorObservable.autorun() 186 | * 187 | * @returns {Observable} - RxJS Observable, which trigger the subscription callback 188 | * each time that Meteor Tracker detects a change. 189 | * @example Example using Angular2 Component 190 | * class MyComponent { 191 | * constructor() { 192 | * 193 | * } 194 | * 195 | * doAction(payload) { 196 | * MeteorObservable.autorun().subscribe(() => { 197 | * // Handle Tracker autorun change 198 | * }); 199 | * } 200 | * } 201 | */ 202 | MeteorObservable.autorun = function () { 203 | var zone = forkZone(); 204 | var observers = []; 205 | var autorun = function () { 206 | return Tracker.autorun(function (computation) { 207 | zone.run(function () { 208 | observers.forEach(function (observer) { return observer.next(computation); }); 209 | }); 210 | }); 211 | }; 212 | var handler = null; 213 | return Observable.create(function (observer) { 214 | observers.push(observer); 215 | // Execute autorun lazily. 216 | if (handler === null) { 217 | handler = autorun(); 218 | } 219 | return function () { 220 | removeObserver(observers, observer, function () { return handler.stop(); }); 221 | }; 222 | }); 223 | }; 224 | return MeteorObservable; 225 | }()); 226 | export { MeteorObservable }; 227 | //# sourceMappingURL=MeteorObservable.js.map -------------------------------------------------------------------------------- /dist/MeteorObservable.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"MeteorObservable.js","sourceRoot":"","sources":["../src/MeteorObservable.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/ObservableCollection.d.ts: -------------------------------------------------------------------------------- 1 | import { Observable } from 'rxjs'; 2 | import { ObservableCursor } from './ObservableCursor'; 3 | import Selector = Mongo.Selector; 4 | import ObjectID = Mongo.ObjectID; 5 | import SortSpecifier = Mongo.SortSpecifier; 6 | import FieldSpecifier = Mongo.FieldSpecifier; 7 | import Modifier = Mongo.Modifier; 8 | export declare module MongoObservable { 9 | interface ConstructorOptions { 10 | connection?: Object; 11 | idGeneration?: string; 12 | transform?: Function; 13 | } 14 | interface AllowDenyOptionsObject { 15 | insert?: (userId: string, doc: T) => boolean; 16 | update?: (userId: string, doc: T, fieldNames: string[], modifier: any) => boolean; 17 | remove?: (userId: string, doc: T) => boolean; 18 | fetch?: string[]; 19 | transform?: Function; 20 | } 21 | /** 22 | * Creates a new MongoObservable.Collection from an existing of predefined Mongo.Collection. 23 | * Use this feature to wrap existing collections such as Meteor.users. 24 | * @param {Mongo.Collection} collection - The collection. 25 | * @returns {MongoObservable.Collection} - Wrapped collection. 26 | * @static 27 | */ 28 | function fromExisting(collection: Mongo.Collection): MongoObservable.Collection; 29 | /** 30 | * A class represents a MongoDB collection in the client side, wrapped with RxJS 31 | * Observables, so you can use it with your Angular 2 easier. 32 | * The wrapper has the same API as Mongo.Collection, only the "find" method returns 33 | * an ObservableCursor instead of regular Mongo.Cursor. 34 | * 35 | * T is a generic type - should be used with the type of the objects inside the collection. 36 | */ 37 | class Collection { 38 | private _collection; 39 | /** 40 | * Creates a new Mongo.Collection instance wrapped with Observable features. 41 | * @param {String | Mongo.Collection} nameOrExisting - The name of the collection. If null, creates an 42 | * unmanaged (unsynchronized) local collection. If provided an instance of existing collection, will 43 | * create a wrapper for the existing Mongo.Collection. 44 | * @param {ConstructorOptions} options - Creation options. 45 | * @constructor 46 | */ 47 | constructor(nameOrExisting: string | Mongo.Collection, options?: ConstructorOptions); 48 | /** 49 | * Returns the Mongo.Collection object that wrapped with the MongoObservable.Collection. 50 | * @returns {Mongo.Collection} The Collection instance 51 | */ 52 | readonly collection: Mongo.Collection; 53 | /** 54 | * Allow users to write directly to this collection from client code, subject to limitations you define. 55 | * 56 | * @returns {Boolean} 57 | */ 58 | allow(options: AllowDenyOptionsObject): boolean; 59 | /** 60 | * Override allow rules. 61 | * 62 | * @returns {Boolean} 63 | */ 64 | deny(options: AllowDenyOptionsObject): boolean; 65 | /** 66 | * Returns the Collection object corresponding to this collection from the npm 67 | * mongodb driver module which is wrapped by Mongo.Collection. 68 | * 69 | * @returns {Mongo.Collection} The Collection instance 70 | * 71 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-rawCollection|rawCollection on Meteor documentation} 72 | */ 73 | rawCollection(): any; 74 | /** 75 | * Returns the Db object corresponding to this collection's database connection from the 76 | * npm mongodb driver module which is wrapped by Mongo.Collection. 77 | * 78 | * @returns {Mongo.Db} The Db instance 79 | * 80 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-rawDatabase|rawDatabase on Meteor documentation} 81 | */ 82 | rawDatabase(): any; 83 | /** 84 | * Insert a document in the collection. 85 | * 86 | * @param {T} doc - The document to insert. May not yet have an _id 87 | * attribute, in which case Meteor will generate one for you. 88 | * @returns {Observable} Observable which completes with the inserted ObjectId 89 | * 90 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-insert|insert on Meteor documentation} 91 | */ 92 | insert(doc: T): Observable; 93 | /** 94 | * Remove documents from the collection. 95 | * 96 | * @param {Collection~MongoQuerySelector} selector - Specifies which documents to modify 97 | * @returns {Observable} Observable which completes with the number of affected rows 98 | * 99 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-remove|remove on Meteor documentation} 100 | */ 101 | remove(selector: Selector | ObjectID | string): Observable; 102 | /** 103 | * Modify one or more documents in the collection. 104 | * 105 | * @param {Collection~MongoQuerySelector} selector - Specifies which documents to modify 106 | * @param {Modifier} modifier - Specifies how to modify the documents 107 | * @param {MongoUpdateOptions} options - Update options 108 | * first argument and, if no error, the number of affected documents as the second 109 | * @returns {Observable} Observable which completes with the number of affected rows 110 | * 111 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-update|update on Meteor documentation} 112 | */ 113 | update(selector: Selector | ObjectID | string, modifier: Modifier, options?: { 114 | multi?: boolean; 115 | upsert?: boolean; 116 | }): Observable; 117 | /** 118 | * Finds the first document that matches the selector, as ordered by sort and skip options. 119 | * 120 | * @param {Collection~MongoQuerySelector} selector - Specifies which documents to modify 121 | * @param {Modifier} modifier - Specifies how to modify the documents 122 | * @param {MongoUpsertOptions} options - Upsert options 123 | * first argument and, if no error, the number of affected documents as the second. 124 | * @returns {Observable<{numberAffected, insertedId}>} Observable which completes with an 125 | * Object that contain the keys numberAffected and insertedId. 126 | * 127 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-upsert|upsert on Meteor documentation} 128 | */ 129 | upsert(selector: Selector | ObjectID | string, modifier: Modifier, options?: { 130 | multi?: boolean; 131 | }): Observable; 132 | /** 133 | * Method has the same notation as Mongo.Collection.find, only returns Observable. 134 | * 135 | * @param {Collection~MongoQuerySelector} selector - A query describing the documents to find 136 | * @param {Collection~MongoQueryOptions} options - Query options, such as sort, limit, etc. 137 | * @returns {ObservableCursor} RxJS Observable wrapped with Meteor features. 138 | * @example Using Angular2 Component 139 | * const MyCollection = MongoObservable.Collection("myCollection"); 140 | * 141 | * class MyComponent { 142 | * private myData: ObservableCursor; 143 | * 144 | * constructor() { 145 | * this.myData = MyCollection.find({}, {limit: 10}); 146 | * } 147 | * } 148 | * 149 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-find|find on Meteor documentation} 150 | */ 151 | find(selector?: Selector | ObjectID | string, options?: { 152 | sort?: SortSpecifier; 153 | skip?: number; 154 | limit?: number; 155 | fields?: FieldSpecifier; 156 | reactive?: boolean; 157 | transform?: Function; 158 | }): ObservableCursor; 159 | /** 160 | * Finds the first document that matches the selector, as ordered by sort and skip options. 161 | * 162 | * @param {Collection~MongoQuerySelector} selector - A query describing the documents to find 163 | * @param {Collection~MongoQueryOptions} options - Query options, such as sort, limit, etc. 164 | * @returns {any} The first object, or `undefined` in case of non-existing object. 165 | * 166 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-findOne|findOne on Meteor documentation} 167 | */ 168 | findOne(selector?: Selector | ObjectID | string, options?: { 169 | sort?: SortSpecifier; 170 | skip?: number; 171 | fields?: FieldSpecifier; 172 | reactive?: boolean; 173 | transform?: Function; 174 | }): T; 175 | private _createObservable(observers); 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /dist/ObservableCollection.js: -------------------------------------------------------------------------------- 1 | import { Observable } from 'rxjs'; 2 | import { ObservableCursor } from './ObservableCursor'; 3 | import { removeObserver } from './utils'; 4 | export var MongoObservable; 5 | (function (MongoObservable) { 6 | 'use strict'; 7 | /** 8 | * Creates a new MongoObservable.Collection from an existing of predefined Mongo.Collection. 9 | * Use this feature to wrap existing collections such as Meteor.users. 10 | * @param {Mongo.Collection} collection - The collection. 11 | * @returns {MongoObservable.Collection} - Wrapped collection. 12 | * @static 13 | */ 14 | function fromExisting(collection) { 15 | return new MongoObservable.Collection(collection); 16 | } 17 | MongoObservable.fromExisting = fromExisting; 18 | /** 19 | * A class represents a MongoDB collection in the client side, wrapped with RxJS 20 | * Observables, so you can use it with your Angular 2 easier. 21 | * The wrapper has the same API as Mongo.Collection, only the "find" method returns 22 | * an ObservableCursor instead of regular Mongo.Cursor. 23 | * 24 | * T is a generic type - should be used with the type of the objects inside the collection. 25 | */ 26 | var Collection = /** @class */ (function () { 27 | /** 28 | * Creates a new Mongo.Collection instance wrapped with Observable features. 29 | * @param {String | Mongo.Collection} nameOrExisting - The name of the collection. If null, creates an 30 | * unmanaged (unsynchronized) local collection. If provided an instance of existing collection, will 31 | * create a wrapper for the existing Mongo.Collection. 32 | * @param {ConstructorOptions} options - Creation options. 33 | * @constructor 34 | */ 35 | function Collection(nameOrExisting, options) { 36 | if (nameOrExisting instanceof Mongo.Collection) { 37 | this._collection = nameOrExisting; 38 | } 39 | else { 40 | this._collection = new Mongo.Collection(nameOrExisting, options); 41 | } 42 | } 43 | Object.defineProperty(Collection.prototype, "collection", { 44 | /** 45 | * Returns the Mongo.Collection object that wrapped with the MongoObservable.Collection. 46 | * @returns {Mongo.Collection} The Collection instance 47 | */ 48 | get: function () { 49 | return this._collection; 50 | }, 51 | enumerable: true, 52 | configurable: true 53 | }); 54 | /** 55 | * Allow users to write directly to this collection from client code, subject to limitations you define. 56 | * 57 | * @returns {Boolean} 58 | */ 59 | Collection.prototype.allow = function (options) { 60 | return this._collection.allow(options); 61 | }; 62 | /** 63 | * Override allow rules. 64 | * 65 | * @returns {Boolean} 66 | */ 67 | Collection.prototype.deny = function (options) { 68 | return this._collection.deny(options); 69 | }; 70 | /** 71 | * Returns the Collection object corresponding to this collection from the npm 72 | * mongodb driver module which is wrapped by Mongo.Collection. 73 | * 74 | * @returns {Mongo.Collection} The Collection instance 75 | * 76 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-rawCollection|rawCollection on Meteor documentation} 77 | */ 78 | Collection.prototype.rawCollection = function () { 79 | return this._collection.rawCollection(); 80 | }; 81 | /** 82 | * Returns the Db object corresponding to this collection's database connection from the 83 | * npm mongodb driver module which is wrapped by Mongo.Collection. 84 | * 85 | * @returns {Mongo.Db} The Db instance 86 | * 87 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-rawDatabase|rawDatabase on Meteor documentation} 88 | */ 89 | Collection.prototype.rawDatabase = function () { 90 | return this._collection.rawDatabase(); 91 | }; 92 | /** 93 | * Insert a document in the collection. 94 | * 95 | * @param {T} doc - The document to insert. May not yet have an _id 96 | * attribute, in which case Meteor will generate one for you. 97 | * @returns {Observable} Observable which completes with the inserted ObjectId 98 | * 99 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-insert|insert on Meteor documentation} 100 | */ 101 | Collection.prototype.insert = function (doc) { 102 | var observers = []; 103 | var obs = this._createObservable(observers); 104 | this._collection.insert(doc, function (error, docId) { 105 | observers.forEach(function (observer) { 106 | error ? observer.error(error) : 107 | observer.next(docId); 108 | observer.complete(); 109 | }); 110 | }); 111 | return obs; 112 | }; 113 | /** 114 | * Remove documents from the collection. 115 | * 116 | * @param {Collection~MongoQuerySelector} selector - Specifies which documents to modify 117 | * @returns {Observable} Observable which completes with the number of affected rows 118 | * 119 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-remove|remove on Meteor documentation} 120 | */ 121 | Collection.prototype.remove = function (selector) { 122 | var observers = []; 123 | var obs = this._createObservable(observers); 124 | this._collection.remove(selector, function (error, removed) { 125 | observers.forEach(function (observer) { 126 | error ? observer.error(error) : 127 | observer.next(removed); 128 | observer.complete(); 129 | }); 130 | }); 131 | return obs; 132 | }; 133 | /** 134 | * Modify one or more documents in the collection. 135 | * 136 | * @param {Collection~MongoQuerySelector} selector - Specifies which documents to modify 137 | * @param {Modifier} modifier - Specifies how to modify the documents 138 | * @param {MongoUpdateOptions} options - Update options 139 | * first argument and, if no error, the number of affected documents as the second 140 | * @returns {Observable} Observable which completes with the number of affected rows 141 | * 142 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-update|update on Meteor documentation} 143 | */ 144 | Collection.prototype.update = function (selector, modifier, options) { 145 | var observers = []; 146 | var obs = this._createObservable(observers); 147 | this._collection.update(selector, modifier, options, function (error, updated) { 148 | observers.forEach(function (observer) { 149 | error ? observer.error(error) : 150 | observer.next(updated); 151 | observer.complete(); 152 | }); 153 | }); 154 | return obs; 155 | }; 156 | /** 157 | * Finds the first document that matches the selector, as ordered by sort and skip options. 158 | * 159 | * @param {Collection~MongoQuerySelector} selector - Specifies which documents to modify 160 | * @param {Modifier} modifier - Specifies how to modify the documents 161 | * @param {MongoUpsertOptions} options - Upsert options 162 | * first argument and, if no error, the number of affected documents as the second. 163 | * @returns {Observable<{numberAffected, insertedId}>} Observable which completes with an 164 | * Object that contain the keys numberAffected and insertedId. 165 | * 166 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-upsert|upsert on Meteor documentation} 167 | */ 168 | Collection.prototype.upsert = function (selector, modifier, options) { 169 | var observers = []; 170 | var obs = this._createObservable(observers); 171 | this._collection.upsert(selector, modifier, options, function (error, affected) { 172 | observers.forEach(function (observer) { 173 | error ? observer.error(error) : 174 | observer.next(affected); 175 | observer.complete(); 176 | }); 177 | }); 178 | return obs; 179 | }; 180 | /** 181 | * Method has the same notation as Mongo.Collection.find, only returns Observable. 182 | * 183 | * @param {Collection~MongoQuerySelector} selector - A query describing the documents to find 184 | * @param {Collection~MongoQueryOptions} options - Query options, such as sort, limit, etc. 185 | * @returns {ObservableCursor} RxJS Observable wrapped with Meteor features. 186 | * @example Using Angular2 Component 187 | * const MyCollection = MongoObservable.Collection("myCollection"); 188 | * 189 | * class MyComponent { 190 | * private myData: ObservableCursor; 191 | * 192 | * constructor() { 193 | * this.myData = MyCollection.find({}, {limit: 10}); 194 | * } 195 | * } 196 | * 197 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-find|find on Meteor documentation} 198 | */ 199 | Collection.prototype.find = function (selector, options) { 200 | var cursor = this._collection.find.apply(this._collection, arguments); 201 | return ObservableCursor.create(cursor); 202 | }; 203 | /** 204 | * Finds the first document that matches the selector, as ordered by sort and skip options. 205 | * 206 | * @param {Collection~MongoQuerySelector} selector - A query describing the documents to find 207 | * @param {Collection~MongoQueryOptions} options - Query options, such as sort, limit, etc. 208 | * @returns {any} The first object, or `undefined` in case of non-existing object. 209 | * 210 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-findOne|findOne on Meteor documentation} 211 | */ 212 | Collection.prototype.findOne = function (selector, options) { 213 | return this._collection.findOne.apply(this._collection, arguments); 214 | }; 215 | Collection.prototype._createObservable = function (observers) { 216 | return Observable.create(function (observer) { 217 | observers.push(observer); 218 | return function () { 219 | removeObserver(observers, observer); 220 | }; 221 | }); 222 | }; 223 | return Collection; 224 | }()); 225 | MongoObservable.Collection = Collection; 226 | })(MongoObservable || (MongoObservable = {})); 227 | /** 228 | * An options object for MongoDB queries. 229 | * @typedef {Object} Collection~MongoQueryOptions 230 | * @property {Object} sort - Sort order (default: natural order) 231 | * @property {Number} skip - Number of results to skip at the beginning 232 | * @property {Object} fields - Dictionary of fields to return or exclude. 233 | * @property {Boolean} reactive - (Client only) Default true; pass false to disable reactivity 234 | * @property {Function} transform - Overrides transform on the Collection for this cursor. Pass null to disable transformation. 235 | */ 236 | /** 237 | * A MongoDB query selector representation. 238 | * @typedef {(Mongo.Selector|Mongo.ObjectID|string)} Collection~MongoQuerySelector 239 | */ 240 | /** 241 | * A MongoDB query options for upsert action 242 | * @typedef {Object} Collection~MongoUpsertOptions 243 | * @property {Boolean} multi - True to modify all matching documents; 244 | * false to only modify one of the matching documents (the default). 245 | */ 246 | /** 247 | * A MongoDB query options for update action 248 | * @typedef {Object} Collection~MongoUpdateOptions 249 | * @property {Boolean} multi - True to modify all matching documents; 250 | * @property {Boolean} upsert - True to use upsert logic. 251 | */ 252 | //# sourceMappingURL=ObservableCollection.js.map -------------------------------------------------------------------------------- /dist/ObservableCollection.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"ObservableCollection.js","sourceRoot":"","sources":["../src/ObservableCollection.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/ObservableCursor.d.ts: -------------------------------------------------------------------------------- 1 | import { Observable } from 'rxjs'; 2 | export declare class ObservableCursor extends Observable { 3 | private _zone; 4 | private _data; 5 | private _cursor; 6 | private _hCursor; 7 | private _observers; 8 | private _countObserver; 9 | private _isDataInitinialized; 10 | /** 11 | * Static method which creates an ObservableCursor from Mongo.Cursor. 12 | * Use this to create an ObservableCursor object from an existing Mongo.Cursor. 13 | * Prefer to create an Cursors from the ObservableCollection instance instead. 14 | * 15 | * @param {Mongo.Cursor} cursor - The Mongo.Cursor to wrap. 16 | * @static 17 | * @returns {ObservableCursor} Wrapped Cursor. 18 | */ 19 | static create(cursor: Mongo.Cursor): ObservableCursor; 20 | /** 21 | * @constructor 22 | * @extends Observable 23 | * @param {Mongo.Cursor} cursor - The Mongo.Cursor to wrap. 24 | */ 25 | constructor(cursor: Mongo.Cursor); 26 | /** 27 | * Returns the actual Mongo.Cursor that wrapped by current ObservableCursor instance. 28 | * @return {Mongo.Cursor} The actual MongoDB Cursor. 29 | */ 30 | readonly cursor: Mongo.Cursor; 31 | /** 32 | * A wrapper for Mongo.Cursor.count() method - returns an Observable of number, which 33 | * triggers each time there is a change in the collection, and exposes the number of 34 | * objects in the collection. 35 | * @returns {Observable} Observable which trigger the callback when the 36 | * count of the object changes. 37 | */ 38 | collectionCount(): Observable; 39 | /** 40 | * Stops the observation on the cursor. 41 | */ 42 | stop(): void; 43 | /** 44 | * Clears the Observable definition. 45 | * Use this method only when the Observable is still cold, and there are no active subscriptions yet. 46 | */ 47 | dispose(): void; 48 | /** 49 | * Return all matching documents as an Array. 50 | * 51 | * @return {Array} The array with the matching documents. 52 | */ 53 | fetch(): Array; 54 | /** 55 | * Watch a query. Receive callbacks as the result set changes. 56 | * @param {Mongo.ObserveCallbacks} callbacks - The callbacks object. 57 | * @return {Meteor.LiveQueryHandle} The array with the matching documents. 58 | */ 59 | observe(callbacks: Object): Meteor.LiveQueryHandle; 60 | /** 61 | * Watch a query. Receive callbacks as the result set changes. 62 | * Only the differences between the old and new documents are passed to the callbacks. 63 | * @param {Mongo.ObserveChangesCallbacks} callbacks - The callbacks object. 64 | * @return {Meteor.LiveQueryHandle} The array with the matching documents. 65 | */ 66 | observeChanges(callbacks: Object): Meteor.LiveQueryHandle; 67 | _runComplete(): void; 68 | _runNext(data: Array): void; 69 | _addedAt(doc: any, at: any, before: any): void; 70 | _changedAt(doc: any, old: any, at: any): void; 71 | _removedAt(doc: any, at: any): void; 72 | _movedTo(doc: any, fromIndex: any, toIndex: any): void; 73 | _handleChange(): void; 74 | _observeCursor(cursor: Mongo.Cursor): any; 75 | } 76 | -------------------------------------------------------------------------------- /dist/ObservableCursor.js: -------------------------------------------------------------------------------- 1 | var __extends = (this && this.__extends) || (function () { 2 | var extendStatics = Object.setPrototypeOf || 3 | ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 4 | function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; 5 | return function (d, b) { 6 | extendStatics(d, b); 7 | function __() { this.constructor = d; } 8 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 9 | }; 10 | })(); 11 | import { Observable, Subject } from 'rxjs'; 12 | import { gZone, forkZone, removeObserver } from './utils'; 13 | var ObservableCursor = /** @class */ (function (_super) { 14 | __extends(ObservableCursor, _super); 15 | /** 16 | * @constructor 17 | * @extends Observable 18 | * @param {Mongo.Cursor} cursor - The Mongo.Cursor to wrap. 19 | */ 20 | function ObservableCursor(cursor) { 21 | var _this = _super.call(this, function (observer) { 22 | _this._observers.push(observer); 23 | if (!_this._hCursor) { 24 | _this._hCursor = _this._observeCursor(cursor); 25 | } 26 | Meteor.setTimeout(function () { 27 | if (_this._isDataInitinialized) { 28 | observer.next(_this._data); 29 | } 30 | else if (cursor.count() === 0) { 31 | _this._isDataInitinialized = true; 32 | observer.next(_this._data); 33 | } 34 | }, 0); 35 | return function () { 36 | removeObserver(_this._observers, observer, function () { return _this.stop(); }); 37 | }; 38 | }) || this; 39 | _this._data = []; 40 | _this._observers = []; 41 | _this._countObserver = new Subject(); 42 | _this._isDataInitinialized = false; 43 | _.extend(_this, _.omit(cursor, 'count', 'map')); 44 | _this._cursor = cursor; 45 | _this._zone = forkZone(); 46 | return _this; 47 | } 48 | /** 49 | * Static method which creates an ObservableCursor from Mongo.Cursor. 50 | * Use this to create an ObservableCursor object from an existing Mongo.Cursor. 51 | * Prefer to create an Cursors from the ObservableCollection instance instead. 52 | * 53 | * @param {Mongo.Cursor} cursor - The Mongo.Cursor to wrap. 54 | * @static 55 | * @returns {ObservableCursor} Wrapped Cursor. 56 | */ 57 | ObservableCursor.create = function (cursor) { 58 | return new ObservableCursor(cursor); 59 | }; 60 | Object.defineProperty(ObservableCursor.prototype, "cursor", { 61 | /** 62 | * Returns the actual Mongo.Cursor that wrapped by current ObservableCursor instance. 63 | * @return {Mongo.Cursor} The actual MongoDB Cursor. 64 | */ 65 | get: function () { 66 | return this._cursor; 67 | }, 68 | enumerable: true, 69 | configurable: true 70 | }); 71 | /** 72 | * A wrapper for Mongo.Cursor.count() method - returns an Observable of number, which 73 | * triggers each time there is a change in the collection, and exposes the number of 74 | * objects in the collection. 75 | * @returns {Observable} Observable which trigger the callback when the 76 | * count of the object changes. 77 | */ 78 | ObservableCursor.prototype.collectionCount = function () { 79 | return this._countObserver.asObservable(); 80 | }; 81 | /** 82 | * Stops the observation on the cursor. 83 | */ 84 | ObservableCursor.prototype.stop = function () { 85 | var _this = this; 86 | this._zone.run(function () { 87 | _this._runComplete(); 88 | }); 89 | if (this._hCursor) { 90 | this._hCursor.stop(); 91 | } 92 | this._data = []; 93 | this._hCursor = null; 94 | }; 95 | /** 96 | * Clears the Observable definition. 97 | * Use this method only when the Observable is still cold, and there are no active subscriptions yet. 98 | */ 99 | ObservableCursor.prototype.dispose = function () { 100 | this._observers = null; 101 | this._cursor = null; 102 | }; 103 | /** 104 | * Return all matching documents as an Array. 105 | * 106 | * @return {Array} The array with the matching documents. 107 | */ 108 | ObservableCursor.prototype.fetch = function () { 109 | return this._cursor.fetch(); 110 | }; 111 | /** 112 | * Watch a query. Receive callbacks as the result set changes. 113 | * @param {Mongo.ObserveCallbacks} callbacks - The callbacks object. 114 | * @return {Meteor.LiveQueryHandle} The array with the matching documents. 115 | */ 116 | ObservableCursor.prototype.observe = function (callbacks) { 117 | return this._cursor.observe(callbacks); 118 | }; 119 | /** 120 | * Watch a query. Receive callbacks as the result set changes. 121 | * Only the differences between the old and new documents are passed to the callbacks. 122 | * @param {Mongo.ObserveChangesCallbacks} callbacks - The callbacks object. 123 | * @return {Meteor.LiveQueryHandle} The array with the matching documents. 124 | */ 125 | ObservableCursor.prototype.observeChanges = function (callbacks) { 126 | return this._cursor.observeChanges(callbacks); 127 | }; 128 | ObservableCursor.prototype._runComplete = function () { 129 | this._countObserver.complete(); 130 | this._observers.forEach(function (observer) { 131 | observer.complete(); 132 | }); 133 | }; 134 | ObservableCursor.prototype._runNext = function (data) { 135 | this._countObserver.next(this._data.length); 136 | this._observers.forEach(function (observer) { 137 | observer.next(data); 138 | }); 139 | }; 140 | ObservableCursor.prototype._addedAt = function (doc, at, before) { 141 | this._data.splice(at, 0, doc); 142 | this._handleChange(); 143 | }; 144 | ObservableCursor.prototype._changedAt = function (doc, old, at) { 145 | this._data[at] = doc; 146 | this._handleChange(); 147 | }; 148 | ObservableCursor.prototype._removedAt = function (doc, at) { 149 | this._data.splice(at, 1); 150 | this._handleChange(); 151 | }; 152 | ObservableCursor.prototype._movedTo = function (doc, fromIndex, toIndex) { 153 | this._data.splice(fromIndex, 1); 154 | this._data.splice(toIndex, 0, doc); 155 | this._handleChange(); 156 | }; 157 | ObservableCursor.prototype._handleChange = function () { 158 | var _this = this; 159 | this._isDataInitinialized = true; 160 | this._zone.run(function () { 161 | _this._runNext(_this._data); 162 | }); 163 | }; 164 | ObservableCursor.prototype._observeCursor = function (cursor) { 165 | var _this = this; 166 | return gZone.run(function () { return cursor.observe({ 167 | addedAt: _this._addedAt.bind(_this), 168 | changedAt: _this._changedAt.bind(_this), 169 | movedTo: _this._movedTo.bind(_this), 170 | removedAt: _this._removedAt.bind(_this) 171 | }); }); 172 | }; 173 | return ObservableCursor; 174 | }(Observable)); 175 | export { ObservableCursor }; 176 | //# sourceMappingURL=ObservableCursor.js.map -------------------------------------------------------------------------------- /dist/ObservableCursor.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"ObservableCursor.js","sourceRoot":"","sources":["../src/ObservableCursor.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/bundles/index.umd.js: -------------------------------------------------------------------------------- 1 | (function (global, factory) { 2 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('rxjs')) : 3 | typeof define === 'function' && define.amd ? define(['exports', 'rxjs'], factory) : 4 | (factory((global.meteor = global.meteor || {}, global.meteor.rxjs = {}),global.rxjs)); 5 | }(this, (function (exports,rxjs) { 'use strict'; 6 | 7 | var subscribeEvents = ['onReady', 'onError', 'onStop']; 8 | function isMeteorCallbacks(callbacks) { 9 | return _.isFunction(callbacks) || isCallbacksObject(callbacks); 10 | } 11 | // Checks if callbacks of {@link CallbacksObject} type. 12 | function isCallbacksObject(callbacks) { 13 | return callbacks && subscribeEvents.some(function (event) { 14 | return _.isFunction(callbacks[event]); 15 | }); 16 | } 17 | var g = typeof global === 'object' ? global : 18 | typeof window === 'object' ? window : 19 | typeof self === 'object' ? self : undefined; 20 | var METEOR_RXJS_ZONE = 'meteor-rxjs-zone'; 21 | var fakeZone = { 22 | name: METEOR_RXJS_ZONE, 23 | run: function (func) { 24 | return func(); 25 | }, 26 | fork: function (spec) { 27 | return fakeZone; 28 | } 29 | }; 30 | function forkZone() { 31 | if (g.Zone) { 32 | var zone = g.Zone.current; 33 | if (zone.name === METEOR_RXJS_ZONE) { 34 | zone = zone.parent || fakeZone; 35 | } 36 | return zone.fork({ name: METEOR_RXJS_ZONE }); 37 | } 38 | return fakeZone; 39 | } 40 | function getZone() { 41 | if (g.Zone) { 42 | var zone = g.Zone.current; 43 | if (zone.name === METEOR_RXJS_ZONE) { 44 | return zone.parent; 45 | } 46 | return zone; 47 | } 48 | } 49 | function removeObserver(observers, observer, onEmpty) { 50 | var index = observers.indexOf(observer); 51 | observers.splice(index, 1); 52 | if (observers.length === 0 && onEmpty) { 53 | onEmpty(); 54 | } 55 | } 56 | var gZone = g.Zone ? g.Zone.current : fakeZone; 57 | 58 | var __extends = (undefined && undefined.__extends) || (function () { 59 | var extendStatics = Object.setPrototypeOf || 60 | ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 61 | function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; 62 | return function (d, b) { 63 | extendStatics(d, b); 64 | function __() { this.constructor = d; } 65 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 66 | }; 67 | })(); 68 | var ObservableCursor = /** @class */ (function (_super) { 69 | __extends(ObservableCursor, _super); 70 | /** 71 | * @constructor 72 | * @extends Observable 73 | * @param {Mongo.Cursor} cursor - The Mongo.Cursor to wrap. 74 | */ 75 | function ObservableCursor(cursor) { 76 | var _this = _super.call(this, function (observer) { 77 | _this._observers.push(observer); 78 | if (!_this._hCursor) { 79 | _this._hCursor = _this._observeCursor(cursor); 80 | } 81 | Meteor.setTimeout(function () { 82 | if (_this._isDataInitinialized) { 83 | observer.next(_this._data); 84 | } 85 | else if (cursor.count() === 0) { 86 | _this._isDataInitinialized = true; 87 | observer.next(_this._data); 88 | } 89 | }, 0); 90 | return function () { 91 | removeObserver(_this._observers, observer, function () { return _this.stop(); }); 92 | }; 93 | }) || this; 94 | _this._data = []; 95 | _this._observers = []; 96 | _this._countObserver = new rxjs.Subject(); 97 | _this._isDataInitinialized = false; 98 | _.extend(_this, _.omit(cursor, 'count', 'map')); 99 | _this._cursor = cursor; 100 | _this._zone = forkZone(); 101 | return _this; 102 | } 103 | /** 104 | * Static method which creates an ObservableCursor from Mongo.Cursor. 105 | * Use this to create an ObservableCursor object from an existing Mongo.Cursor. 106 | * Prefer to create an Cursors from the ObservableCollection instance instead. 107 | * 108 | * @param {Mongo.Cursor} cursor - The Mongo.Cursor to wrap. 109 | * @static 110 | * @returns {ObservableCursor} Wrapped Cursor. 111 | */ 112 | ObservableCursor.create = function (cursor) { 113 | return new ObservableCursor(cursor); 114 | }; 115 | Object.defineProperty(ObservableCursor.prototype, "cursor", { 116 | /** 117 | * Returns the actual Mongo.Cursor that wrapped by current ObservableCursor instance. 118 | * @return {Mongo.Cursor} The actual MongoDB Cursor. 119 | */ 120 | get: function () { 121 | return this._cursor; 122 | }, 123 | enumerable: true, 124 | configurable: true 125 | }); 126 | /** 127 | * A wrapper for Mongo.Cursor.count() method - returns an Observable of number, which 128 | * triggers each time there is a change in the collection, and exposes the number of 129 | * objects in the collection. 130 | * @returns {Observable} Observable which trigger the callback when the 131 | * count of the object changes. 132 | */ 133 | ObservableCursor.prototype.collectionCount = function () { 134 | return this._countObserver.asObservable(); 135 | }; 136 | /** 137 | * Stops the observation on the cursor. 138 | */ 139 | ObservableCursor.prototype.stop = function () { 140 | var _this = this; 141 | this._zone.run(function () { 142 | _this._runComplete(); 143 | }); 144 | if (this._hCursor) { 145 | this._hCursor.stop(); 146 | } 147 | this._data = []; 148 | this._hCursor = null; 149 | }; 150 | /** 151 | * Clears the Observable definition. 152 | * Use this method only when the Observable is still cold, and there are no active subscriptions yet. 153 | */ 154 | ObservableCursor.prototype.dispose = function () { 155 | this._observers = null; 156 | this._cursor = null; 157 | }; 158 | /** 159 | * Return all matching documents as an Array. 160 | * 161 | * @return {Array} The array with the matching documents. 162 | */ 163 | ObservableCursor.prototype.fetch = function () { 164 | return this._cursor.fetch(); 165 | }; 166 | /** 167 | * Watch a query. Receive callbacks as the result set changes. 168 | * @param {Mongo.ObserveCallbacks} callbacks - The callbacks object. 169 | * @return {Meteor.LiveQueryHandle} The array with the matching documents. 170 | */ 171 | ObservableCursor.prototype.observe = function (callbacks) { 172 | return this._cursor.observe(callbacks); 173 | }; 174 | /** 175 | * Watch a query. Receive callbacks as the result set changes. 176 | * Only the differences between the old and new documents are passed to the callbacks. 177 | * @param {Mongo.ObserveChangesCallbacks} callbacks - The callbacks object. 178 | * @return {Meteor.LiveQueryHandle} The array with the matching documents. 179 | */ 180 | ObservableCursor.prototype.observeChanges = function (callbacks) { 181 | return this._cursor.observeChanges(callbacks); 182 | }; 183 | ObservableCursor.prototype._runComplete = function () { 184 | this._countObserver.complete(); 185 | this._observers.forEach(function (observer) { 186 | observer.complete(); 187 | }); 188 | }; 189 | ObservableCursor.prototype._runNext = function (data) { 190 | this._countObserver.next(this._data.length); 191 | this._observers.forEach(function (observer) { 192 | observer.next(data); 193 | }); 194 | }; 195 | ObservableCursor.prototype._addedAt = function (doc, at, before) { 196 | this._data.splice(at, 0, doc); 197 | this._handleChange(); 198 | }; 199 | ObservableCursor.prototype._changedAt = function (doc, old, at) { 200 | this._data[at] = doc; 201 | this._handleChange(); 202 | }; 203 | ObservableCursor.prototype._removedAt = function (doc, at) { 204 | this._data.splice(at, 1); 205 | this._handleChange(); 206 | }; 207 | ObservableCursor.prototype._movedTo = function (doc, fromIndex, toIndex) { 208 | this._data.splice(fromIndex, 1); 209 | this._data.splice(toIndex, 0, doc); 210 | this._handleChange(); 211 | }; 212 | ObservableCursor.prototype._handleChange = function () { 213 | var _this = this; 214 | this._isDataInitinialized = true; 215 | this._zone.run(function () { 216 | _this._runNext(_this._data); 217 | }); 218 | }; 219 | ObservableCursor.prototype._observeCursor = function (cursor) { 220 | var _this = this; 221 | return gZone.run(function () { return cursor.observe({ 222 | addedAt: _this._addedAt.bind(_this), 223 | changedAt: _this._changedAt.bind(_this), 224 | movedTo: _this._movedTo.bind(_this), 225 | removedAt: _this._removedAt.bind(_this) 226 | }); }); 227 | }; 228 | return ObservableCursor; 229 | }(rxjs.Observable)); 230 | 231 | (function (MongoObservable) { 232 | 'use strict'; 233 | /** 234 | * Creates a new MongoObservable.Collection from an existing of predefined Mongo.Collection. 235 | * Use this feature to wrap existing collections such as Meteor.users. 236 | * @param {Mongo.Collection} collection - The collection. 237 | * @returns {MongoObservable.Collection} - Wrapped collection. 238 | * @static 239 | */ 240 | function fromExisting(collection) { 241 | return new MongoObservable.Collection(collection); 242 | } 243 | MongoObservable.fromExisting = fromExisting; 244 | /** 245 | * A class represents a MongoDB collection in the client side, wrapped with RxJS 246 | * Observables, so you can use it with your Angular 2 easier. 247 | * The wrapper has the same API as Mongo.Collection, only the "find" method returns 248 | * an ObservableCursor instead of regular Mongo.Cursor. 249 | * 250 | * T is a generic type - should be used with the type of the objects inside the collection. 251 | */ 252 | var Collection = /** @class */ (function () { 253 | /** 254 | * Creates a new Mongo.Collection instance wrapped with Observable features. 255 | * @param {String | Mongo.Collection} nameOrExisting - The name of the collection. If null, creates an 256 | * unmanaged (unsynchronized) local collection. If provided an instance of existing collection, will 257 | * create a wrapper for the existing Mongo.Collection. 258 | * @param {ConstructorOptions} options - Creation options. 259 | * @constructor 260 | */ 261 | function Collection(nameOrExisting, options) { 262 | if (nameOrExisting instanceof Mongo.Collection) { 263 | this._collection = nameOrExisting; 264 | } 265 | else { 266 | this._collection = new Mongo.Collection(nameOrExisting, options); 267 | } 268 | } 269 | Object.defineProperty(Collection.prototype, "collection", { 270 | /** 271 | * Returns the Mongo.Collection object that wrapped with the MongoObservable.Collection. 272 | * @returns {Mongo.Collection} The Collection instance 273 | */ 274 | get: function () { 275 | return this._collection; 276 | }, 277 | enumerable: true, 278 | configurable: true 279 | }); 280 | /** 281 | * Allow users to write directly to this collection from client code, subject to limitations you define. 282 | * 283 | * @returns {Boolean} 284 | */ 285 | Collection.prototype.allow = function (options) { 286 | return this._collection.allow(options); 287 | }; 288 | /** 289 | * Override allow rules. 290 | * 291 | * @returns {Boolean} 292 | */ 293 | Collection.prototype.deny = function (options) { 294 | return this._collection.deny(options); 295 | }; 296 | /** 297 | * Returns the Collection object corresponding to this collection from the npm 298 | * mongodb driver module which is wrapped by Mongo.Collection. 299 | * 300 | * @returns {Mongo.Collection} The Collection instance 301 | * 302 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-rawCollection|rawCollection on Meteor documentation} 303 | */ 304 | Collection.prototype.rawCollection = function () { 305 | return this._collection.rawCollection(); 306 | }; 307 | /** 308 | * Returns the Db object corresponding to this collection's database connection from the 309 | * npm mongodb driver module which is wrapped by Mongo.Collection. 310 | * 311 | * @returns {Mongo.Db} The Db instance 312 | * 313 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-rawDatabase|rawDatabase on Meteor documentation} 314 | */ 315 | Collection.prototype.rawDatabase = function () { 316 | return this._collection.rawDatabase(); 317 | }; 318 | /** 319 | * Insert a document in the collection. 320 | * 321 | * @param {T} doc - The document to insert. May not yet have an _id 322 | * attribute, in which case Meteor will generate one for you. 323 | * @returns {Observable} Observable which completes with the inserted ObjectId 324 | * 325 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-insert|insert on Meteor documentation} 326 | */ 327 | Collection.prototype.insert = function (doc) { 328 | var observers = []; 329 | var obs = this._createObservable(observers); 330 | this._collection.insert(doc, function (error, docId) { 331 | observers.forEach(function (observer) { 332 | error ? observer.error(error) : 333 | observer.next(docId); 334 | observer.complete(); 335 | }); 336 | }); 337 | return obs; 338 | }; 339 | /** 340 | * Remove documents from the collection. 341 | * 342 | * @param {Collection~MongoQuerySelector} selector - Specifies which documents to modify 343 | * @returns {Observable} Observable which completes with the number of affected rows 344 | * 345 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-remove|remove on Meteor documentation} 346 | */ 347 | Collection.prototype.remove = function (selector) { 348 | var observers = []; 349 | var obs = this._createObservable(observers); 350 | this._collection.remove(selector, function (error, removed) { 351 | observers.forEach(function (observer) { 352 | error ? observer.error(error) : 353 | observer.next(removed); 354 | observer.complete(); 355 | }); 356 | }); 357 | return obs; 358 | }; 359 | /** 360 | * Modify one or more documents in the collection. 361 | * 362 | * @param {Collection~MongoQuerySelector} selector - Specifies which documents to modify 363 | * @param {Modifier} modifier - Specifies how to modify the documents 364 | * @param {MongoUpdateOptions} options - Update options 365 | * first argument and, if no error, the number of affected documents as the second 366 | * @returns {Observable} Observable which completes with the number of affected rows 367 | * 368 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-update|update on Meteor documentation} 369 | */ 370 | Collection.prototype.update = function (selector, modifier, options) { 371 | var observers = []; 372 | var obs = this._createObservable(observers); 373 | this._collection.update(selector, modifier, options, function (error, updated) { 374 | observers.forEach(function (observer) { 375 | error ? observer.error(error) : 376 | observer.next(updated); 377 | observer.complete(); 378 | }); 379 | }); 380 | return obs; 381 | }; 382 | /** 383 | * Finds the first document that matches the selector, as ordered by sort and skip options. 384 | * 385 | * @param {Collection~MongoQuerySelector} selector - Specifies which documents to modify 386 | * @param {Modifier} modifier - Specifies how to modify the documents 387 | * @param {MongoUpsertOptions} options - Upsert options 388 | * first argument and, if no error, the number of affected documents as the second. 389 | * @returns {Observable<{numberAffected, insertedId}>} Observable which completes with an 390 | * Object that contain the keys numberAffected and insertedId. 391 | * 392 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-upsert|upsert on Meteor documentation} 393 | */ 394 | Collection.prototype.upsert = function (selector, modifier, options) { 395 | var observers = []; 396 | var obs = this._createObservable(observers); 397 | this._collection.upsert(selector, modifier, options, function (error, affected) { 398 | observers.forEach(function (observer) { 399 | error ? observer.error(error) : 400 | observer.next(affected); 401 | observer.complete(); 402 | }); 403 | }); 404 | return obs; 405 | }; 406 | /** 407 | * Method has the same notation as Mongo.Collection.find, only returns Observable. 408 | * 409 | * @param {Collection~MongoQuerySelector} selector - A query describing the documents to find 410 | * @param {Collection~MongoQueryOptions} options - Query options, such as sort, limit, etc. 411 | * @returns {ObservableCursor} RxJS Observable wrapped with Meteor features. 412 | * @example Using Angular2 Component 413 | * const MyCollection = MongoObservable.Collection("myCollection"); 414 | * 415 | * class MyComponent { 416 | * private myData: ObservableCursor; 417 | * 418 | * constructor() { 419 | * this.myData = MyCollection.find({}, {limit: 10}); 420 | * } 421 | * } 422 | * 423 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-find|find on Meteor documentation} 424 | */ 425 | Collection.prototype.find = function (selector, options) { 426 | var cursor = this._collection.find.apply(this._collection, arguments); 427 | return ObservableCursor.create(cursor); 428 | }; 429 | /** 430 | * Finds the first document that matches the selector, as ordered by sort and skip options. 431 | * 432 | * @param {Collection~MongoQuerySelector} selector - A query describing the documents to find 433 | * @param {Collection~MongoQueryOptions} options - Query options, such as sort, limit, etc. 434 | * @returns {any} The first object, or `undefined` in case of non-existing object. 435 | * 436 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-findOne|findOne on Meteor documentation} 437 | */ 438 | Collection.prototype.findOne = function (selector, options) { 439 | return this._collection.findOne.apply(this._collection, arguments); 440 | }; 441 | Collection.prototype._createObservable = function (observers) { 442 | return rxjs.Observable.create(function (observer) { 443 | observers.push(observer); 444 | return function () { 445 | removeObserver(observers, observer); 446 | }; 447 | }); 448 | }; 449 | return Collection; 450 | }()); 451 | MongoObservable.Collection = Collection; 452 | })(exports.MongoObservable || (exports.MongoObservable = {})); 453 | /** 454 | * An options object for MongoDB queries. 455 | * @typedef {Object} Collection~MongoQueryOptions 456 | * @property {Object} sort - Sort order (default: natural order) 457 | * @property {Number} skip - Number of results to skip at the beginning 458 | * @property {Object} fields - Dictionary of fields to return or exclude. 459 | * @property {Boolean} reactive - (Client only) Default true; pass false to disable reactivity 460 | * @property {Function} transform - Overrides transform on the Collection for this cursor. Pass null to disable transformation. 461 | */ 462 | /** 463 | * A MongoDB query selector representation. 464 | * @typedef {(Mongo.Selector|Mongo.ObjectID|string)} Collection~MongoQuerySelector 465 | */ 466 | /** 467 | * A MongoDB query options for upsert action 468 | * @typedef {Object} Collection~MongoUpsertOptions 469 | * @property {Boolean} multi - True to modify all matching documents; 470 | * false to only modify one of the matching documents (the default). 471 | */ 472 | /** 473 | * A MongoDB query options for update action 474 | * @typedef {Object} Collection~MongoUpdateOptions 475 | * @property {Boolean} multi - True to modify all matching documents; 476 | * @property {Boolean} upsert - True to use upsert logic. 477 | */ 478 | 479 | var liveSubscriptions = []; 480 | function throwInvalidCallback(method) { 481 | throw new Error("Invalid " + method + " arguments:\n your last param can't be a callback function,\n please remove it and use \".subscribe\" of the Observable!"); 482 | } 483 | /** 484 | * This is a class with static methods that wrap Meteor's API and return RxJS 485 | * Observables. The methods' signatures are the same as Meteor's, with the ] 486 | * exception that the callbacks are handled by Meteor-rxjs. Instead of 487 | * providing callbacks, you need to subscribe to the observables that are 488 | * returned. The methods that are wrapped in MeteorObservable are 489 | * [Meteor.call](https://docs.meteor.com/api/methods.html#Meteor-call), 490 | * [Meteor.autorun](https://docs.meteor.com/api/tracker.html#Tracker-autorun) 491 | * and [Meteor.subscribe](https://docs.meteor.com/api/pubsub.html#Meteor-subscribe). 492 | */ 493 | var MeteorObservable = /** @class */ (function () { 494 | function MeteorObservable() { 495 | } 496 | /** 497 | * Invokes a [Meteor Method](https://docs.meteor.com/api/methods.html) 498 | * defined on the server, passing any number of arguments. This method has 499 | * the same signature as 500 | * [Meteor.call](https://docs.meteor.com/api/methods.html#Meteor-call), only 501 | * without the callbacks: 502 | * MeteorObservable.call(name, [...args]) 503 | * 504 | * 505 | * @param {string} name - Name of the method in the Meteor server 506 | * @param {any} args - Parameters that will be forwarded to the method. 507 | * after the func call to initiate change detection. 508 | * @returns {Observable} - RxJS Observable, which completes when the 509 | * server returns a response. 510 | * 511 | * @example Example using Angular2 Component 512 | * class MyComponent { 513 | * constructor() { 514 | * 515 | * } 516 | * 517 | * doAction(payload) { 518 | * MeteorObservable.call("myData", payload).subscribe((response) => { 519 | * // Handle success and response from server! 520 | * }, (err) => { 521 | * // Handle error 522 | * }); 523 | * } 524 | * } 525 | */ 526 | MeteorObservable.call = function (name) { 527 | var args = []; 528 | for (var _i = 1; _i < arguments.length; _i++) { 529 | args[_i - 1] = arguments[_i]; 530 | } 531 | var lastParam = args[args.length - 1]; 532 | if (isMeteorCallbacks(lastParam)) { 533 | throwInvalidCallback('MeteorObservable.call'); 534 | } 535 | var zone = forkZone(); 536 | return rxjs.Observable.create(function (observer) { 537 | Meteor.call.apply(Meteor, [name].concat(args.concat([ 538 | function (error, result) { 539 | zone.run(function () { 540 | error ? observer.error(error) : 541 | observer.next(result); 542 | observer.complete(); 543 | }); 544 | } 545 | ]))); 546 | }); 547 | }; 548 | /** 549 | * When you subscribe to a collection, it tells the server to send records to 550 | * the client. This method has the same signature as 551 | * [Meteor.subscribe](https://docs.meteor.com/api/pubsub.html#Meteor-subscribe), 552 | * except without the callbacks again: 553 | * subscribe(name, [...args]) 554 | * 555 | * You can use this method from any Angular2 element - such as Component, 556 | * Pipe or Service. 557 | * 558 | * @param {string} name - Name of the publication in the Meteor server 559 | * @param {any} args - Parameters that will be forwarded to the publication. 560 | * after the func call to initiate change detection. 561 | * @returns {Observable} - RxJS Observable, which completes when the 562 | * subscription is ready. 563 | * 564 | * @example Example using Angular2 Service 565 | * class MyService { 566 | * private meteorSubscription: Observable; 567 | * 568 | * constructor() { 569 | * 570 | * } 571 | * 572 | * subscribeToData() { 573 | * this.meteorSubscription = MeteorObservable.subscribe("myData").subscribe(() => { 574 | * // Subscription is ready! 575 | * }); 576 | * } 577 | * 578 | * unsubscribeToData() { 579 | * this.meteorSubscription.unsubscribe(); 580 | * } 581 | * } 582 | * 583 | * @example Example using Angular2 Component 584 | * class MyComponent implements OnInit, OnDestroy { 585 | * private meteorSubscription: Observable; 586 | * 587 | * constructor() { 588 | * 589 | * } 590 | * 591 | * ngOnInit() { 592 | * this.meteorSubscription = MeteorObservable.subscribe("myData").subscribe(() => { 593 | * // Subscription is ready! 594 | * }); 595 | * } 596 | * 597 | * ngOnDestroy() { 598 | * this.meteorSubscription.unsubscribe(); 599 | * } 600 | * } 601 | * 602 | * @see {@link http://docs.meteor.com/api/pubsub.html|Publications in Meteor documentation} 603 | */ 604 | MeteorObservable.subscribe = function (name) { 605 | var args = []; 606 | for (var _i = 1; _i < arguments.length; _i++) { 607 | args[_i - 1] = arguments[_i]; 608 | } 609 | var lastParam = args[args.length - 1]; 610 | if (isMeteorCallbacks(lastParam)) { 611 | throwInvalidCallback('MeteorObservable.subscribe'); 612 | } 613 | var zone = forkZone(); 614 | var observers = []; 615 | var subscribe = function () { 616 | return Meteor.subscribe.apply(Meteor, [name].concat(args.concat([{ 617 | onError: function (error) { 618 | zone.run(function () { 619 | observers.forEach(function (observer) { return observer.error(error); }); 620 | }); 621 | }, 622 | onReady: function () { 623 | zone.run(function () { 624 | observers.forEach(function (observer) { return observer.next(); }); 625 | }); 626 | } 627 | } 628 | ]))); 629 | }; 630 | var subHandler = null; 631 | return rxjs.Observable.create(function (observer) { 632 | observers.push(observer); 633 | // Execute subscribe lazily. 634 | if (subHandler === null) { 635 | subHandler = subscribe(); 636 | if (liveSubscriptions.find(function (sub) { return sub === subHandler.subscriptionId; })) { 637 | // subscription already exists, call observer.next() since Meteor won't. 638 | observer.next(); 639 | } 640 | else { 641 | liveSubscriptions.push(subHandler.subscriptionId); 642 | } 643 | } 644 | return function () { 645 | removeObserver(observers, observer, function () { 646 | // remove subscription from liveSubscriptions list 647 | var i = liveSubscriptions.findIndex(function (sub) { return sub === subHandler.subscriptionId; }); 648 | if (i > -1) { 649 | liveSubscriptions.splice(i, 1); 650 | } 651 | subHandler.stop(); 652 | }); 653 | }; 654 | }); 655 | }; 656 | /** 657 | * Allows you to run a function every time there is a change is a reactive 658 | * data sources. This method has the same signature as 659 | * [Meteor.autorun](https://docs.meteor.com/api/tracker.html#Tracker-autorun), 660 | * only without the callback: 661 | * MeteorObservable.autorun() 662 | * 663 | * @returns {Observable} - RxJS Observable, which trigger the subscription callback 664 | * each time that Meteor Tracker detects a change. 665 | * @example Example using Angular2 Component 666 | * class MyComponent { 667 | * constructor() { 668 | * 669 | * } 670 | * 671 | * doAction(payload) { 672 | * MeteorObservable.autorun().subscribe(() => { 673 | * // Handle Tracker autorun change 674 | * }); 675 | * } 676 | * } 677 | */ 678 | MeteorObservable.autorun = function () { 679 | var zone = forkZone(); 680 | var observers = []; 681 | var autorun = function () { 682 | return Tracker.autorun(function (computation) { 683 | zone.run(function () { 684 | observers.forEach(function (observer) { return observer.next(computation); }); 685 | }); 686 | }); 687 | }; 688 | var handler = null; 689 | return rxjs.Observable.create(function (observer) { 690 | observers.push(observer); 691 | // Execute autorun lazily. 692 | if (handler === null) { 693 | handler = autorun(); 694 | } 695 | return function () { 696 | removeObserver(observers, observer, function () { return handler.stop(); }); 697 | }; 698 | }); 699 | }; 700 | return MeteorObservable; 701 | }()); 702 | 703 | var __extends$1 = (undefined && undefined.__extends) || (function () { 704 | var extendStatics = Object.setPrototypeOf || 705 | ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 706 | function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; 707 | return function (d, b) { 708 | extendStatics(d, b); 709 | function __() { this.constructor = d; } 710 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 711 | }; 712 | })(); 713 | var zoneOperator = function (zone) { return function (source) { return source.lift(new ZoneOperator(zone || getZone())); }; }; 714 | var ZoneOperator = /** @class */ (function () { 715 | function ZoneOperator(zone) { 716 | this.zone = zone; 717 | } 718 | ZoneOperator.prototype.call = function (subscriber, source) { 719 | return source._subscribe(new ZoneSubscriber(subscriber, this.zone)); 720 | }; 721 | return ZoneOperator; 722 | }()); 723 | var ZoneSubscriber = /** @class */ (function (_super) { 724 | __extends$1(ZoneSubscriber, _super); 725 | function ZoneSubscriber(destination, zone) { 726 | var _this = _super.call(this, destination) || this; 727 | _this.zone = zone; 728 | return _this; 729 | } 730 | ZoneSubscriber.prototype._next = function (value) { 731 | var _this = this; 732 | this.zone.run(function () { 733 | _this.destination.next(value); 734 | }); 735 | }; 736 | ZoneSubscriber.prototype._complete = function () { 737 | var _this = this; 738 | this.zone.run(function () { 739 | _this.destination.complete(); 740 | }); 741 | }; 742 | ZoneSubscriber.prototype._error = function (err) { 743 | var _this = this; 744 | this.zone.run(function () { 745 | _this.destination.error(err); 746 | }); 747 | }; 748 | return ZoneSubscriber; 749 | }(rxjs.Subscriber)); 750 | 751 | exports.MeteorObservable = MeteorObservable; 752 | exports.ObservableCursor = ObservableCursor; 753 | exports.zoneOperator = zoneOperator; 754 | 755 | Object.defineProperty(exports, '__esModule', { value: true }); 756 | 757 | }))); 758 | -------------------------------------------------------------------------------- /dist/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from './ObservableCollection'; 2 | export * from './MeteorObservable'; 3 | export * from './ObservableCursor'; 4 | export * from './zone'; 5 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | export * from './ObservableCollection'; 2 | export * from './MeteorObservable'; 3 | export * from './ObservableCursor'; 4 | export * from './zone'; 5 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /dist/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,QAAQ,CAAC"} -------------------------------------------------------------------------------- /dist/utils.d.ts: -------------------------------------------------------------------------------- 1 | import { Subscriber } from 'rxjs'; 2 | export declare type CallbacksObject = { 3 | onReady?: Function; 4 | onError?: Function; 5 | onStop?: Function; 6 | }; 7 | export declare type MeteorCallbacks = ((...args) => any) | CallbacksObject; 8 | export declare const subscribeEvents: string[]; 9 | export declare function isMeteorCallbacks(callbacks: any): boolean; 10 | export declare function isCallbacksObject(callbacks: any): boolean; 11 | export declare const g: any; 12 | export declare function forkZone(): any; 13 | export declare function getZone(): any; 14 | export declare function removeObserver(observers: Subscriber[], observer: Subscriber, onEmpty?: Function): void; 15 | export declare const gZone: any; 16 | -------------------------------------------------------------------------------- /dist/utils.js: -------------------------------------------------------------------------------- 1 | export var subscribeEvents = ['onReady', 'onError', 'onStop']; 2 | export function isMeteorCallbacks(callbacks) { 3 | return _.isFunction(callbacks) || isCallbacksObject(callbacks); 4 | } 5 | // Checks if callbacks of {@link CallbacksObject} type. 6 | export function isCallbacksObject(callbacks) { 7 | return callbacks && subscribeEvents.some(function (event) { 8 | return _.isFunction(callbacks[event]); 9 | }); 10 | } 11 | export var g = typeof global === 'object' ? global : 12 | typeof window === 'object' ? window : 13 | typeof self === 'object' ? self : undefined; 14 | var METEOR_RXJS_ZONE = 'meteor-rxjs-zone'; 15 | var fakeZone = { 16 | name: METEOR_RXJS_ZONE, 17 | run: function (func) { 18 | return func(); 19 | }, 20 | fork: function (spec) { 21 | return fakeZone; 22 | } 23 | }; 24 | export function forkZone() { 25 | if (g.Zone) { 26 | var zone = g.Zone.current; 27 | if (zone.name === METEOR_RXJS_ZONE) { 28 | zone = zone.parent || fakeZone; 29 | } 30 | return zone.fork({ name: METEOR_RXJS_ZONE }); 31 | } 32 | return fakeZone; 33 | } 34 | export function getZone() { 35 | if (g.Zone) { 36 | var zone = g.Zone.current; 37 | if (zone.name === METEOR_RXJS_ZONE) { 38 | return zone.parent; 39 | } 40 | return zone; 41 | } 42 | } 43 | export function removeObserver(observers, observer, onEmpty) { 44 | var index = observers.indexOf(observer); 45 | observers.splice(index, 1); 46 | if (observers.length === 0 && onEmpty) { 47 | onEmpty(); 48 | } 49 | } 50 | export var gZone = g.Zone ? g.Zone.current : fakeZone; 51 | //# sourceMappingURL=utils.js.map -------------------------------------------------------------------------------- /dist/utils.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAYA,MAAM,CAAC,IAAM,eAAe,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;AAEhE,MAAM,4BAA4B,SAAc;IAC9C,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,iBAAiB,CAAC,SAAS,CAAC,CAAC;AACjE,CAAC;AAED,uDAAuD;AACvD,MAAM,4BAA4B,SAAc;IAC9C,MAAM,CAAC,SAAS,IAAI,eAAe,CAAC,IAAI,CAAC,UAAC,KAAK;QAC7C,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;AACL,CAAC;AAGD,MAAM,CAAC,IAAM,CAAC,GACZ,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACnC,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACnC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AAElD,IAAM,gBAAgB,GAAG,kBAAkB,CAAC;AAE5C,IAAM,QAAQ,GAAG;IACf,IAAI,EAAE,gBAAgB;IACtB,GAAG,YAAC,IAAc;QAChB,MAAM,CAAC,IAAI,EAAE,CAAC;IAChB,CAAC;IACD,IAAI,YAAC,IAAS;QACZ,MAAM,CAAC,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC;AAEF,MAAM;IACJ,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACX,IAAI,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;QAC1B,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,gBAAgB,CAAC,CAAC,CAAC;YACnC,IAAI,GAAG,IAAI,CAAC,MAAM,IAAI,QAAQ,CAAC;QACjC,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAC/C,CAAC;IACD,MAAM,CAAC,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM;IACJ,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACX,IAAI,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;QAC1B,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,gBAAgB,CAAC,CAAC,CAAC;YACnC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;QACrB,CAAC;QACD,MAAM,CAAC,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,yBAAyB,SAA4B,EAC5B,QAAyB,EACzB,OAAkB;IAC/C,IAAI,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxC,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAC3B,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC;QACtC,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,IAAM,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC"} -------------------------------------------------------------------------------- /dist/zone.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Observable } from 'rxjs'; 3 | export declare const zoneOperator: (zone?: Zone) => (source: Observable) => Observable<{}>; 4 | -------------------------------------------------------------------------------- /dist/zone.js: -------------------------------------------------------------------------------- 1 | var __extends = (this && this.__extends) || (function () { 2 | var extendStatics = Object.setPrototypeOf || 3 | ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 4 | function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; 5 | return function (d, b) { 6 | extendStatics(d, b); 7 | function __() { this.constructor = d; } 8 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 9 | }; 10 | })(); 11 | import { Subscriber } from 'rxjs'; 12 | import { getZone } from './utils'; 13 | export var zoneOperator = function (zone) { return function (source) { return source.lift(new ZoneOperator(zone || getZone())); }; }; 14 | var ZoneOperator = /** @class */ (function () { 15 | function ZoneOperator(zone) { 16 | this.zone = zone; 17 | } 18 | ZoneOperator.prototype.call = function (subscriber, source) { 19 | return source._subscribe(new ZoneSubscriber(subscriber, this.zone)); 20 | }; 21 | return ZoneOperator; 22 | }()); 23 | var ZoneSubscriber = /** @class */ (function (_super) { 24 | __extends(ZoneSubscriber, _super); 25 | function ZoneSubscriber(destination, zone) { 26 | var _this = _super.call(this, destination) || this; 27 | _this.zone = zone; 28 | return _this; 29 | } 30 | ZoneSubscriber.prototype._next = function (value) { 31 | var _this = this; 32 | this.zone.run(function () { 33 | _this.destination.next(value); 34 | }); 35 | }; 36 | ZoneSubscriber.prototype._complete = function () { 37 | var _this = this; 38 | this.zone.run(function () { 39 | _this.destination.complete(); 40 | }); 41 | }; 42 | ZoneSubscriber.prototype._error = function (err) { 43 | var _this = this; 44 | this.zone.run(function () { 45 | _this.destination.error(err); 46 | }); 47 | }; 48 | return ZoneSubscriber; 49 | }(Subscriber)); 50 | //# sourceMappingURL=zone.js.map -------------------------------------------------------------------------------- /dist/zone.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"zone.js","sourceRoot":"","sources":["../src/zone.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,OAAO,EAA4B,UAAU,EAAE,MAAM,MAAM,CAAC;AAE5D,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,MAAM,CAAC,IAAM,YAAY,GAAG,UAAI,IAAW,IAAK,OAAA,UAAC,MAAqB,IAAK,OAAA,MAAM,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC,IAAI,IAAI,OAAO,EAAE,CAAC,CAAC,EAAhD,CAAgD,EAA3E,CAA2E,CAAC;AAG5H;IACE,sBAAoB,IAAU;QAAV,SAAI,GAAJ,IAAI,CAAM;IAC9B,CAAC;IAED,2BAAI,GAAJ,UAAK,UAAyB,EAAE,MAAW;QACzC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,cAAc,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACtE,CAAC;IACH,mBAAC;AAAD,CAAC,AAPD,IAOC;AAED;IAAgC,kCAAa;IAC3C,wBAAY,WAA0B,EAClB,IAAU;QAD9B,YAEE,kBAAM,WAAW,CAAC,SACnB;QAFmB,UAAI,GAAJ,IAAI,CAAM;;IAE9B,CAAC;IAES,8BAAK,GAAf,UAAgB,KAAQ;QAAxB,iBAIC;QAHC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;YACZ,KAAI,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;IACL,CAAC;IAES,kCAAS,GAAnB;QAAA,iBAIC;QAHC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;YACZ,KAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;QAC9B,CAAC,CAAC,CAAC;IACL,CAAC;IAES,+BAAM,GAAhB,UAAiB,GAAS;QAA1B,iBAIC;QAHC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;YACZ,KAAI,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;IACL,CAAC;IACH,qBAAC;AAAD,CAAC,AAvBD,CAAgC,UAAU,GAuBzC"} -------------------------------------------------------------------------------- /docs/MeteorObservable.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## MeteorObservable 4 | This is a class with static methods that wrap Meteor's API and return RxJS 5 | Observables. The methods' signatures are the same as Meteor's, with the ] 6 | exception that the callbacks are handled by Meteor-rxjs. Instead of 7 | providing callbacks, you need to subscribe to the observables that are 8 | returned. The methods that are wrapped in MeteorObservable are 9 | [Meteor.call](https://docs.meteor.com/api/methods.html#Meteor-call), 10 | [Meteor.autorun](https://docs.meteor.com/api/tracker.html#Tracker-autorun) 11 | and [Meteor.subscribe](https://docs.meteor.com/api/pubsub.html#Meteor-subscribe). 12 | 13 | **Kind**: global class 14 | 15 | * [MeteorObservable](#MeteorObservable) 16 | * [.call(name, ...args)](#MeteorObservable.call) ⇒ Observable.<T> 17 | * [.subscribe(name, ...args)](#MeteorObservable.subscribe) ⇒ Observable 18 | * [.autorun()](#MeteorObservable.autorun) ⇒ Observable.<T> 19 | 20 | 21 | 22 | ### MeteorObservable.call(name, ...args) ⇒ Observable.<T> 23 | Invokes a [Meteor Method](https://docs.meteor.com/api/methods.html) 24 | defined on the server, passing any number of arguments. This method has 25 | the same signature as 26 | [Meteor.call](https://docs.meteor.com/api/methods.html#Meteor-call), only 27 | without the callbacks: 28 | MeteorObservable.call(name, [...args]) 29 | 30 | **Kind**: static method of [MeteorObservable](#MeteorObservable) 31 | **Returns**: Observable.<T> - - RxJS Observable, which completes when the 32 | server returns a response. 33 | 34 | | Param | Type | Description | 35 | | --- | --- | --- | 36 | | name | string | Name of the method in the Meteor server | 37 | | ...args | any | Parameters that will be forwarded to the method. after the func call to initiate change detection. | 38 | 39 | **Example** *(Example using Angular2 Component)* 40 | ```js 41 | class MyComponent { 42 | constructor() { 43 | 44 | } 45 | 46 | doAction(payload) { 47 | MeteorObservable.call("myData", payload).subscribe((response) => { 48 | // Handle success and response from server! 49 | }, (err) => { 50 | // Handle error 51 | }); 52 | } 53 | } 54 | ``` 55 | 56 | 57 | ### MeteorObservable.subscribe(name, ...args) ⇒ Observable 58 | When you subscribe to a collection, it tells the server to send records to 59 | the client. This method has the same signature as 60 | [Meteor.subscribe](https://docs.meteor.com/api/pubsub.html#Meteor-subscribe), 61 | except without the callbacks again: 62 | subscribe(name, [...args]) 63 | 64 | You can use this method from any Angular2 element - such as Component, 65 | Pipe or Service. 66 | 67 | **Kind**: static method of [MeteorObservable](#MeteorObservable) 68 | **Returns**: Observable - - RxJS Observable, which completes when the 69 | subscription is ready. 70 | **See**: [Publications in Meteor documentation](http://docs.meteor.com/api/pubsub.html) 71 | 72 | | Param | Type | Description | 73 | | --- | --- | --- | 74 | | name | string | Name of the publication in the Meteor server | 75 | | ...args | any | Parameters that will be forwarded to the publication. after the func call to initiate change detection. | 76 | 77 | **Example** *(Example using Angular2 Service)* 78 | ```js 79 | class MyService { 80 | private meteorSubscription: Observable; 81 | 82 | constructor() { 83 | 84 | } 85 | 86 | subscribeToData() { 87 | this.meteorSubscription = MeteorObservable.subscribe("myData").subscribe(() => { 88 | // Subscription is ready! 89 | }); 90 | } 91 | 92 | unsubscribeToData() { 93 | this.meteorSubscription.unsubscribe(); 94 | } 95 | } 96 | 97 | 98 | ``` 99 | **Example** *(Example using Angular2 Component)* 100 | ```js 101 | class MyComponent implements OnInit, OnDestroy { 102 | private meteorSubscription: Observable; 103 | 104 | constructor() { 105 | 106 | } 107 | 108 | ngOnInit() { 109 | this.meteorSubscription = MeteorObservable.subscribe("myData").subscribe(() => { 110 | // Subscription is ready! 111 | }); 112 | } 113 | 114 | ngOnDestroy() { 115 | this.meteorSubscription.unsubscribe(); 116 | } 117 | } 118 | 119 | 120 | ``` 121 | 122 | 123 | ### MeteorObservable.autorun() ⇒ Observable.<T> 124 | Allows you to run a function every time there is a change is a reactive 125 | data sources. This method has the same signature as 126 | [Meteor.autorun](https://docs.meteor.com/api/tracker.html#Tracker-autorun), 127 | only without the callback: 128 | MeteorObservable.autorun() 129 | 130 | **Kind**: static method of [MeteorObservable](#MeteorObservable) 131 | **Returns**: Observable.<T> - - RxJS Observable, which trigger the subscription callback 132 | each time that Meteor Tracker detects a change. 133 | **Example** *(Example using Angular2 Component)* 134 | ```js 135 | class MyComponent { 136 | constructor() { 137 | 138 | } 139 | 140 | doAction(payload) { 141 | MeteorObservable.autorun().subscribe(() => { 142 | // Handle Tracker autorun change 143 | }); 144 | } 145 | } 146 | ``` 147 | -------------------------------------------------------------------------------- /docs/ObservableCollection.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Collection 4 | A class represents a MongoDB collection in the client side, wrapped with RxJS 5 | Observables, so you can use it with your Angular 2 easier. 6 | The wrapper has the same API as Mongo.Collection, only the "find" method returns 7 | an ObservableCursor instead of regular Mongo.Cursor. 8 | 9 | T is a generic type - should be used with the type of the objects inside the collection. 10 | 11 | **Kind**: global class 12 | 13 | * [Collection](#Collection) 14 | * [new Collection(nameOrExisting, options)](#new_Collection_new) 15 | * _instance_ 16 | * [.collection](#Collection+collection) ⇒ Mongo.Collection.<T> 17 | * [.allow()](#Collection+allow) ⇒ Boolean 18 | * [.deny()](#Collection+deny) ⇒ Boolean 19 | * [.rawCollection()](#Collection+rawCollection) ⇒ Mongo.Collection 20 | * [.rawDatabase()](#Collection+rawDatabase) ⇒ Mongo.Db 21 | * [.insert(doc)](#Collection+insert) ⇒ Observable.<string> 22 | * [.remove(selector)](#Collection+remove) ⇒ Observable.<Number> 23 | * [.update(selector, modifier, options)](#Collection+update) ⇒ Observable.<Number> 24 | * [.upsert(selector, modifier, options)](#Collection+upsert) ⇒ Observable.<{numberAffected, insertedId}> 25 | * [.find(selector, options)](#Collection+find) ⇒ ObservableCursor.<T> 26 | * [.findOne(selector, options)](#Collection+findOne) ⇒ any 27 | * _inner_ 28 | * [~MongoQueryOptions](#Collection..MongoQueryOptions) : Object 29 | * [~MongoQuerySelector](#Collection..MongoQuerySelector) : Mongo.Selector \| Mongo.ObjectID \| string 30 | * [~MongoUpsertOptions](#Collection..MongoUpsertOptions) : Object 31 | * [~MongoUpdateOptions](#Collection..MongoUpdateOptions) : Object 32 | 33 | 34 | 35 | ### new Collection(nameOrExisting, options) 36 | Creates a new Mongo.Collection instance wrapped with Observable features. 37 | 38 | 39 | | Param | Type | Description | 40 | | --- | --- | --- | 41 | | nameOrExisting | String \| Mongo.Collection | The name of the collection. If null, creates an unmanaged (unsynchronized) local collection. If provided an instance of existing collection, will create a wrapper for the existing Mongo.Collection. | 42 | | options | ConstructorOptions | Creation options. | 43 | 44 | 45 | 46 | ### collection.collection ⇒ Mongo.Collection.<T> 47 | Returns the Mongo.Collection object that wrapped with the MongoObservable.Collection. 48 | 49 | **Kind**: instance property of [Collection](#Collection) 50 | **Returns**: Mongo.Collection.<T> - The Collection instance 51 | 52 | 53 | ### collection.allow() ⇒ Boolean 54 | Allow users to write directly to this collection from client code, subject to limitations you define. 55 | 56 | **Kind**: instance method of [Collection](#Collection) 57 | 58 | 59 | ### collection.deny() ⇒ Boolean 60 | Override allow rules. 61 | 62 | **Kind**: instance method of [Collection](#Collection) 63 | 64 | 65 | ### collection.rawCollection() ⇒ Mongo.Collection 66 | Returns the Collection object corresponding to this collection from the npm 67 | mongodb driver module which is wrapped by Mongo.Collection. 68 | 69 | **Kind**: instance method of [Collection](#Collection) 70 | **Returns**: Mongo.Collection - The Collection instance 71 | **See**: [rawCollection on Meteor documentation](https://docs.meteor.com/api/collections.html#Mongo-Collection-rawCollection) 72 | 73 | 74 | ### collection.rawDatabase() ⇒ Mongo.Db 75 | Returns the Db object corresponding to this collection's database connection from the 76 | npm mongodb driver module which is wrapped by Mongo.Collection. 77 | 78 | **Kind**: instance method of [Collection](#Collection) 79 | **Returns**: Mongo.Db - The Db instance 80 | **See**: [rawDatabase on Meteor documentation](https://docs.meteor.com/api/collections.html#Mongo-Collection-rawDatabase) 81 | 82 | 83 | ### collection.insert(doc) ⇒ Observable.<string> 84 | Insert a document in the collection. 85 | 86 | **Kind**: instance method of [Collection](#Collection) 87 | **Returns**: Observable.<string> - Observable which completes with the inserted ObjectId 88 | **See**: [insert on Meteor documentation](https://docs.meteor.com/api/collections.html#Mongo-Collection-insert) 89 | 90 | | Param | Type | Description | 91 | | --- | --- | --- | 92 | | doc | T | The document to insert. May not yet have an _id attribute, in which case Meteor will generate one for you. | 93 | 94 | 95 | 96 | ### collection.remove(selector) ⇒ Observable.<Number> 97 | Remove documents from the collection. 98 | 99 | **Kind**: instance method of [Collection](#Collection) 100 | **Returns**: Observable.<Number> - Observable which completes with the number of affected rows 101 | **See**: [remove on Meteor documentation](https://docs.meteor.com/api/collections.html#Mongo-Collection-remove) 102 | 103 | | Param | Type | Description | 104 | | --- | --- | --- | 105 | | selector | [MongoQuerySelector](#Collection..MongoQuerySelector) | Specifies which documents to modify | 106 | 107 | 108 | 109 | ### collection.update(selector, modifier, options) ⇒ Observable.<Number> 110 | Modify one or more documents in the collection. 111 | 112 | **Kind**: instance method of [Collection](#Collection) 113 | **Returns**: Observable.<Number> - Observable which completes with the number of affected rows 114 | **See**: [update on Meteor documentation](https://docs.meteor.com/api/collections.html#Mongo-Collection-update) 115 | 116 | | Param | Type | Description | 117 | | --- | --- | --- | 118 | | selector | [MongoQuerySelector](#Collection..MongoQuerySelector) | Specifies which documents to modify | 119 | | modifier | Modifier | Specifies how to modify the documents | 120 | | options | MongoUpdateOptions | Update options first argument and, if no error, the number of affected documents as the second | 121 | 122 | 123 | 124 | ### collection.upsert(selector, modifier, options) ⇒ Observable.<{numberAffected, insertedId}> 125 | Finds the first document that matches the selector, as ordered by sort and skip options. 126 | 127 | **Kind**: instance method of [Collection](#Collection) 128 | **Returns**: Observable.<{numberAffected, insertedId}> - Observable which completes with an 129 | Object that contain the keys numberAffected and insertedId. 130 | **See**: [upsert on Meteor documentation](https://docs.meteor.com/api/collections.html#Mongo-Collection-upsert) 131 | 132 | | Param | Type | Description | 133 | | --- | --- | --- | 134 | | selector | [MongoQuerySelector](#Collection..MongoQuerySelector) | Specifies which documents to modify | 135 | | modifier | Modifier | Specifies how to modify the documents | 136 | | options | MongoUpsertOptions | Upsert options first argument and, if no error, the number of affected documents as the second. | 137 | 138 | 139 | 140 | ### collection.find(selector, options) ⇒ ObservableCursor.<T> 141 | Method has the same notation as Mongo.Collection.find, only returns Observable. 142 | 143 | **Kind**: instance method of [Collection](#Collection) 144 | **Returns**: ObservableCursor.<T> - RxJS Observable wrapped with Meteor features. 145 | **See**: [find on Meteor documentation](https://docs.meteor.com/api/collections.html#Mongo-Collection-find) 146 | 147 | | Param | Type | Description | 148 | | --- | --- | --- | 149 | | selector | [MongoQuerySelector](#Collection..MongoQuerySelector) | A query describing the documents to find | 150 | | options | [MongoQueryOptions](#Collection..MongoQueryOptions) | Query options, such as sort, limit, etc. | 151 | 152 | **Example** *(Using Angular2 Component)* 153 | ```js 154 | const MyCollection = MongoObservable.Collection("myCollection"); 155 | 156 | class MyComponent { 157 | private myData: ObservableCursor; 158 | 159 | constructor() { 160 | this.myData = MyCollection.find({}, {limit: 10}); 161 | } 162 | } 163 | ``` 164 | 165 | 166 | ### collection.findOne(selector, options) ⇒ any 167 | Finds the first document that matches the selector, as ordered by sort and skip options. 168 | 169 | **Kind**: instance method of [Collection](#Collection) 170 | **Returns**: any - The first object, or `undefined` in case of non-existing object. 171 | **See**: [findOne on Meteor documentation](https://docs.meteor.com/api/collections.html#Mongo-Collection-findOne) 172 | 173 | | Param | Type | Description | 174 | | --- | --- | --- | 175 | | selector | [MongoQuerySelector](#Collection..MongoQuerySelector) | A query describing the documents to find | 176 | | options | [MongoQueryOptions](#Collection..MongoQueryOptions) | Query options, such as sort, limit, etc. | 177 | 178 | 179 | 180 | ### Collection~MongoQueryOptions : Object 181 | An options object for MongoDB queries. 182 | 183 | **Kind**: inner typedef of [Collection](#Collection) 184 | **Properties** 185 | 186 | | Name | Type | Description | 187 | | --- | --- | --- | 188 | | sort | Object | Sort order (default: natural order) | 189 | | skip | Number | Number of results to skip at the beginning | 190 | | fields | Object | Dictionary of fields to return or exclude. | 191 | | reactive | Boolean | (Client only) Default true; pass false to disable reactivity | 192 | | transform | function | Overrides transform on the Collection for this cursor. Pass null to disable transformation. | 193 | 194 | 195 | 196 | ### Collection~MongoQuerySelector : Mongo.Selector \| Mongo.ObjectID \| string 197 | A MongoDB query selector representation. 198 | 199 | **Kind**: inner typedef of [Collection](#Collection) 200 | 201 | 202 | ### Collection~MongoUpsertOptions : Object 203 | A MongoDB query options for upsert action 204 | 205 | **Kind**: inner typedef of [Collection](#Collection) 206 | **Properties** 207 | 208 | | Name | Type | Description | 209 | | --- | --- | --- | 210 | | multi | Boolean | True to modify all matching documents; false to only modify one of the matching documents (the default). | 211 | 212 | 213 | 214 | ### Collection~MongoUpdateOptions : Object 215 | A MongoDB query options for update action 216 | 217 | **Kind**: inner typedef of [Collection](#Collection) 218 | **Properties** 219 | 220 | | Name | Type | Description | 221 | | --- | --- | --- | 222 | | multi | Boolean | True to modify all matching documents; | 223 | | upsert | Boolean | True to use upsert logic. | 224 | 225 | -------------------------------------------------------------------------------- /docs/ObservableCursor.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## ObservableCursor ⇐ Observable 4 | **Kind**: global class 5 | **Extends**: Observable 6 | 7 | * [ObservableCursor](#ObservableCursor) ⇐ Observable 8 | * [new ObservableCursor(cursor)](#new_ObservableCursor_new) 9 | * _instance_ 10 | * [.cursor](#ObservableCursor+cursor) ⇒ Mongo.Cursor.<T> 11 | * [.collectionCount()](#ObservableCursor+collectionCount) ⇒ Observable 12 | * [.stop()](#ObservableCursor+stop) 13 | * [.dispose()](#ObservableCursor+dispose) 14 | * [.fetch()](#ObservableCursor+fetch) ⇒ Array.<T> 15 | * [.observe(callbacks)](#ObservableCursor+observe) ⇒ Meteor.LiveQueryHandle 16 | * [.observeChanges(callbacks)](#ObservableCursor+observeChanges) ⇒ Meteor.LiveQueryHandle 17 | * _static_ 18 | * [.create(cursor)](#ObservableCursor.create) ⇒ [ObservableCursor](#ObservableCursor) 19 | 20 | 21 | 22 | ### new ObservableCursor(cursor) 23 | 24 | | Param | Type | Description | 25 | | --- | --- | --- | 26 | | cursor | Mongo.Cursor.<T> | The Mongo.Cursor to wrap. | 27 | 28 | 29 | 30 | ### observableCursor.cursor ⇒ Mongo.Cursor.<T> 31 | Returns the actual Mongo.Cursor that wrapped by current ObservableCursor instance. 32 | 33 | **Kind**: instance property of [ObservableCursor](#ObservableCursor) 34 | **Returns**: Mongo.Cursor.<T> - The actual MongoDB Cursor. 35 | 36 | 37 | ### observableCursor.collectionCount() ⇒ Observable 38 | A wrapper for Mongo.Cursor.count() method - returns an Observable of number, which 39 | triggers each time there is a change in the collection, and exposes the number of 40 | objects in the collection. 41 | 42 | **Kind**: instance method of [ObservableCursor](#ObservableCursor) 43 | **Returns**: Observable - Observable which trigger the callback when the 44 | count of the object changes. 45 | 46 | 47 | ### observableCursor.stop() 48 | Stops the observation on the cursor. 49 | 50 | **Kind**: instance method of [ObservableCursor](#ObservableCursor) 51 | 52 | 53 | ### observableCursor.dispose() 54 | Clears the Observable definition. 55 | Use this method only when the Observable is still cold, and there are no active subscriptions yet. 56 | 57 | **Kind**: instance method of [ObservableCursor](#ObservableCursor) 58 | 59 | 60 | ### observableCursor.fetch() ⇒ Array.<T> 61 | Return all matching documents as an Array. 62 | 63 | **Kind**: instance method of [ObservableCursor](#ObservableCursor) 64 | **Returns**: Array.<T> - The array with the matching documents. 65 | 66 | 67 | ### observableCursor.observe(callbacks) ⇒ Meteor.LiveQueryHandle 68 | Watch a query. Receive callbacks as the result set changes. 69 | 70 | **Kind**: instance method of [ObservableCursor](#ObservableCursor) 71 | **Returns**: Meteor.LiveQueryHandle - The array with the matching documents. 72 | 73 | | Param | Type | Description | 74 | | --- | --- | --- | 75 | | callbacks | Mongo.ObserveCallbacks | The callbacks object. | 76 | 77 | 78 | 79 | ### observableCursor.observeChanges(callbacks) ⇒ Meteor.LiveQueryHandle 80 | Watch a query. Receive callbacks as the result set changes. 81 | Only the differences between the old and new documents are passed to the callbacks. 82 | 83 | **Kind**: instance method of [ObservableCursor](#ObservableCursor) 84 | **Returns**: Meteor.LiveQueryHandle - The array with the matching documents. 85 | 86 | | Param | Type | Description | 87 | | --- | --- | --- | 88 | | callbacks | Mongo.ObserveChangesCallbacks | The callbacks object. | 89 | 90 | 91 | 92 | ### ObservableCursor.create(cursor) ⇒ [ObservableCursor](#ObservableCursor) 93 | Static method which creates an ObservableCursor from Mongo.Cursor. 94 | Use this to create an ObservableCursor object from an existing Mongo.Cursor. 95 | Prefer to create an Cursors from the ObservableCollection instance instead. 96 | 97 | **Kind**: static method of [ObservableCursor](#ObservableCursor) 98 | **Returns**: [ObservableCursor](#ObservableCursor) - Wrapped Cursor. 99 | 100 | | Param | Type | Description | 101 | | --- | --- | --- | 102 | | cursor | Mongo.Cursor.<T> | The Mongo.Cursor to wrap. | 103 | 104 | -------------------------------------------------------------------------------- /examples/angular2/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .meteor/local 3 | npm-debug.log 4 | typings 5 | .idea 6 | .meteor/local 7 | -------------------------------------------------------------------------------- /examples/angular2/.meteor/.finished-upgraders: -------------------------------------------------------------------------------- 1 | # This file contains information which helps Meteor properly upgrade your 2 | # app when you run 'meteor update'. You should check it into version control 3 | # with your project. 4 | 5 | notices-for-0.9.0 6 | notices-for-0.9.1 7 | 0.9.4-platform-file 8 | notices-for-facebook-graph-api-2 9 | 1.2.0-standard-minifiers-package 10 | 1.2.0-meteor-platform-split 11 | 1.2.0-cordova-changes 12 | 1.2.0-breaking-changes 13 | 1.3.0-split-minifiers-package 14 | 1.3.5-remove-old-dev-bundle-link 15 | 1.4.0-remove-old-dev-bundle-link 16 | 1.4.1-add-shell-server-package 17 | -------------------------------------------------------------------------------- /examples/angular2/.meteor/.gitignore: -------------------------------------------------------------------------------- 1 | dev_bundle 2 | local 3 | -------------------------------------------------------------------------------- /examples/angular2/.meteor/.id: -------------------------------------------------------------------------------- 1 | # This file contains a token that is unique to your project. 2 | # Check it into your repository along with the rest of this directory. 3 | # It can be used for purposes such as: 4 | # - ensuring you don't accidentally deploy one app on top of another 5 | # - providing package authors with aggregated statistics 6 | 7 | a4kqps1d5y31214lew0l 8 | -------------------------------------------------------------------------------- /examples/angular2/.meteor/packages: -------------------------------------------------------------------------------- 1 | # Meteor packages used by this project, one per line. 2 | # Check this file (and the other files in this directory) into your repository. 3 | # 4 | # 'meteor add' and 'meteor remove' will edit this file for you, 5 | # but you can also edit it by hand. 6 | 7 | meteor-base@1.0.4 # Packages every Meteor app needs to have 8 | mobile-experience@1.0.4 # Packages for a great mobile UX 9 | mongo@1.1.14 # The database Meteor supports right now 10 | reactive-var@1.0.11 # Reactive variable for tracker 11 | tracker@1.1.1 # Meteor's client-side reactive programming library 12 | 13 | standard-minifier-css@1.3.2 # CSS minifier run for production mode 14 | standard-minifier-js@1.2.1 # JS minifier run for production mode 15 | es5-shim@4.6.15 # ECMAScript 5 compatibility for older browsers. 16 | 17 | autopublish@1.0.7 # Publish all data to the clients (for prototyping) 18 | insecure@1.0.7 # Allow all DB writes from clients (for prototyping) 19 | angular2-compilers 20 | practicalmeteor:mocha 21 | xolvio:cleaner 22 | hwillson:stub-collections 23 | dispatch:mocha-phantomjs 24 | shell-server@0.2.1 25 | -------------------------------------------------------------------------------- /examples/angular2/.meteor/platforms: -------------------------------------------------------------------------------- 1 | server 2 | browser 3 | -------------------------------------------------------------------------------- /examples/angular2/.meteor/release: -------------------------------------------------------------------------------- 1 | METEOR@1.4.2 2 | -------------------------------------------------------------------------------- /examples/angular2/.meteor/versions: -------------------------------------------------------------------------------- 1 | allow-deny@1.0.5 2 | angular2-compilers@0.6.5 3 | autopublish@1.0.7 4 | autoupdate@1.3.12 5 | babel-compiler@6.13.0 6 | babel-runtime@0.1.13 7 | barbatus:css-compiler@0.3.4 8 | barbatus:scss-compiler@3.8.2 9 | barbatus:typescript@0.5.2 10 | barbatus:typescript-compiler@0.8.4 11 | barbatus:typescript-runtime@0.1.2 12 | base64@1.0.10 13 | binary-heap@1.0.10 14 | blaze@2.2.0 15 | blaze-tools@1.0.10 16 | boilerplate-generator@1.0.11 17 | caching-compiler@1.1.8 18 | caching-html-compiler@1.0.7 19 | callback-hook@1.0.10 20 | check@1.2.4 21 | coffeescript@1.11.1_2 22 | ddp@1.2.5 23 | ddp-client@1.3.2 24 | ddp-common@1.2.7 25 | ddp-server@1.3.11 26 | deps@1.0.12 27 | diff-sequence@1.0.7 28 | dispatch:mocha-phantomjs@0.1.7 29 | dispatch:phantomjs-tests@0.0.5 30 | ecmascript@0.5.9 31 | ecmascript-runtime@0.3.15 32 | ejson@1.0.13 33 | es5-shim@4.6.15 34 | fastclick@1.0.13 35 | geojson-utils@1.0.10 36 | hot-code-push@1.0.4 37 | html-tools@1.0.11 38 | htmljs@1.0.11 39 | http@1.2.10 40 | hwillson:stub-collections@1.0.2 41 | id-map@1.0.9 42 | insecure@1.0.7 43 | jquery@1.11.10 44 | launch-screen@1.1.0 45 | livedata@1.0.18 46 | logging@1.1.16 47 | meteor@1.6.0 48 | meteor-base@1.0.4 49 | minifier-css@1.2.15 50 | minifier-js@1.2.15 51 | minimongo@1.0.18 52 | mobile-experience@1.0.4 53 | mobile-status-bar@1.0.13 54 | modules@0.7.7 55 | modules-runtime@0.7.7 56 | mongo@1.1.14 57 | mongo-id@1.0.6 58 | npm-mongo@2.2.11_2 59 | observe-sequence@1.0.14 60 | ordered-dict@1.0.9 61 | practicalmeteor:chai@2.1.0_1 62 | practicalmeteor:loglevel@1.2.0_2 63 | practicalmeteor:mocha@2.4.5_6 64 | practicalmeteor:mocha-core@1.0.1 65 | practicalmeteor:sinon@1.14.1_2 66 | promise@0.8.8 67 | random@1.0.10 68 | reactive-var@1.0.11 69 | reload@1.1.11 70 | retry@1.0.9 71 | routepolicy@1.0.12 72 | shell-server@0.2.1 73 | spacebars@1.0.13 74 | spacebars-compiler@1.0.13 75 | standard-minifier-css@1.3.2 76 | standard-minifier-js@1.2.1 77 | templating@1.2.15 78 | templating-compiler@1.2.15 79 | templating-runtime@1.2.15 80 | templating-tools@1.0.5 81 | tmeasday:test-reporter-helpers@0.2.1 82 | tracker@1.1.1 83 | ui@1.0.12 84 | underscore@1.0.10 85 | urigo:static-html-compiler@0.1.8 86 | url@1.0.11 87 | webapp@1.3.12 88 | webapp-hashing@1.0.9 89 | xolvio:cleaner@0.3.1 90 | -------------------------------------------------------------------------------- /examples/angular2/both/collections/demo.collection.ts: -------------------------------------------------------------------------------- 1 | import { MongoObservable } from "meteor-rxjs"; 2 | import {Demo} from "../models/demo.model"; 3 | 4 | export const DemoCollection = new MongoObservable.Collection("demo-collection"); 5 | -------------------------------------------------------------------------------- /examples/angular2/both/models/demo.model.ts: -------------------------------------------------------------------------------- 1 | export interface Demo { 2 | name: string; 3 | age: number; 4 | } 5 | -------------------------------------------------------------------------------- /examples/angular2/client/imports/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 |

Angular 2 with Meteor-RxJS Example

3 |
4 | Items: 5 |
    6 |
  • 7 | {{ item._id }} 8 |
  • 9 |
10 |
11 | -------------------------------------------------------------------------------- /examples/angular2/client/imports/app/app.component.scss: -------------------------------------------------------------------------------- 1 | app { 2 | 3 | } -------------------------------------------------------------------------------- /examples/angular2/client/imports/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, ChangeDetectionStrategy} from "@angular/core"; 2 | import template from "./app.component.html"; 3 | import style from "./app.component.scss"; 4 | import {MeteorObservable} from "../../../../../src/MeteorObservable"; 5 | import {DemoCollection} from "../../../both/collections/demo.collection"; 6 | 7 | @Component({ 8 | selector: "app", 9 | template, 10 | styles: [ style ], 11 | changeDetection: ChangeDetectionStrategy.OnPush 12 | }) 13 | export class AppComponent { 14 | items = DemoCollection.find({}); 15 | 16 | constructor() { 17 | } 18 | } -------------------------------------------------------------------------------- /examples/angular2/client/imports/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from "@angular/core"; 2 | import { BrowserModule } from "@angular/platform-browser"; 3 | import { AppComponent } from "./app.component"; 4 | 5 | @NgModule({ 6 | // Components, Pipes, Directive 7 | declarations: [ 8 | AppComponent 9 | ], 10 | // Entry Components 11 | entryComponents: [ 12 | AppComponent 13 | ], 14 | // Providers 15 | providers: [ 16 | 17 | ], 18 | // Modules 19 | imports: [ 20 | BrowserModule 21 | ], 22 | // Main Component 23 | bootstrap: [ AppComponent ] 24 | }) 25 | export class AppModule { 26 | constructor() { 27 | 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/angular2/client/imports/app/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./app.component"; 2 | export * from "./app.module"; 3 | -------------------------------------------------------------------------------- /examples/angular2/client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Loading... 6 | 7 | -------------------------------------------------------------------------------- /examples/angular2/client/main.ts: -------------------------------------------------------------------------------- 1 | import "angular2-meteor-polyfills"; 2 | 3 | import { platformBrowserDynamic } from "@angular/platform-browser-dynamic"; 4 | import { enableProdMode } from "@angular/core"; 5 | import { Meteor } from "meteor/meteor"; 6 | import { AppModule } from "./imports/app"; 7 | 8 | enableProdMode(); 9 | 10 | Meteor.startup(() => { 11 | platformBrowserDynamic().bootstrapModule(AppModule); 12 | }); 13 | -------------------------------------------------------------------------------- /examples/angular2/client/styles/main.scss: -------------------------------------------------------------------------------- 1 | body, html { 2 | 3 | } -------------------------------------------------------------------------------- /examples/angular2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular2-meteor-rxjs-example", 3 | "private": true, 4 | "scripts": { 5 | "start": "meteor run", 6 | "start:prod": "meteor run --production", 7 | "build": "meteor build ./build/", 8 | "clear": "meteor reset", 9 | "meteor:update": "meteor update --all-packages", 10 | "test": "meteor test --driver-package practicalmeteor:mocha", 11 | "test:ci": "meteor test --once --driver-package dispatch:mocha-phantomjs" 12 | }, 13 | "devDependencies": { 14 | "@types/chai": "^3.4.33", 15 | "@types/mocha": "^2.2.32", 16 | "chai": "3.5.0", 17 | "chai-spies": "0.7.1" 18 | }, 19 | "dependencies": { 20 | "@angular/common": "2.1.2", 21 | "@angular/compiler": "2.1.2", 22 | "@angular/core": "2.1.2", 23 | "@angular/forms": "2.1.2", 24 | "@angular/platform-browser": "2.1.2", 25 | "@angular/platform-browser-dynamic": "2.1.2", 26 | "@angular/router": "3.1.2", 27 | "@types/meteor": "1.3.31", 28 | "angular2-meteor": "0.7.0", 29 | "angular2-meteor-polyfills": "0.1.1", 30 | "angular2-meteor-tests-polyfills": "0.0.2", 31 | "meteor-node-stubs": "0.2.3", 32 | "meteor-rxjs": "../../", 33 | "reflect-metadata": "0.1.8", 34 | "rxjs": "5.0.0-beta.12", 35 | "zone.js": "0.6.26" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /examples/angular2/server/imports/server-main/main.ts: -------------------------------------------------------------------------------- 1 | import {DemoCollection} from "../../../both/collections/demo.collection"; 2 | import {Demo} from "../../../both/models/demo.model"; 3 | 4 | export class Main { 5 | start(): void { 6 | this.initFakeData(); 7 | } 8 | 9 | initFakeData(): void { 10 | if (DemoCollection.find({}).cursor.count() === 0) { 11 | const data: Demo[] = [{ 12 | name: "Dotan", 13 | age: 25 14 | }, { 15 | name: "Liran", 16 | age: 26 17 | }, { 18 | name: "Uri", 19 | age: 30 20 | }]; 21 | data.forEach((obj: Demo) => { 22 | DemoCollection.insert(obj); 23 | }); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/angular2/server/main.ts: -------------------------------------------------------------------------------- 1 | import { Main } from "./imports/server-main/main"; 2 | 3 | const mainInstance = new Main(); 4 | mainInstance.start(); 5 | -------------------------------------------------------------------------------- /examples/angular2/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "es6", 6 | "dom" 7 | ], 8 | "module": "commonjs", 9 | "moduleResolution": "node", 10 | "experimentalDecorators": true, 11 | "emitDecoratorMetadata": true, 12 | "sourceMap": true 13 | }, 14 | "exclude": [ 15 | "node_modules" 16 | ], 17 | "files": [ 18 | "typings.d.ts" 19 | ], 20 | "compileOnSave": false, 21 | "angularCompilerOptions": { 22 | "genDir": "aot", 23 | "skipMetadataEmit": true 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/angular2/typings.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | 5 | declare module "*.html" { 6 | const template: string; 7 | export default template; 8 | } 9 | 10 | declare module "*.scss" { 11 | const style: string; 12 | export default style; 13 | } 14 | 15 | declare module "*.less" { 16 | const style: string; 17 | export default style; 18 | } 19 | 20 | declare module "*.css" { 21 | const style: string; 22 | export default style; 23 | } 24 | 25 | declare module "*.sass" { 26 | const style: string; 27 | export default style; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /generate-docs.sh: -------------------------------------------------------------------------------- 1 | rm -rf temp &> /dev/null 2 | mkdir temp &> /dev/null 3 | tsc --outDir ./temp/ --target es6 4 | $(npm bin)/jsdoc2md -l js --no-cache --source "$(cat ./temp/MeteorObservable.js)" > ./docs/MeteorObservable.md 5 | $(npm bin)/jsdoc2md -l js --no-cache --source "$(cat ./temp/ObservableCollection.js)" > ./docs/ObservableCollection.md 6 | $(npm bin)/jsdoc2md -l js --no-cache --source "$(cat ./temp/ObservableCursor.js)" > ./docs/ObservableCursor.md 7 | rm -rf temp &> /dev/null -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "meteor-rxjs", 3 | "version": "0.4.11", 4 | "description": "Use Meteor API in RxJS style", 5 | "keywords": [ 6 | "rxjs", 7 | "angular", 8 | "angular2", 9 | "meteor", 10 | "mongo", 11 | "typescript" 12 | ], 13 | "main": "dist/bundles/index.umd.js", 14 | "module": "dist/index.js", 15 | "typings": "dist/index.d.ts", 16 | "scripts": { 17 | "changelog": "$(npm bin)/conventional-changelog -p meteor-rxjs -i CHANGELOG.md -s -r 0", 18 | "docs": "./generate-docs.sh", 19 | "prebuild": "npm run lint", 20 | "build": "npm run build-only && npm run bundle && npm run docs", 21 | "prepublish": "npm run build", 22 | "build-only": "tsc || echo not ok", 23 | "pretest": "cd tests && rm -rf node_modules && npm install", 24 | "test-ci": "npm run pretest && cd tests && meteor test --once --driver-package dispatch:mocha-phantomjs", 25 | "test": "cd tests && meteor test --driver-package practicalmeteor:mocha", 26 | "lint": "tslint src/**/*.ts", 27 | "bundle": "rollup -i ./dist/index.js -o ./dist/bundles/index.umd.js -n meteor.rxjs -c rollup.config.js" 28 | }, 29 | "repository": { 30 | "type": "git", 31 | "url": "git+https://github.com/Urigo/mongo-rxjs-observable.git" 32 | }, 33 | "author": "Angular2-Meteor (https://github.com/Urigo/angular2-meteor)", 34 | "license": "MIT", 35 | "bugs": { 36 | "url": "https://github.com/Urigo/mongo-rxjs-observable/issues" 37 | }, 38 | "homepage": "http://www.angular-meteor.com", 39 | "peerDependencies": { 40 | "@types/meteor": "^1.4.6", 41 | "rxjs": "^5.4.3 || ^6.0.0" 42 | }, 43 | "devDependencies": { 44 | "@types/chai": "4.0.4", 45 | "@types/meteor": "1.4.14", 46 | "@types/mocha": "2.2.43", 47 | "@types/underscore": "1.8.3", 48 | "conventional-changelog": "1.1.0", 49 | "conventional-changelog-cli": "1.2.0", 50 | "jsdoc-to-markdown": "3.0.0", 51 | "rollup": "1.10.0", 52 | "rxjs": "6.0.0", 53 | "rxjs-compat": "6.0.0", 54 | "tslint": "5.7.0", 55 | "typescript": "2.7.2", 56 | "zone.js": "0.8.20" 57 | }, 58 | "greenkeeper": { 59 | "ignore": [ 60 | "rxjs" 61 | ] 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | output: { 3 | format: 'umd' 4 | }, 5 | globals: { 6 | 'rxjs': 'rxjs' 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /src/MeteorObservable.ts: -------------------------------------------------------------------------------- 1 | import { Observable , Subscriber } from 'rxjs'; 2 | 3 | import { isMeteorCallbacks, forkZone, removeObserver } from './utils'; 4 | 5 | let liveSubscriptions = []; 6 | 7 | function throwInvalidCallback(method: string) { 8 | throw new Error( 9 | `Invalid ${method} arguments: 10 | your last param can't be a callback function, 11 | please remove it and use ".subscribe" of the Observable!`); 12 | } 13 | 14 | /** 15 | * This is a class with static methods that wrap Meteor's API and return RxJS 16 | * Observables. The methods' signatures are the same as Meteor's, with the ] 17 | * exception that the callbacks are handled by Meteor-rxjs. Instead of 18 | * providing callbacks, you need to subscribe to the observables that are 19 | * returned. The methods that are wrapped in MeteorObservable are 20 | * [Meteor.call](https://docs.meteor.com/api/methods.html#Meteor-call), 21 | * [Meteor.autorun](https://docs.meteor.com/api/tracker.html#Tracker-autorun) 22 | * and [Meteor.subscribe](https://docs.meteor.com/api/pubsub.html#Meteor-subscribe). 23 | */ 24 | export class MeteorObservable { 25 | 26 | /** 27 | * Invokes a [Meteor Method](https://docs.meteor.com/api/methods.html) 28 | * defined on the server, passing any number of arguments. This method has 29 | * the same signature as 30 | * [Meteor.call](https://docs.meteor.com/api/methods.html#Meteor-call), only 31 | * without the callbacks: 32 | * MeteorObservable.call(name, [...args]) 33 | * 34 | * 35 | * @param {string} name - Name of the method in the Meteor server 36 | * @param {any} args - Parameters that will be forwarded to the method. 37 | * after the func call to initiate change detection. 38 | * @returns {Observable} - RxJS Observable, which completes when the 39 | * server returns a response. 40 | * 41 | * @example Example using Angular2 Component 42 | * class MyComponent { 43 | * constructor() { 44 | * 45 | * } 46 | * 47 | * doAction(payload) { 48 | * MeteorObservable.call("myData", payload).subscribe((response) => { 49 | * // Handle success and response from server! 50 | * }, (err) => { 51 | * // Handle error 52 | * }); 53 | * } 54 | * } 55 | */ 56 | public static call(name: string, ...args: any[]): Observable { 57 | const lastParam = args[args.length - 1]; 58 | 59 | if (isMeteorCallbacks(lastParam)) { 60 | throwInvalidCallback('MeteorObservable.call'); 61 | } 62 | 63 | let zone = forkZone(); 64 | 65 | return Observable.create((observer: Subscriber) => { 66 | Meteor.call(name, ...args.concat([ 67 | (error: Meteor.Error, result: T) => { 68 | zone.run(() => { 69 | error ? observer.error(error) : 70 | observer.next(result); 71 | observer.complete(); 72 | }); 73 | } 74 | ])); 75 | }); 76 | } 77 | 78 | /** 79 | * When you subscribe to a collection, it tells the server to send records to 80 | * the client. This method has the same signature as 81 | * [Meteor.subscribe](https://docs.meteor.com/api/pubsub.html#Meteor-subscribe), 82 | * except without the callbacks again: 83 | * subscribe(name, [...args]) 84 | * 85 | * You can use this method from any Angular2 element - such as Component, 86 | * Pipe or Service. 87 | * 88 | * @param {string} name - Name of the publication in the Meteor server 89 | * @param {any} args - Parameters that will be forwarded to the publication. 90 | * after the func call to initiate change detection. 91 | * @returns {Observable} - RxJS Observable, which completes when the 92 | * subscription is ready. 93 | * 94 | * @example Example using Angular2 Service 95 | * class MyService { 96 | * private meteorSubscription: Observable; 97 | * 98 | * constructor() { 99 | * 100 | * } 101 | * 102 | * subscribeToData() { 103 | * this.meteorSubscription = MeteorObservable.subscribe("myData").subscribe(() => { 104 | * // Subscription is ready! 105 | * }); 106 | * } 107 | * 108 | * unsubscribeToData() { 109 | * this.meteorSubscription.unsubscribe(); 110 | * } 111 | * } 112 | * 113 | * @example Example using Angular2 Component 114 | * class MyComponent implements OnInit, OnDestroy { 115 | * private meteorSubscription: Observable; 116 | * 117 | * constructor() { 118 | * 119 | * } 120 | * 121 | * ngOnInit() { 122 | * this.meteorSubscription = MeteorObservable.subscribe("myData").subscribe(() => { 123 | * // Subscription is ready! 124 | * }); 125 | * } 126 | * 127 | * ngOnDestroy() { 128 | * this.meteorSubscription.unsubscribe(); 129 | * } 130 | * } 131 | * 132 | * @see {@link http://docs.meteor.com/api/pubsub.html|Publications in Meteor documentation} 133 | */ 134 | public static subscribe(name: string, ...args: any[]): Observable { 135 | let lastParam = args[args.length - 1]; 136 | 137 | if (isMeteorCallbacks(lastParam)) { 138 | throwInvalidCallback('MeteorObservable.subscribe'); 139 | } 140 | 141 | let zone = forkZone(); 142 | let observers = []; 143 | let subscribe = () => { 144 | return Meteor.subscribe(name, ...args.concat([{ 145 | onError: (error: Meteor.Error) => { 146 | zone.run(() => { 147 | observers.forEach(observer => observer.error(error)); 148 | }); 149 | }, 150 | onReady: () => { 151 | zone.run(() => { 152 | observers.forEach(observer => observer.next()); 153 | }); 154 | } 155 | } 156 | ])); 157 | }; 158 | 159 | let subHandler = null; 160 | return Observable.create((observer: Subscriber) => { 161 | observers.push(observer); 162 | // Execute subscribe lazily. 163 | if (subHandler === null) { 164 | subHandler = subscribe(); 165 | if (liveSubscriptions.find(sub => sub === subHandler.subscriptionId)) { 166 | // subscription already exists, call observer.next() since Meteor won't. 167 | observer.next(); 168 | } else { 169 | liveSubscriptions.push(subHandler.subscriptionId); 170 | } 171 | } 172 | return () => { 173 | removeObserver(observers, 174 | observer, () => { 175 | // remove subscription from liveSubscriptions list 176 | let i = liveSubscriptions.findIndex( 177 | sub => sub === subHandler.subscriptionId 178 | ); 179 | 180 | if (i > -1) { 181 | liveSubscriptions.splice(i, 1); 182 | } 183 | 184 | subHandler.stop(); 185 | 186 | }); 187 | }; 188 | }); 189 | } 190 | 191 | /** 192 | * Allows you to run a function every time there is a change is a reactive 193 | * data sources. This method has the same signature as 194 | * [Meteor.autorun](https://docs.meteor.com/api/tracker.html#Tracker-autorun), 195 | * only without the callback: 196 | * MeteorObservable.autorun() 197 | * 198 | * @returns {Observable} - RxJS Observable, which trigger the subscription callback 199 | * each time that Meteor Tracker detects a change. 200 | * @example Example using Angular2 Component 201 | * class MyComponent { 202 | * constructor() { 203 | * 204 | * } 205 | * 206 | * doAction(payload) { 207 | * MeteorObservable.autorun().subscribe(() => { 208 | * // Handle Tracker autorun change 209 | * }); 210 | * } 211 | * } 212 | */ 213 | public static autorun(): Observable { 214 | let zone = forkZone(); 215 | let observers = []; 216 | let autorun = () => { 217 | return Tracker.autorun((computation: Tracker.Computation) => { 218 | zone.run(() => { 219 | observers.forEach(observer => observer.next(computation)); 220 | }); 221 | }); 222 | }; 223 | 224 | let handler = null; 225 | return Observable.create((observer: Subscriber) => { 226 | observers.push(observer); 227 | // Execute autorun lazily. 228 | if (handler === null) { 229 | handler = autorun(); 230 | } 231 | return () => { 232 | removeObserver(observers, 233 | observer, () => handler.stop()); 234 | }; 235 | }); 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /src/ObservableCollection.ts: -------------------------------------------------------------------------------- 1 | import { Observable , Subscriber } from 'rxjs'; 2 | 3 | import { ObservableCursor } from './ObservableCursor'; 4 | import { removeObserver } from './utils'; 5 | 6 | import Selector = Mongo.Selector; 7 | import ObjectID = Mongo.ObjectID; 8 | import SortSpecifier = Mongo.SortSpecifier; 9 | import FieldSpecifier = Mongo.FieldSpecifier; 10 | import Modifier = Mongo.Modifier; 11 | 12 | export module MongoObservable { 13 | 'use strict'; 14 | 15 | export interface ConstructorOptions { 16 | connection?: Object; 17 | idGeneration?: string; 18 | transform?: Function; 19 | } 20 | 21 | export interface AllowDenyOptionsObject { 22 | insert?: (userId: string, doc: T) => boolean; 23 | update?: (userId: string, doc: T, fieldNames: string[], modifier: any) => boolean; 24 | remove?: (userId: string, doc: T) => boolean; 25 | fetch?: string[]; 26 | transform?: Function; 27 | } 28 | 29 | /** 30 | * Creates a new MongoObservable.Collection from an existing of predefined Mongo.Collection. 31 | * Use this feature to wrap existing collections such as Meteor.users. 32 | * @param {Mongo.Collection} collection - The collection. 33 | * @returns {MongoObservable.Collection} - Wrapped collection. 34 | * @static 35 | */ 36 | export function fromExisting(collection: Mongo.Collection): MongoObservable.Collection { 37 | return new MongoObservable.Collection(collection); 38 | } 39 | 40 | /** 41 | * A class represents a MongoDB collection in the client side, wrapped with RxJS 42 | * Observables, so you can use it with your Angular 2 easier. 43 | * The wrapper has the same API as Mongo.Collection, only the "find" method returns 44 | * an ObservableCursor instead of regular Mongo.Cursor. 45 | * 46 | * T is a generic type - should be used with the type of the objects inside the collection. 47 | */ 48 | export class Collection { 49 | private _collection: Mongo.Collection; 50 | 51 | /** 52 | * Creates a new Mongo.Collection instance wrapped with Observable features. 53 | * @param {String | Mongo.Collection} nameOrExisting - The name of the collection. If null, creates an 54 | * unmanaged (unsynchronized) local collection. If provided an instance of existing collection, will 55 | * create a wrapper for the existing Mongo.Collection. 56 | * @param {ConstructorOptions} options - Creation options. 57 | * @constructor 58 | */ 59 | constructor(nameOrExisting: string | Mongo.Collection, 60 | options?: ConstructorOptions) { 61 | if (nameOrExisting instanceof Mongo.Collection) { 62 | this._collection = nameOrExisting; 63 | } else { 64 | this._collection = new Mongo.Collection(nameOrExisting, options); 65 | } 66 | } 67 | 68 | /** 69 | * Returns the Mongo.Collection object that wrapped with the MongoObservable.Collection. 70 | * @returns {Mongo.Collection} The Collection instance 71 | */ 72 | get collection(): Mongo.Collection { 73 | return this._collection; 74 | } 75 | 76 | /** 77 | * Allow users to write directly to this collection from client code, subject to limitations you define. 78 | * 79 | * @returns {Boolean} 80 | */ 81 | allow(options: AllowDenyOptionsObject): boolean { 82 | return this._collection.allow(options); 83 | } 84 | 85 | /** 86 | * Override allow rules. 87 | * 88 | * @returns {Boolean} 89 | */ 90 | deny(options: AllowDenyOptionsObject): boolean { 91 | return this._collection.deny(options); 92 | } 93 | 94 | /** 95 | * Returns the Collection object corresponding to this collection from the npm 96 | * mongodb driver module which is wrapped by Mongo.Collection. 97 | * 98 | * @returns {Mongo.Collection} The Collection instance 99 | * 100 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-rawCollection|rawCollection on Meteor documentation} 101 | */ 102 | rawCollection(): any { 103 | return this._collection.rawCollection(); 104 | } 105 | 106 | /** 107 | * Returns the Db object corresponding to this collection's database connection from the 108 | * npm mongodb driver module which is wrapped by Mongo.Collection. 109 | * 110 | * @returns {Mongo.Db} The Db instance 111 | * 112 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-rawDatabase|rawDatabase on Meteor documentation} 113 | */ 114 | rawDatabase(): any { 115 | return this._collection.rawDatabase(); 116 | } 117 | 118 | /** 119 | * Insert a document in the collection. 120 | * 121 | * @param {T} doc - The document to insert. May not yet have an _id 122 | * attribute, in which case Meteor will generate one for you. 123 | * @returns {Observable} Observable which completes with the inserted ObjectId 124 | * 125 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-insert|insert on Meteor documentation} 126 | */ 127 | insert(doc: T): Observable { 128 | let observers: Subscriber[] = []; 129 | let obs = this._createObservable(observers); 130 | 131 | this._collection.insert(doc, 132 | (error: Meteor.Error, docId: string) => { 133 | observers.forEach(observer => { 134 | error ? observer.error(error) : 135 | observer.next(docId); 136 | observer.complete(); 137 | }); 138 | }); 139 | return obs; 140 | } 141 | 142 | /** 143 | * Remove documents from the collection. 144 | * 145 | * @param {Collection~MongoQuerySelector} selector - Specifies which documents to modify 146 | * @returns {Observable} Observable which completes with the number of affected rows 147 | * 148 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-remove|remove on Meteor documentation} 149 | */ 150 | remove(selector: Selector | ObjectID | string): Observable { 151 | let observers: Subscriber[] = []; 152 | let obs = this._createObservable(observers); 153 | 154 | this._collection.remove(selector, 155 | (error: Meteor.Error, removed: number) => { 156 | observers.forEach(observer => { 157 | error ? observer.error(error) : 158 | observer.next(removed); 159 | observer.complete(); 160 | }); 161 | }); 162 | 163 | return obs; 164 | } 165 | 166 | /** 167 | * Modify one or more documents in the collection. 168 | * 169 | * @param {Collection~MongoQuerySelector} selector - Specifies which documents to modify 170 | * @param {Modifier} modifier - Specifies how to modify the documents 171 | * @param {MongoUpdateOptions} options - Update options 172 | * first argument and, if no error, the number of affected documents as the second 173 | * @returns {Observable} Observable which completes with the number of affected rows 174 | * 175 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-update|update on Meteor documentation} 176 | */ 177 | update(selector: Selector | ObjectID | string, 178 | modifier: Modifier, 179 | options?: { multi?: boolean; upsert?: boolean; }): Observable { 180 | let observers: Subscriber[] = []; 181 | let obs = this._createObservable(observers); 182 | 183 | this._collection.update(selector, modifier, options, 184 | (error: Meteor.Error, updated: number) => { 185 | observers.forEach(observer => { 186 | error ? observer.error(error) : 187 | observer.next(updated); 188 | observer.complete(); 189 | }); 190 | }); 191 | 192 | return obs; 193 | } 194 | 195 | /** 196 | * Finds the first document that matches the selector, as ordered by sort and skip options. 197 | * 198 | * @param {Collection~MongoQuerySelector} selector - Specifies which documents to modify 199 | * @param {Modifier} modifier - Specifies how to modify the documents 200 | * @param {MongoUpsertOptions} options - Upsert options 201 | * first argument and, if no error, the number of affected documents as the second. 202 | * @returns {Observable<{numberAffected, insertedId}>} Observable which completes with an 203 | * Object that contain the keys numberAffected and insertedId. 204 | * 205 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-upsert|upsert on Meteor documentation} 206 | */ 207 | upsert(selector: Selector | ObjectID | string, 208 | modifier: Modifier, 209 | options?: { multi?: boolean; }): Observable { 210 | let observers: Subscriber[] = []; 211 | let obs = this._createObservable(observers); 212 | 213 | this._collection.upsert(selector, modifier, options, 214 | (error: Meteor.Error, affected: number) => { 215 | observers.forEach(observer => { 216 | error ? observer.error(error) : 217 | observer.next(affected); 218 | observer.complete(); 219 | }); 220 | }); 221 | 222 | return obs; 223 | } 224 | 225 | /** 226 | * Method has the same notation as Mongo.Collection.find, only returns Observable. 227 | * 228 | * @param {Collection~MongoQuerySelector} selector - A query describing the documents to find 229 | * @param {Collection~MongoQueryOptions} options - Query options, such as sort, limit, etc. 230 | * @returns {ObservableCursor} RxJS Observable wrapped with Meteor features. 231 | * @example Using Angular2 Component 232 | * const MyCollection = MongoObservable.Collection("myCollection"); 233 | * 234 | * class MyComponent { 235 | * private myData: ObservableCursor; 236 | * 237 | * constructor() { 238 | * this.myData = MyCollection.find({}, {limit: 10}); 239 | * } 240 | * } 241 | * 242 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-find|find on Meteor documentation} 243 | */ 244 | find(selector?: Selector | ObjectID | string, options?: { 245 | sort?: SortSpecifier; 246 | skip?: number; 247 | limit?: number; 248 | fields?: FieldSpecifier; 249 | reactive?: boolean; 250 | transform?: Function; 251 | }): ObservableCursor { 252 | const cursor = this._collection.find.apply( 253 | this._collection, arguments); 254 | return ObservableCursor.create(cursor); 255 | } 256 | 257 | /** 258 | * Finds the first document that matches the selector, as ordered by sort and skip options. 259 | * 260 | * @param {Collection~MongoQuerySelector} selector - A query describing the documents to find 261 | * @param {Collection~MongoQueryOptions} options - Query options, such as sort, limit, etc. 262 | * @returns {any} The first object, or `undefined` in case of non-existing object. 263 | * 264 | * @see {@link https://docs.meteor.com/api/collections.html#Mongo-Collection-findOne|findOne on Meteor documentation} 265 | */ 266 | findOne(selector?: Selector | ObjectID | string, options?: { 267 | sort?: SortSpecifier; 268 | skip?: number; 269 | fields?: FieldSpecifier; 270 | reactive?: boolean; 271 | transform?: Function; 272 | }): T { 273 | return this._collection.findOne.apply( 274 | this._collection, arguments); 275 | } 276 | 277 | private _createObservable(observers: Subscriber[]) { 278 | return Observable.create((observer: Subscriber) => { 279 | observers.push(observer); 280 | return () => { 281 | removeObserver(observers, observer); 282 | }; 283 | }); 284 | } 285 | } 286 | } 287 | 288 | 289 | /** 290 | * An options object for MongoDB queries. 291 | * @typedef {Object} Collection~MongoQueryOptions 292 | * @property {Object} sort - Sort order (default: natural order) 293 | * @property {Number} skip - Number of results to skip at the beginning 294 | * @property {Object} fields - Dictionary of fields to return or exclude. 295 | * @property {Boolean} reactive - (Client only) Default true; pass false to disable reactivity 296 | * @property {Function} transform - Overrides transform on the Collection for this cursor. Pass null to disable transformation. 297 | */ 298 | 299 | /** 300 | * A MongoDB query selector representation. 301 | * @typedef {(Mongo.Selector|Mongo.ObjectID|string)} Collection~MongoQuerySelector 302 | */ 303 | 304 | /** 305 | * A MongoDB query options for upsert action 306 | * @typedef {Object} Collection~MongoUpsertOptions 307 | * @property {Boolean} multi - True to modify all matching documents; 308 | * false to only modify one of the matching documents (the default). 309 | */ 310 | 311 | /** 312 | * A MongoDB query options for update action 313 | * @typedef {Object} Collection~MongoUpdateOptions 314 | * @property {Boolean} multi - True to modify all matching documents; 315 | * @property {Boolean} upsert - True to use upsert logic. 316 | */ 317 | -------------------------------------------------------------------------------- /src/ObservableCursor.ts: -------------------------------------------------------------------------------- 1 | import { Observable , Subscriber , Subject } from 'rxjs'; 2 | 3 | import { gZone, forkZone, removeObserver } from './utils'; 4 | 5 | declare let _; 6 | 7 | export class ObservableCursor extends Observable { 8 | private _zone: Zone; 9 | private _data: Array = []; 10 | private _cursor: Mongo.Cursor; 11 | private _hCursor: Meteor.LiveQueryHandle; 12 | private _observers: Subscriber[] = []; 13 | private _countObserver: Subject = new Subject(); 14 | private _isDataInitinialized = false; 15 | 16 | /** 17 | * Static method which creates an ObservableCursor from Mongo.Cursor. 18 | * Use this to create an ObservableCursor object from an existing Mongo.Cursor. 19 | * Prefer to create an Cursors from the ObservableCollection instance instead. 20 | * 21 | * @param {Mongo.Cursor} cursor - The Mongo.Cursor to wrap. 22 | * @static 23 | * @returns {ObservableCursor} Wrapped Cursor. 24 | */ 25 | static create(cursor: Mongo.Cursor): ObservableCursor { 26 | return new ObservableCursor(cursor); 27 | } 28 | 29 | /** 30 | * @constructor 31 | * @extends Observable 32 | * @param {Mongo.Cursor} cursor - The Mongo.Cursor to wrap. 33 | */ 34 | constructor(cursor: Mongo.Cursor) { 35 | super((observer: Subscriber) => { 36 | this._observers.push(observer); 37 | 38 | if (!this._hCursor) { 39 | this._hCursor = this._observeCursor(cursor); 40 | } 41 | 42 | Meteor.setTimeout(() => { 43 | if (this._isDataInitinialized) { 44 | observer.next(this._data); 45 | } else if (cursor.count() === 0) { 46 | this._isDataInitinialized = true; 47 | observer.next(this._data); 48 | } 49 | }, 0); 50 | 51 | return () => { 52 | removeObserver(this._observers, 53 | observer, () => this.stop()); 54 | }; 55 | }); 56 | 57 | _.extend(this, _.omit(cursor, 'count', 'map')); 58 | 59 | this._cursor = cursor; 60 | this._zone = forkZone(); 61 | } 62 | 63 | /** 64 | * Returns the actual Mongo.Cursor that wrapped by current ObservableCursor instance. 65 | * @return {Mongo.Cursor} The actual MongoDB Cursor. 66 | */ 67 | get cursor(): Mongo.Cursor { 68 | return this._cursor; 69 | } 70 | 71 | /** 72 | * A wrapper for Mongo.Cursor.count() method - returns an Observable of number, which 73 | * triggers each time there is a change in the collection, and exposes the number of 74 | * objects in the collection. 75 | * @returns {Observable} Observable which trigger the callback when the 76 | * count of the object changes. 77 | */ 78 | collectionCount(): Observable { 79 | return this._countObserver.asObservable(); 80 | } 81 | 82 | /** 83 | * Stops the observation on the cursor. 84 | */ 85 | stop() { 86 | this._zone.run(() => { 87 | this._runComplete(); 88 | }); 89 | 90 | if (this._hCursor) { 91 | this._hCursor.stop(); 92 | } 93 | 94 | this._data = []; 95 | this._hCursor = null; 96 | } 97 | 98 | /** 99 | * Clears the Observable definition. 100 | * Use this method only when the Observable is still cold, and there are no active subscriptions yet. 101 | */ 102 | dispose() { 103 | this._observers = null; 104 | this._cursor = null; 105 | } 106 | 107 | /** 108 | * Return all matching documents as an Array. 109 | * 110 | * @return {Array} The array with the matching documents. 111 | */ 112 | fetch(): Array { 113 | return this._cursor.fetch(); 114 | } 115 | 116 | /** 117 | * Watch a query. Receive callbacks as the result set changes. 118 | * @param {Mongo.ObserveCallbacks} callbacks - The callbacks object. 119 | * @return {Meteor.LiveQueryHandle} The array with the matching documents. 120 | */ 121 | observe(callbacks: Object): Meteor.LiveQueryHandle { 122 | return this._cursor.observe(callbacks); 123 | } 124 | 125 | /** 126 | * Watch a query. Receive callbacks as the result set changes. 127 | * Only the differences between the old and new documents are passed to the callbacks. 128 | * @param {Mongo.ObserveChangesCallbacks} callbacks - The callbacks object. 129 | * @return {Meteor.LiveQueryHandle} The array with the matching documents. 130 | */ 131 | observeChanges(callbacks: Object): Meteor.LiveQueryHandle { 132 | return this._cursor.observeChanges(callbacks); 133 | } 134 | 135 | _runComplete() { 136 | this._countObserver.complete(); 137 | 138 | this._observers.forEach(observer => { 139 | observer.complete(); 140 | }); 141 | } 142 | 143 | _runNext(data: Array) { 144 | this._countObserver.next(this._data.length); 145 | 146 | this._observers.forEach(observer => { 147 | observer.next(data); 148 | }); 149 | } 150 | 151 | _addedAt(doc, at, before) { 152 | this._data.splice(at, 0, doc); 153 | this._handleChange(); 154 | } 155 | 156 | _changedAt(doc, old, at) { 157 | this._data[at] = doc; 158 | this._handleChange(); 159 | } 160 | 161 | _removedAt(doc, at) { 162 | this._data.splice(at, 1); 163 | this._handleChange(); 164 | } 165 | 166 | _movedTo(doc, fromIndex, toIndex) { 167 | this._data.splice(fromIndex, 1); 168 | this._data.splice(toIndex, 0, doc); 169 | this._handleChange(); 170 | } 171 | 172 | _handleChange() { 173 | this._isDataInitinialized = true; 174 | 175 | this._zone.run(() => { 176 | this._runNext(this._data); 177 | }); 178 | } 179 | 180 | _observeCursor(cursor: Mongo.Cursor) { 181 | return gZone.run( 182 | () => cursor.observe({ 183 | addedAt: this._addedAt.bind(this), 184 | changedAt: this._changedAt.bind(this), 185 | movedTo: this._movedTo.bind(this), 186 | removedAt: this._removedAt.bind(this) 187 | })); 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ObservableCollection'; 2 | export * from './MeteorObservable'; 3 | export * from './ObservableCursor'; 4 | export * from './zone'; 5 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import { Subscriber } from 'rxjs'; 2 | 3 | declare let _; 4 | 5 | export declare type CallbacksObject = { 6 | onReady?: Function; 7 | onError?: Function; 8 | onStop?: Function; 9 | }; 10 | 11 | export declare type MeteorCallbacks = ((...args) => any) | CallbacksObject; 12 | 13 | export const subscribeEvents = ['onReady', 'onError', 'onStop']; 14 | 15 | export function isMeteorCallbacks(callbacks: any): boolean { 16 | return _.isFunction(callbacks) || isCallbacksObject(callbacks); 17 | } 18 | 19 | // Checks if callbacks of {@link CallbacksObject} type. 20 | export function isCallbacksObject(callbacks: any): boolean { 21 | return callbacks && subscribeEvents.some((event) => { 22 | return _.isFunction(callbacks[event]); 23 | }); 24 | } 25 | 26 | declare const global; 27 | export const g = 28 | typeof global === 'object' ? global : 29 | typeof window === 'object' ? window : 30 | typeof self === 'object' ? self : undefined; 31 | 32 | const METEOR_RXJS_ZONE = 'meteor-rxjs-zone'; 33 | 34 | const fakeZone = { 35 | name: METEOR_RXJS_ZONE, 36 | run(func: Function) { 37 | return func(); 38 | }, 39 | fork(spec: any) { 40 | return fakeZone; 41 | } 42 | }; 43 | 44 | export function forkZone() { 45 | if (g.Zone) { 46 | let zone = g.Zone.current; 47 | if (zone.name === METEOR_RXJS_ZONE) { 48 | zone = zone.parent || fakeZone; 49 | } 50 | return zone.fork({ name: METEOR_RXJS_ZONE }); 51 | } 52 | return fakeZone; 53 | } 54 | 55 | export function getZone() { 56 | if (g.Zone) { 57 | let zone = g.Zone.current; 58 | if (zone.name === METEOR_RXJS_ZONE) { 59 | return zone.parent; 60 | } 61 | return zone; 62 | } 63 | } 64 | 65 | export function removeObserver(observers: Subscriber[], 66 | observer: Subscriber, 67 | onEmpty?: Function) { 68 | let index = observers.indexOf(observer); 69 | observers.splice(index, 1); 70 | if (observers.length === 0 && onEmpty) { 71 | onEmpty(); 72 | } 73 | } 74 | 75 | export const gZone = g.Zone ? g.Zone.current : fakeZone; 76 | -------------------------------------------------------------------------------- /src/zone.ts: -------------------------------------------------------------------------------- 1 | import { Observable , Operator , Subscriber } from 'rxjs'; 2 | 3 | import { getZone } from './utils'; 4 | 5 | export const zoneOperator = (zone?: Zone) => (source: Observable) => source.lift(new ZoneOperator(zone || getZone())); 6 | 7 | 8 | class ZoneOperator implements Operator { 9 | constructor(private zone: Zone) { 10 | } 11 | 12 | call(subscriber: Subscriber, source: any) { 13 | return source._subscribe(new ZoneSubscriber(subscriber, this.zone)); 14 | } 15 | } 16 | 17 | class ZoneSubscriber extends Subscriber { 18 | constructor(destination: Subscriber, 19 | private zone: Zone) { 20 | super(destination); 21 | } 22 | 23 | protected _next(value: T) { 24 | this.zone.run(() => { 25 | this.destination.next(value); 26 | }); 27 | } 28 | 29 | protected _complete() { 30 | this.zone.run(() => { 31 | this.destination.complete(); 32 | }); 33 | } 34 | 35 | protected _error(err?: any) { 36 | this.zone.run(() => { 37 | this.destination.error(err); 38 | }); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/.meteor/.finished-upgraders: -------------------------------------------------------------------------------- 1 | # This file contains information which helps Meteor properly upgrade your 2 | # app when you run 'meteor update'. You should check it into version control 3 | # with your project. 4 | 5 | notices-for-0.9.0 6 | notices-for-0.9.1 7 | 0.9.4-platform-file 8 | notices-for-facebook-graph-api-2 9 | 1.2.0-standard-minifiers-package 10 | 1.2.0-meteor-platform-split 11 | 1.2.0-cordova-changes 12 | 1.2.0-breaking-changes 13 | 1.3.0-split-minifiers-package 14 | 1.4.0-remove-old-dev-bundle-link 15 | 1.4.1-add-shell-server-package 16 | 1.4.3-split-account-service-packages 17 | 1.5-add-dynamic-import-package 18 | -------------------------------------------------------------------------------- /tests/.meteor/.gitignore: -------------------------------------------------------------------------------- 1 | local 2 | -------------------------------------------------------------------------------- /tests/.meteor/.id: -------------------------------------------------------------------------------- 1 | # This file contains a token that is unique to your project. 2 | # Check it into your repository along with the rest of this directory. 3 | # It can be used for purposes such as: 4 | # - ensuring you don't accidentally deploy one app on top of another 5 | # - providing package authors with aggregated statistics 6 | 7 | 1bh2ud7roqxsj1ibpje 8 | -------------------------------------------------------------------------------- /tests/.meteor/packages: -------------------------------------------------------------------------------- 1 | # Meteor packages used by this project, one per line. 2 | # Check this file (and the other files in this directory) into your repository. 3 | # 4 | # 'meteor add' and 'meteor remove' will edit this file for you, 5 | # but you can also edit it by hand. 6 | 7 | meteor-base@1.1.0 # Packages every Meteor app needs to have 8 | mobile-experience@1.0.4 # Packages for a great mobile UX 9 | mongo@1.2.0 # The database Meteor supports right now 10 | reactive-var@1.0.11 # Reactive variable for tracker 11 | jquery@1.11.10 # Helpful client-side library 12 | tracker@1.1.3 # Meteor's client-side reactive programming library 13 | 14 | standard-minifier-css@1.3.4 # CSS minifier run for production mode 15 | standard-minifier-js@2.1.1 # JS minifier run for production mode 16 | es5-shim@4.6.15 # ECMAScript 5 compatibility for older browsers. 17 | ecmascript@0.8.2 # Enable ECMAScript2015+ syntax in app code 18 | 19 | insecure@1.0.7 # Allow all DB writes from clients (for prototyping) 20 | angular2-compilers 21 | practicalmeteor:sinon 22 | practicalmeteor:chai 23 | dispatch:mocha-phantomjs 24 | dburles:factory 25 | xolvio:cleaner 26 | shell-server@0.2.4 27 | practicalmeteor:mocha 28 | dynamic-import 29 | -------------------------------------------------------------------------------- /tests/.meteor/platforms: -------------------------------------------------------------------------------- 1 | server 2 | browser 3 | -------------------------------------------------------------------------------- /tests/.meteor/release: -------------------------------------------------------------------------------- 1 | METEOR@1.5.2 2 | -------------------------------------------------------------------------------- /tests/.meteor/versions: -------------------------------------------------------------------------------- 1 | allow-deny@1.0.6 2 | angular2-compilers@0.6.6 3 | autoupdate@1.3.12 4 | babel-compiler@6.20.0 5 | babel-runtime@1.0.1 6 | barbatus:caching-compiler@1.1.9 7 | barbatus:css-compiler@0.4.1 8 | barbatus:scss-compiler@3.8.3 9 | barbatus:typescript@0.6.11 10 | barbatus:typescript-compiler@0.9.11 11 | barbatus:typescript-runtime@1.0.2 12 | base64@1.0.10 13 | binary-heap@1.0.10 14 | blaze@2.3.2 15 | blaze-tools@1.0.10 16 | boilerplate-generator@1.2.0 17 | caching-compiler@1.1.9 18 | caching-html-compiler@1.1.2 19 | callback-hook@1.0.10 20 | check@1.2.5 21 | coffeescript@1.12.7_1 22 | coffeescript-compiler@1.12.7_1 23 | dburles:factory@1.1.0 24 | ddp@1.3.0 25 | ddp-client@2.1.0 26 | ddp-common@1.2.9 27 | ddp-server@2.0.0 28 | deps@1.0.12 29 | diff-sequence@1.0.7 30 | dispatch:mocha-phantomjs@0.1.9 31 | dispatch:phantomjs-tests@0.0.7 32 | dynamic-import@0.1.1 33 | ecmascript@0.8.2 34 | ecmascript-runtime@0.4.1 35 | ecmascript-runtime-client@0.4.3 36 | ecmascript-runtime-server@0.4.1 37 | ejson@1.0.14 38 | es5-shim@4.6.15 39 | fastclick@1.0.13 40 | geojson-utils@1.0.10 41 | hot-code-push@1.0.4 42 | html-tools@1.0.11 43 | htmljs@1.0.11 44 | http@1.2.12 45 | id-map@1.0.9 46 | insecure@1.0.7 47 | jquery@1.11.10 48 | launch-screen@1.1.1 49 | livedata@1.0.18 50 | logging@1.1.17 51 | meteor@1.7.1 52 | meteor-base@1.1.0 53 | minifier-css@1.2.16 54 | minifier-js@2.1.3 55 | minimongo@1.3.0 56 | mobile-experience@1.0.4 57 | mobile-status-bar@1.0.14 58 | modules@0.10.0 59 | modules-runtime@0.8.0 60 | mongo@1.2.0 61 | mongo-dev-server@1.0.1 62 | mongo-id@1.0.6 63 | npm-mongo@2.2.30 64 | observe-sequence@1.0.16 65 | ordered-dict@1.0.9 66 | practicalmeteor:chai@2.1.0_1 67 | practicalmeteor:loglevel@1.2.0_2 68 | practicalmeteor:mocha@2.4.5_6 69 | practicalmeteor:mocha-core@1.0.1 70 | practicalmeteor:sinon@1.14.1_2 71 | promise@0.9.0 72 | random@1.0.10 73 | reactive-var@1.0.11 74 | reload@1.1.11 75 | retry@1.0.9 76 | routepolicy@1.0.12 77 | shell-server@0.2.4 78 | spacebars@1.0.15 79 | spacebars-compiler@1.1.3 80 | standard-minifier-css@1.3.4 81 | standard-minifier-js@2.1.1 82 | templating@1.3.2 83 | templating-compiler@1.3.2 84 | templating-runtime@1.3.2 85 | templating-tools@1.1.2 86 | tmeasday:test-reporter-helpers@0.2.1 87 | tracker@1.1.3 88 | underscore@1.0.10 89 | urigo:static-html-compiler@0.1.8 90 | url@1.1.0 91 | webapp@1.3.18 92 | webapp-hashing@1.0.9 93 | xolvio:cleaner@0.3.1 94 | -------------------------------------------------------------------------------- /tests/client/unit/meteor-observable.spec.ts: -------------------------------------------------------------------------------- 1 | import {chai} from 'meteor/practicalmeteor:chai'; 2 | import {sinon} from 'meteor/practicalmeteor:sinon'; 3 | import {MeteorObservable} from 'meteor-rxjs'; 4 | import {Observable} from 'rxjs'; 5 | 6 | const expect = chai.expect; 7 | 8 | describe('MeteorObservable', () => { 9 | describe('call', () => { 10 | it('Should return RxJS Observable when using "call"', () => { 11 | let returnValue = MeteorObservable.call('testMethod'); 12 | expect(returnValue instanceof Observable).to.equal(true); 13 | }); 14 | 15 | it('Should NOT run the actual "call" method without subscribing to the result', () => { 16 | let spy = sinon.spy(Meteor, 'call'); 17 | MeteorObservable.call('testMethod'); 18 | expect(spy.called).to.equal(false); 19 | spy.restore(); 20 | }); 21 | 22 | it('Should run the actual "call" method when subscribing to the result', () => { 23 | let spy = sinon.spy(Meteor, 'call'); 24 | let subHandler = MeteorObservable.call('testMethod').subscribe(); 25 | expect(spy.calledOnce).to.equal(true); 26 | spy.restore(); 27 | subHandler.unsubscribe(); 28 | }); 29 | 30 | it('Should trigger the RxJS Observable "next" callback when got the server response', 31 | (done) => { 32 | let subHandler = MeteorObservable.call('testMethod').subscribe((serverResponse) => { 33 | expect(serverResponse).to.equal('TEST_VALUE'); 34 | subHandler.unsubscribe(); 35 | done(); 36 | }); 37 | }); 38 | 39 | it('Should trigger the RxJS Observable "error" callback when got the server error', 40 | (done) => { 41 | let subscriptionHandler = MeteorObservable.call('NON_EXISTING_METHOD').subscribe(null, 42 | (e) => { 43 | expect(e instanceof Meteor.Error).to.equal(true); 44 | subscriptionHandler.unsubscribe(); 45 | done(); 46 | }); 47 | }); 48 | }); 49 | 50 | describe('subscribe', () => { 51 | function getSubsCount() { 52 | return Object.keys((Meteor).default_connection._subscriptions).length; 53 | } 54 | 55 | it('Should return RxJS Observable when using "subscribe"', () => { 56 | let returnValue = MeteorObservable.subscribe('test'); 57 | expect(returnValue instanceof Observable).to.equal(true); 58 | }); 59 | 60 | it('Should NOT run the actual "subscribe" method without subscribing to the result', () => { 61 | let spy = sinon.spy(Meteor, 'subscribe'); 62 | MeteorObservable.subscribe('test'); 63 | expect(spy.called).to.equal(false); 64 | spy.restore(); 65 | }); 66 | 67 | it('Should run the actual "subscribe" method when subscribing to the result', () => { 68 | let spy = sinon.spy(Meteor, 'subscribe'); 69 | let subHandler = MeteorObservable.subscribe('test').subscribe(); 70 | expect(spy.called).to.equal(true); 71 | spy.restore(); 72 | subHandler.unsubscribe(); 73 | }); 74 | 75 | it('Should call RxJS Observable "next" callback when subscription is ready', done => { 76 | let subHandler = MeteorObservable.subscribe('test').subscribe(() => { 77 | subHandler.unsubscribe(); 78 | done(); 79 | }); 80 | }); 81 | 82 | it('Should stop subscription when one observer subscribes', done => { 83 | let baseCount = getSubsCount(); 84 | let subHandler = MeteorObservable.subscribe('test').subscribe(() => { 85 | expect(getSubsCount()).to.equal(baseCount + 1); 86 | subHandler.unsubscribe(); 87 | expect(getSubsCount()).to.equal(baseCount); 88 | done(); 89 | }); 90 | }); 91 | 92 | it('Should persist same subscription when two observers subscribe, and then one unsubscribes', 93 | done => { 94 | let baseCount = getSubsCount(); 95 | let observable = MeteorObservable.subscribe('test'); 96 | let subHandler1 = observable.subscribe(() => {}); 97 | let subHandler2 = observable.subscribe(() => { 98 | expect(getSubsCount()).to.equal(baseCount + 1); 99 | subHandler1.unsubscribe(); 100 | expect(getSubsCount()).to.equal(baseCount + 1); 101 | subHandler2.unsubscribe(); 102 | expect(getSubsCount()).to.equal(baseCount); 103 | done(); 104 | }); 105 | }); 106 | }); 107 | }); 108 | -------------------------------------------------------------------------------- /tests/client/unit/observable-collection.spec.ts: -------------------------------------------------------------------------------- 1 | import {chai} from 'meteor/practicalmeteor:chai'; 2 | import {sinon} from 'meteor/practicalmeteor:sinon'; 3 | import {MongoObservable, ObservableCursor} from 'meteor-rxjs'; 4 | import {Observable} from 'rxjs'; 5 | 6 | const expect = chai.expect; 7 | 8 | describe('MongoObservable methods bridge', () => { 9 | let observable = new MongoObservable.Collection(null); 10 | let mongoCollection = observable.collection; 11 | 12 | it('Should return RxJS Observable object when using "find"', () => { 13 | let findResult = observable.find({}); 14 | expect(findResult instanceof Observable).to.equal(true); 15 | }); 16 | 17 | it('Should wrap existing collection', () => { 18 | let collection = new Mongo.Collection(null); 19 | let insert = sinon.stub(collection, 'insert'); 20 | 21 | let observable = new MongoObservable.Collection(collection); 22 | observable.insert({}); 23 | expect(insert.calledOnce).to.be.true; 24 | }); 25 | 26 | it('Insert should return an observable', done => { 27 | observable.insert({}).subscribe(id => { 28 | expect(id).to.be.string; 29 | done(); 30 | }); 31 | }); 32 | 33 | it('Remove should return an observable', done => { 34 | observable.insert({}).subscribe(id => { 35 | observable.remove(id).subscribe(() => { 36 | done(); 37 | }); 38 | }); 39 | }); 40 | 41 | function testOriginalMethod(methodName) { 42 | it(`Should call the original ${methodName} method of the Mongo.Collection`, () => { 43 | let stub = sinon.stub(mongoCollection, methodName); 44 | observable[methodName]({}); 45 | expect(stub.calledOnce).to.equal(true); 46 | }); 47 | } 48 | 49 | testOriginalMethod('allow'); 50 | testOriginalMethod('deny'); 51 | testOriginalMethod('insert'); 52 | testOriginalMethod('rawCollection'); 53 | testOriginalMethod('rawDatabase'); 54 | testOriginalMethod('remove'); 55 | testOriginalMethod('update'); 56 | testOriginalMethod('upsert'); 57 | testOriginalMethod('find'); 58 | testOriginalMethod('findOne'); 59 | }); 60 | -------------------------------------------------------------------------------- /tests/client/unit/observable-cursor.spec.ts: -------------------------------------------------------------------------------- 1 | import {chai} from 'meteor/practicalmeteor:chai'; 2 | import {sinon} from 'meteor/practicalmeteor:sinon'; 3 | import {Observable} from 'rxjs'; 4 | import {ObservableCursor, MongoObservable} from 'meteor-rxjs'; 5 | 6 | 7 | 8 | 9 | const expect = chai.expect; 10 | 11 | describe('ObservableCursor', function () { 12 | let collection: Mongo.Collection; 13 | let cursor: Mongo.Cursor; 14 | let observable: ObservableCursor; 15 | 16 | beforeEach(function () { 17 | collection = new Mongo.Collection(null); 18 | collection.allow({ 19 | insert: function () { 20 | return true; 21 | }, 22 | remove: function () { 23 | return true; 24 | }, 25 | update: function () { 26 | return true; 27 | } 28 | }); 29 | 30 | cursor = collection.find({}); 31 | observable = ObservableCursor.create(cursor); 32 | }); 33 | 34 | it('Should wrap the Mongo.Cursor and return RxJS Observable', () => { 35 | expect(observable instanceof Observable).to.equal(true); 36 | }); 37 | 38 | it('Should not use the actual Cursor "observeChanges" method w/o Observable subscription', () => { 39 | let spy = sinon.spy(cursor, 'observeChanges'); 40 | expect(spy.called).to.equal(false); 41 | spy.restore(); 42 | }); 43 | 44 | it('Should use the actual Cursor "observeChanges" after using Observable subscription', () => { 45 | let spy = sinon.spy(cursor, 'observeChanges'); 46 | let subHandler = observable.subscribe(); 47 | expect(spy.calledOnce).to.equal(true); 48 | spy.restore(); 49 | subHandler.unsubscribe(); 50 | }); 51 | 52 | it('Should not trigger subscription callback when creating the subscription', () => { 53 | let spy = sinon.spy(); 54 | let subscriptionHandler = observable.subscribe(spy); 55 | expect(spy.called).to.equal(false); 56 | subscriptionHandler.unsubscribe(); 57 | }); 58 | 59 | it('Subscription should unsubscribe after the unsubscribe call', () => { 60 | let subHandler; 61 | let callback = () => { 62 | subHandler.unsubscribe(); 63 | }; 64 | let spy = sinon.spy(callback); 65 | subHandler = observable.subscribe(spy); 66 | collection.insert({}); 67 | collection.insert({}); 68 | expect(spy.calledOnce).to.be.true; 69 | }); 70 | 71 | it('Should trigger subscription callback when adding data to the collection', () => { 72 | let newDoc = {name: 'newDoc'}; 73 | let subHandler; 74 | let callback = docs => { 75 | let inserted = docs[0]; 76 | expect(inserted.name).to.equal(newDoc.name); 77 | subHandler.unsubscribe(); 78 | }; 79 | let spy = sinon.spy(callback); 80 | subHandler = observable.subscribe(spy); 81 | collection.insert(newDoc); 82 | expect(spy.calledOnce).to.be.true; 83 | }); 84 | 85 | it('Should trigger subscription callback when moving items in the collection', (done) => { 86 | cursor = collection.find({}, {sort: {name: 1}}); 87 | observable = ObservableCursor.create(cursor); 88 | 89 | let newDoc = {name: 'ZZZZ'}; 90 | let subHandler; 91 | let count = 0; 92 | 93 | let callback = docs => { 94 | count++; 95 | 96 | // 4 because: insert, insert, update, *move* 97 | console.log(count); 98 | if (count === 4) { 99 | let firstItem = docs[0]; 100 | expect(firstItem.name).to.equal('AAAA'); 101 | subHandler.unsubscribe(); 102 | done(); 103 | } 104 | }; 105 | 106 | subHandler = observable.subscribe(callback); 107 | 108 | let objectId = collection.insert(newDoc); 109 | 110 | collection.insert({ 111 | name: 'BBBB' 112 | }); 113 | 114 | collection.update({_id: objectId}, { $set: {name: 'AAAA'} }); 115 | }); 116 | 117 | it('Should trigger callback twice when inserting a doc and then removing it', () => { 118 | let count = 0; 119 | let subHandler; 120 | let callback = docs => { 121 | count++; 122 | if (count == 2) { 123 | expect(docs.length).to.equal(0); 124 | subHandler.unsubscribe(); 125 | } 126 | }; 127 | let spy = sinon.spy(callback); 128 | let subHandler = observable.subscribe(spy); 129 | let idToRemove = collection.insert({test: true}); 130 | collection.remove(idToRemove); 131 | expect(spy.calledTwice).to.be.true; 132 | }); 133 | 134 | it('Should subscription callback should have updated docs after updating', done => { 135 | let count = 0; 136 | let callback = docs => { 137 | count++; 138 | if (count == 1) { 139 | expect(docs[0].test).to.equal(true); 140 | } 141 | 142 | if (count == 2) { 143 | expect(docs[0].test).to.equal(false); 144 | subHandler.unsubscribe(); 145 | done(); 146 | } 147 | }; 148 | let spy = sinon.spy(callback); 149 | 150 | let subHandler = observable.subscribe(spy); 151 | let idToUpdate = collection.insert({test: true}); 152 | collection.update({_id: idToUpdate}, {$set: {test: false}}); 153 | expect(spy.calledTwice).to.be.true; 154 | }); 155 | 156 | it('Should stop Mongo cursor when the last subscription unsubscribes', () => { 157 | let stopSpy = sinon.spy(); 158 | let spy = sinon.stub(cursor, 'observeChanges', () => { 159 | return { 160 | stop: stopSpy 161 | } 162 | }); 163 | 164 | let subHandler = observable.subscribe(); 165 | subHandler.unsubscribe(); 166 | 167 | expect(stopSpy.callCount).to.equal(1); 168 | spy.restore(); 169 | }); 170 | 171 | it('RxJS operators should persist', () => { 172 | expect(observable.count).to.equal(Observable.prototype.count); 173 | expect(observable.map).to.equal(Observable.prototype.map); 174 | }); 175 | 176 | it('Should trigger collectionCount when adding item', () => { 177 | let newDoc = {name: 'newDoc'}; 178 | let subHandler, subCountHandler; 179 | let callback = count => { 180 | expect(count).to.equal(1); 181 | subHandler.unsubscribe(); 182 | subCountHandler.unsubscribe(); 183 | }; 184 | 185 | subHandler = observable.subscribe(); 186 | subCountHandler = observable.collectionCount().subscribe(callback); 187 | collection.insert(newDoc); 188 | }); 189 | 190 | it('Should trigger collectionCount when adding and removing items', (done) => { 191 | let newDoc = {name: 'newDoc'}; 192 | let subHandler, subCountHandler; 193 | let c = 0; 194 | 195 | let callback = count => { 196 | if (c === 0) { 197 | expect(count).to.equal(1); 198 | } 199 | else if (c === 1) { 200 | expect(count).to.equal(0); 201 | subHandler.unsubscribe(); 202 | subCountHandler.unsubscribe(); 203 | done(); 204 | } 205 | 206 | c++; 207 | }; 208 | 209 | subHandler = observable.subscribe(); 210 | subCountHandler = observable.collectionCount().subscribe(callback); 211 | let id = collection.insert(newDoc); 212 | collection.remove({_id: id}); 213 | }); 214 | 215 | it('Multiple subscription for the same Observable should replay last value', () => { 216 | let wrappedCollection = MongoObservable.fromExisting(collection); 217 | let observable = wrappedCollection.find({}); 218 | 219 | let spyCb1 = sinon.spy(); 220 | let spyCb2 = sinon.spy(); 221 | let firstSubscriptionHandler = observable.subscribe(spyCb1); 222 | wrappedCollection.insert({test: 1}); 223 | wrappedCollection.insert({test: 2}); 224 | wrappedCollection.insert({test: 3}); 225 | let secondSubscriptionHandler = observable.subscribe(spyCb2); 226 | wrappedCollection.insert({test: 4}); 227 | 228 | expect(spyCb1.callCount).to.equal(4); 229 | expect(spyCb2.callCount).to.equal(1); 230 | 231 | firstSubscriptionHandler.unsubscribe(); 232 | secondSubscriptionHandler.unsubscribe(); 233 | }); 234 | }); 235 | -------------------------------------------------------------------------------- /tests/client/unit/zone-operator.spec.ts: -------------------------------------------------------------------------------- 1 | import {chai} from 'meteor/practicalmeteor:chai'; 2 | import {sinon} from 'meteor/practicalmeteor:sinon'; 3 | import {Observable} from 'rxjs'; 4 | import {MeteorObservable, MongoObservable,zoneOperator} from 'meteor-rxjs'; 5 | 6 | import 'zone.js/dist/zone.js'; 7 | 8 | const expect = chai.expect; 9 | 10 | describe('ZoneOperator', () => { 11 | let observable = new MongoObservable.Collection(null); 12 | observable.allow({ 13 | insert: function () { 14 | return true; 15 | } 16 | }); 17 | 18 | it('Should run in the expected zone on the next', done => { 19 | let gZone = Zone.current; 20 | let zone = Zone.current.fork({ name: 'ng'}); 21 | 22 | let obs: Observable = Observable.create(observer => { 23 | gZone.run(() => observer.next()); 24 | }); 25 | zone.run(() => { 26 | obs.pipe(zoneOperator()).subscribe(() => { 27 | expect(Zone.current).to.equal(zone); 28 | done(); 29 | }); 30 | }); 31 | }); 32 | 33 | it('Zone operator should use propagated zone from the autorun observable', 34 | done => { 35 | let zone = Zone.current.fork({ name: 'ng'}); 36 | zone.run(() => { 37 | let subHandler = MeteorObservable.autorun().subscribe(() => { 38 | console.log(subHandler); 39 | observable.find({}).pipe(zoneOperator()).subscribe(() => { 40 | expect(Zone.current).to.equal(zone); 41 | subHandler.unsubscribe(); 42 | done(); 43 | }); 44 | }); 45 | }); 46 | observable.insert({}); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /tests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tests", 3 | "private": true, 4 | "scripts": { 5 | "start": "meteor run" 6 | }, 7 | "dependencies": { 8 | "babel-runtime": "^6.26.0", 9 | "es6-shim": "^0.35.3", 10 | "meteor-rxjs": "file:..", 11 | "rxjs": "^6.0.0", 12 | "rxjs-compat": "^6.0.0", 13 | "zone.js": "0.8.17", 14 | "@types/meteor": "^1.4.6" 15 | }, 16 | "devDependencies": { 17 | "linklocal": "^2.8.1" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/server/lib/create-test-method.spec.ts: -------------------------------------------------------------------------------- 1 | let collection = new Mongo.Collection('testCollectionServer'); 2 | 3 | Meteor.methods({ 4 | 'testMethod': function() { 5 | return 'TEST_VALUE'; 6 | } 7 | }); 8 | 9 | Meteor.publish('test', () => { 10 | return collection.find({}); 11 | }); 12 | -------------------------------------------------------------------------------- /tests/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "diagnostics": false 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | babel-runtime@6.26.0: 6 | version "6.26.0" 7 | resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" 8 | dependencies: 9 | core-js "^2.4.0" 10 | regenerator-runtime "^0.11.0" 11 | 12 | balanced-match@^1.0.0: 13 | version "1.0.0" 14 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 15 | 16 | brace-expansion@^1.1.7: 17 | version "1.1.11" 18 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 19 | dependencies: 20 | balanced-match "^1.0.0" 21 | concat-map "0.0.1" 22 | 23 | commander@^2.11.0: 24 | version "2.15.0" 25 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.0.tgz#ad2a23a1c3b036e392469b8012cec6b33b4c1322" 26 | 27 | concat-map@0.0.1: 28 | version "0.0.1" 29 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 30 | 31 | core-js@^2.4.0: 32 | version "2.5.3" 33 | resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e" 34 | 35 | debug@^2.6.8: 36 | version "2.6.9" 37 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 38 | dependencies: 39 | ms "2.0.0" 40 | 41 | es6-shim@0.35.3: 42 | version "0.35.3" 43 | resolved "https://registry.yarnpkg.com/es6-shim/-/es6-shim-0.35.3.tgz#9bfb7363feffff87a6cdb6cd93e405ec3c4b6f26" 44 | 45 | fs.realpath@^1.0.0: 46 | version "1.0.0" 47 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 48 | 49 | glob@^7.0.5: 50 | version "7.1.2" 51 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" 52 | dependencies: 53 | fs.realpath "^1.0.0" 54 | inflight "^1.0.4" 55 | inherits "2" 56 | minimatch "^3.0.4" 57 | once "^1.3.0" 58 | path-is-absolute "^1.0.0" 59 | 60 | inflight@^1.0.4: 61 | version "1.0.6" 62 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 63 | dependencies: 64 | once "^1.3.0" 65 | wrappy "1" 66 | 67 | inherits@2: 68 | version "2.0.3" 69 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 70 | 71 | linklocal@2.8.1: 72 | version "2.8.1" 73 | resolved "https://registry.yarnpkg.com/linklocal/-/linklocal-2.8.1.tgz#3db5a1767afaa127772bdc7a80cbae460dfa30a5" 74 | dependencies: 75 | commander "^2.11.0" 76 | debug "^2.6.8" 77 | map-limit "0.0.1" 78 | mkdirp "^0.5.1" 79 | rimraf "^2.6.1" 80 | 81 | map-limit@0.0.1: 82 | version "0.0.1" 83 | resolved "https://registry.yarnpkg.com/map-limit/-/map-limit-0.0.1.tgz#eb7961031c0f0e8d001bf2d56fab685d58822f38" 84 | dependencies: 85 | once "~1.3.0" 86 | 87 | "meteor-rxjs@file:..": 88 | version "0.4.8" 89 | 90 | minimatch@^3.0.4: 91 | version "3.0.4" 92 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 93 | dependencies: 94 | brace-expansion "^1.1.7" 95 | 96 | minimist@0.0.8: 97 | version "0.0.8" 98 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 99 | 100 | mkdirp@^0.5.1: 101 | version "0.5.1" 102 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 103 | dependencies: 104 | minimist "0.0.8" 105 | 106 | ms@2.0.0: 107 | version "2.0.0" 108 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 109 | 110 | once@^1.3.0: 111 | version "1.4.0" 112 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 113 | dependencies: 114 | wrappy "1" 115 | 116 | once@~1.3.0: 117 | version "1.3.3" 118 | resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" 119 | dependencies: 120 | wrappy "1" 121 | 122 | path-is-absolute@^1.0.0: 123 | version "1.0.1" 124 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 125 | 126 | regenerator-runtime@^0.11.0: 127 | version "0.11.1" 128 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" 129 | 130 | rimraf@^2.6.1: 131 | version "2.6.2" 132 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" 133 | dependencies: 134 | glob "^7.0.5" 135 | 136 | rxjs@5.4.3: 137 | version "5.4.3" 138 | resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.4.3.tgz#0758cddee6033d68e0fd53676f0f3596ce3d483f" 139 | dependencies: 140 | symbol-observable "^1.0.1" 141 | 142 | symbol-observable@^1.0.1: 143 | version "1.2.0" 144 | resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" 145 | 146 | wrappy@1: 147 | version "1.0.2" 148 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 149 | 150 | zone.js@0.8.17: 151 | version "0.8.17" 152 | resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.17.tgz#4c5e5185a857da8da793daf3919371c5a36b2a0b" 153 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "experimentalDecorators": true, 4 | "module": "es2015", 5 | "target": "es5", 6 | "lib": ["es2015", "dom"], 7 | "noImplicitAny": false, 8 | "suppressImplicitAnyIndexErrors": true, 9 | "moduleResolution": "node", 10 | "emitDecoratorMetadata": true, 11 | "sourceMap": true, 12 | "declaration": true, 13 | "outDir": "./dist", 14 | "rootDir": "./src", 15 | "types": [ 16 | "zone.js", 17 | "@types/chai", 18 | "@types/meteor", 19 | "@types/underscore" 20 | ] 21 | }, 22 | "files": [ 23 | "src/index.ts" 24 | ], 25 | "exclude": [ 26 | "node_modules" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "align": [true, "parameters"], 4 | "class-name": true, 5 | "curly": true, 6 | "eofline": true, 7 | "forin": true, 8 | "indent": [true, "spaces"], 9 | "label-position": true, 10 | "max-line-length": [true, 150], 11 | "member-access": false, 12 | "member-ordering": [true, 13 | "public-before-private", 14 | "static-before-instance", 15 | "variables-before-functions" 16 | ], 17 | "no-arg": true, 18 | "no-bitwise": true, 19 | "no-console": [true, 20 | "debug", 21 | "info", 22 | "time", 23 | "timeEnd", 24 | "trace" 25 | ], 26 | "no-construct": true, 27 | "no-debugger": true, 28 | "no-duplicate-variable": true, 29 | "no-empty": false, 30 | "no-eval": true, 31 | "no-inferrable-types": true, 32 | "no-shadowed-variable": false, 33 | "no-string-literal": true, 34 | "no-switch-case-fall-through": true, 35 | "no-trailing-whitespace": true, 36 | "no-unused-expression": true, 37 | "no-use-before-declare": true, 38 | "no-var-keyword": false, 39 | "object-literal-sort-keys": true, 40 | "no-conditional-assignment": true, 41 | "one-line": [true, 42 | "check-open-brace", 43 | "check-catch", 44 | "check-else", 45 | "check-whitespace" 46 | ], 47 | "quotemark": [true, "single"], 48 | "radix": true, 49 | "semicolon": true, 50 | "triple-equals": [true, "allow-null-check"], 51 | "variable-name": [true, 52 | "check-format", 53 | "allow-leading-underscore" 54 | ], 55 | "whitespace": [true, 56 | "check-branch", 57 | "check-decl", 58 | "check-operator", 59 | "check-separator", 60 | "check-type" 61 | ] 62 | } 63 | } 64 | --------------------------------------------------------------------------------