Compare commits
249 Commits
Author | SHA1 | Date | |
---|---|---|---|
0e55cd8876 | |||
eccdf3f00a | |||
c7544133d9 | |||
c7c9acf5bd | |||
c99ec50853 | |||
4dd9557e1d | |||
52b34a6da1 | |||
1bf74fe04d | |||
fdd875ad31 | |||
a7bf0c0298 | |||
59d6336e43 | |||
e0fc81179a | |||
5aa81a56a2 | |||
9ae26177b8 | |||
26ac52d6c5 | |||
fb39463b7d | |||
44acba80c1 | |||
8cf8315577 | |||
9b44b64a50 | |||
699e25201c | |||
2ef9aace68 | |||
cc55a57dfd | |||
b2df512552 | |||
23c62fbd69 | |||
5f70ea0b05 | |||
49a595876a | |||
db38a1ef85 | |||
94854638dd | |||
902fab4cc0 | |||
ed3b19abc5 | |||
5b88da7dce | |||
df273e9efa | |||
fd590e0be3 | |||
ef97b390d4 | |||
cd14eb8bf3 | |||
f48443dcd3 | |||
3f28ff80cb | |||
64005a0b32 | |||
8a77bb3281 | |||
25f50ecf51 | |||
ad87f8147b | |||
da0c9873eb | |||
2fcd3f1550 | |||
f726cf4c5b | |||
c198969fae | |||
be1badeb23 | |||
fe065b966f | |||
811e2490b8 | |||
206ccd40e9 | |||
055298172f | |||
278f3c8169 | |||
0709ba921b | |||
de1f1110b4 | |||
30f4254428 | |||
1c4b03e647 | |||
27cc7651ba | |||
355a2a3f2b | |||
a739582861 | |||
37f9a64735 | |||
83a5170591 | |||
f94363cf31 | |||
df02e5bb71 | |||
38e438c54f | |||
11bc1ac6dc | |||
3431e94ddd | |||
739e040776 | |||
28d57efd9e | |||
f50a61308c | |||
42aa9f9f8a | |||
3f591ff9d8 | |||
7b33347b4c | |||
3f11cbf595 | |||
cf1ec7f9eb | |||
54060deb8f | |||
48cffb5ac2 | |||
8301eb79a2 | |||
ad6366a294 | |||
cb6c03ebfe | |||
551916fe5c | |||
9b3892c1e8 | |||
c1b1af9c5d | |||
d3a3d5be9d | |||
c9a734d879 | |||
856e8e7d1f | |||
7a4d557724 | |||
7cbd0bd99b | |||
e10f6585a5 | |||
5c8dffdd9c | |||
846996eeac | |||
668df09ba0 | |||
03656f4ca0 | |||
c4c612f3a9 | |||
e357f7581c | |||
9697b1e48b | |||
aeb35705d4 | |||
236c8c6551 | |||
1f28db15e7 | |||
86d600e287 | |||
bb81530dac | |||
b9f9b36b87 | |||
df2fadfa01 | |||
8b2beb3485 | |||
144a620f43 | |||
c241247845 | |||
81e39d09e4 | |||
8e51b518b1 | |||
8308d8d03b | |||
97365ddf29 | |||
55d96fa68d | |||
54ec6accdf | |||
fc5d092b25 | |||
dfba057562 | |||
1ad05943b5 | |||
302e51a77f | |||
1330d03af2 | |||
a298e9d190 | |||
e571ef347b | |||
39a4c7ef3f | |||
0d3518d990 | |||
fbdde2268c | |||
8b6c26f45a | |||
97e82ed75a | |||
03baffd9fd | |||
f29ae67580 | |||
e550a8dbd6 | |||
cf6ef25a8d | |||
29c512b0cc | |||
105f69d1c9 | |||
4c375f8465 | |||
9466af6a4a | |||
c5aa747f42 | |||
b5f2474f65 | |||
85f0d99934 | |||
3b2d3d9072 | |||
3ff5c36fdf | |||
a5acc2fe4e | |||
9c81257101 | |||
f7342962f4 | |||
bcd10205d3 | |||
6cab20f32d | |||
5aaa6ad2d6 | |||
635256f2f6 | |||
f799d3efa5 | |||
f74020ba96 | |||
f6d6545ff5 | |||
85a196c8c1 | |||
adb198af01 | |||
6dce9f3ff8 | |||
2f6a4ce3e5 | |||
0984a1ade4 | |||
804701c96a | |||
a3759fa484 | |||
ef38df62be | |||
c17789e92e | |||
0bf2ba554d | |||
5cbf1a222a | |||
f075530838 | |||
efb83853fb | |||
73300ca4d3 | |||
1e946cdceb | |||
608ff93a41 | |||
6211953f14 | |||
99e520b776 | |||
eda8297356 | |||
ffa52a5883 | |||
1e83f0a0ef | |||
0203eabdfd | |||
72894e3ef1 | |||
bbe5f8c6a8 | |||
02af9f5c4b | |||
17de480272 | |||
776fd3ee4e | |||
3272bb7235 | |||
116dfbc3b0 | |||
3f714b1a33 | |||
e58fa57525 | |||
8e7ad5210f | |||
cea6c662ac | |||
6eb43a4b9f | |||
7f89cbeecd | |||
a042a589a0 | |||
75b5f6af08 | |||
e6a36f22ac | |||
246e3486f0 | |||
c1c4a29415 | |||
6448516aa0 | |||
24a7b2dbd3 | |||
afa7c2fe61 | |||
b768896fbe | |||
8d7d9adef1 | |||
ca6d3c60c0 | |||
38c1fcd53a | |||
e433b9e212 | |||
bf3656f792 | |||
7e9fc62ce7 | |||
670a0c63fb | |||
64e76b3ed1 | |||
25803330de | |||
c6cbff1308 | |||
3eeac7b936 | |||
761b742e21 | |||
e56def621c | |||
ab1799f4f2 | |||
9985b849d1 | |||
1800273b25 | |||
e715cc6d37 | |||
f7abc175aa | |||
bbcb3a614e | |||
941d2f0902 | |||
5c78f83a28 | |||
124f117352 | |||
f67da898ae | |||
3c8f70f77e | |||
3674d7d9a5 | |||
fe2a622488 | |||
f092eefbf3 | |||
8d0aa361f9 | |||
692a1223a8 | |||
ae7d101ab9 | |||
3825b15a65 | |||
3fc41678d2 | |||
39f1b7ada1 | |||
f763de2403 | |||
cba1d031b6 | |||
d31e6a5931 | |||
46514a2743 | |||
1cf02157c4 | |||
72efa14da8 | |||
a73c2084c0 | |||
5ed557a21a | |||
2b6c30ff55 | |||
12ef599333 | |||
191ea5d3c6 | |||
bdf33ed1ca | |||
1c76905dcd | |||
4d88cea69d | |||
8b4f7169ff | |||
2a1c45608f | |||
85a6444263 | |||
766ae1d1ff | |||
7630882312 | |||
4aec47f207 | |||
c2e3a1ae6e | |||
3d8f8646b1 | |||
aca9817c56 | |||
7e341f2b50 | |||
d2ca108ef8 | |||
e2d12f8c9c | |||
cfcd9ab386 |
66
.gitea/workflows/default_nottags.yaml
Normal file
66
.gitea/workflows/default_nottags.yaml
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
name: Default (not tags)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags-ignore:
|
||||||
|
- '**'
|
||||||
|
|
||||||
|
env:
|
||||||
|
IMAGE: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||||
|
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@gitea.lossless.digital/${{gitea.repository}}.git
|
||||||
|
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
|
||||||
|
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
|
||||||
|
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
|
||||||
|
NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
security:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: true
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install pnpm and npmci
|
||||||
|
run: |
|
||||||
|
pnpm install -g pnpm
|
||||||
|
pnpm install -g @shipzone/npmci
|
||||||
|
|
||||||
|
- name: Run npm prepare
|
||||||
|
run: npmci npm prepare
|
||||||
|
|
||||||
|
- name: Audit production dependencies
|
||||||
|
run: |
|
||||||
|
npmci command npm config set registry https://registry.npmjs.org
|
||||||
|
npmci command pnpm audit --audit-level=high --prod
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Audit development dependencies
|
||||||
|
run: |
|
||||||
|
npmci command npm config set registry https://registry.npmjs.org
|
||||||
|
npmci command pnpm audit --audit-level=high --dev
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
test:
|
||||||
|
if: ${{ always() }}
|
||||||
|
needs: security
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Test stable
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm install
|
||||||
|
npmci npm test
|
||||||
|
|
||||||
|
- name: Test build
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm install
|
||||||
|
npmci npm build
|
124
.gitea/workflows/default_tags.yaml
Normal file
124
.gitea/workflows/default_tags.yaml
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
name: Default (tags)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- '*'
|
||||||
|
|
||||||
|
env:
|
||||||
|
IMAGE: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||||
|
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@gitea.lossless.digital/${{gitea.repository}}.git
|
||||||
|
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
|
||||||
|
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
|
||||||
|
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
|
||||||
|
NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
security:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: true
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
pnpm install -g pnpm
|
||||||
|
pnpm install -g @shipzone/npmci
|
||||||
|
npmci npm prepare
|
||||||
|
|
||||||
|
- name: Audit production dependencies
|
||||||
|
run: |
|
||||||
|
npmci command npm config set registry https://registry.npmjs.org
|
||||||
|
npmci command pnpm audit --audit-level=high --prod
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Audit development dependencies
|
||||||
|
run: |
|
||||||
|
npmci command npm config set registry https://registry.npmjs.org
|
||||||
|
npmci command pnpm audit --audit-level=high --dev
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
test:
|
||||||
|
if: ${{ always() }}
|
||||||
|
needs: security
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
pnpm install -g pnpm
|
||||||
|
pnpm install -g @shipzone/npmci
|
||||||
|
npmci npm prepare
|
||||||
|
|
||||||
|
- name: Test stable
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm install
|
||||||
|
npmci npm test
|
||||||
|
|
||||||
|
- name: Test build
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm install
|
||||||
|
npmci npm build
|
||||||
|
|
||||||
|
release:
|
||||||
|
needs: test
|
||||||
|
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
pnpm install -g pnpm
|
||||||
|
pnpm install -g @shipzone/npmci
|
||||||
|
npmci npm prepare
|
||||||
|
|
||||||
|
- name: Release
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm publish
|
||||||
|
|
||||||
|
metadata:
|
||||||
|
needs: test
|
||||||
|
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
pnpm install -g pnpm
|
||||||
|
pnpm install -g @shipzone/npmci
|
||||||
|
npmci npm prepare
|
||||||
|
|
||||||
|
- name: Code quality
|
||||||
|
run: |
|
||||||
|
npmci command npm install -g typescript
|
||||||
|
npmci npm install
|
||||||
|
|
||||||
|
- name: Trigger
|
||||||
|
run: npmci trigger
|
||||||
|
|
||||||
|
- name: Build docs and upload artifacts
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm install
|
||||||
|
pnpm install -g @gitzone/tsdoc
|
||||||
|
npmci command tsdoc
|
||||||
|
continue-on-error: true
|
22
.gitignore
vendored
22
.gitignore
vendored
@ -1,4 +1,20 @@
|
|||||||
node_modules/
|
|
||||||
public/
|
|
||||||
coverage/
|
|
||||||
.nogit/
|
.nogit/
|
||||||
|
|
||||||
|
# artifacts
|
||||||
|
coverage/
|
||||||
|
public/
|
||||||
|
pages/
|
||||||
|
|
||||||
|
# installs
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# caches
|
||||||
|
.yarn/
|
||||||
|
.cache/
|
||||||
|
.rpt2_cache
|
||||||
|
|
||||||
|
# builds
|
||||||
|
dist/
|
||||||
|
dist_*/
|
||||||
|
|
||||||
|
# custom
|
@ -1,58 +0,0 @@
|
|||||||
# gitzone standard
|
|
||||||
image: hosttoday/ht-docker-node:npmci
|
|
||||||
|
|
||||||
cache:
|
|
||||||
paths:
|
|
||||||
- .yarn/
|
|
||||||
key: "$CI_BUILD_STAGE"
|
|
||||||
|
|
||||||
stages:
|
|
||||||
- test
|
|
||||||
- release
|
|
||||||
- trigger
|
|
||||||
- pages
|
|
||||||
|
|
||||||
testSTABLE:
|
|
||||||
stage: test
|
|
||||||
script:
|
|
||||||
- npmci node install stable
|
|
||||||
- npmci npm install
|
|
||||||
- npmci npm test
|
|
||||||
coverage: /\d+.?\d+?\%\s*coverage/
|
|
||||||
tags:
|
|
||||||
- docker
|
|
||||||
|
|
||||||
release:
|
|
||||||
stage: release
|
|
||||||
script:
|
|
||||||
- npmci npm prepare
|
|
||||||
- npmci npm publish
|
|
||||||
only:
|
|
||||||
- tags
|
|
||||||
tags:
|
|
||||||
- docker
|
|
||||||
|
|
||||||
trigger:
|
|
||||||
stage: trigger
|
|
||||||
script:
|
|
||||||
- npmci trigger
|
|
||||||
only:
|
|
||||||
- tags
|
|
||||||
tags:
|
|
||||||
- docker
|
|
||||||
|
|
||||||
pages:
|
|
||||||
image: hosttoday/ht-docker-node:npmci
|
|
||||||
stage: pages
|
|
||||||
script:
|
|
||||||
- npmci command yarn global add npmpage
|
|
||||||
- npmci command npmpage
|
|
||||||
tags:
|
|
||||||
- docker
|
|
||||||
only:
|
|
||||||
- tags
|
|
||||||
artifacts:
|
|
||||||
expire_in: 1 week
|
|
||||||
paths:
|
|
||||||
- public
|
|
||||||
allow_failure: true
|
|
11
.vscode/launch.json
vendored
Normal file
11
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"command": "npm test",
|
||||||
|
"name": "Run npm test",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "node-terminal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
26
.vscode/settings.json
vendored
Normal file
26
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"json.schemas": [
|
||||||
|
{
|
||||||
|
"fileMatch": ["/npmextra.json"],
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"npmci": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "settings for npmci"
|
||||||
|
},
|
||||||
|
"gitzone": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "settings for gitzone",
|
||||||
|
"properties": {
|
||||||
|
"projectType": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["website", "element", "service", "npm", "wcc"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
114
README.md
114
README.md
@ -1,114 +0,0 @@
|
|||||||
# smartdata
|
|
||||||
do more with data and RethinkDB
|
|
||||||
|
|
||||||
## Availabililty
|
|
||||||
[](https://www.npmjs.com/package/smartdata)
|
|
||||||
[](https://GitLab.com/pushrocks/smartdata)
|
|
||||||
[](https://github.com/pushrocks/smartdata)
|
|
||||||
[](https://pushrocks.gitlab.io/smartdata/)
|
|
||||||
|
|
||||||
## Status for master
|
|
||||||
[](https://GitLab.com/pushrocks/smartdata/commits/master)
|
|
||||||
[](https://GitLab.com/pushrocks/smartdata/commits/master)
|
|
||||||
[](https://www.npmjs.com/package/smartdata)
|
|
||||||
[](https://david-dm.org/pushrocks/smartdata)
|
|
||||||
[](https://www.bithound.io/github/pushrocks/smartdata/master/dependencies/npm)
|
|
||||||
[](https://www.bithound.io/github/pushrocks/smartdata)
|
|
||||||
[](https://snyk.io/test/npm/smartdata)
|
|
||||||
[](https://nodejs.org/dist/latest-v6.x/docs/api/)
|
|
||||||
[](https://nodejs.org/dist/latest-v6.x/docs/api/)
|
|
||||||
[](http://standardjs.com/)
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
Use TypeScript for best in class instellisense.
|
|
||||||
|
|
||||||
smartdata is an ODM that adheres to TypeScript practices and uses classes to organize data.
|
|
||||||
It uses RethinkDB as persistent storage.
|
|
||||||
|
|
||||||
## Intention
|
|
||||||
There are many ODMs out there, however when we searched for an ODM that uses TypeScript,
|
|
||||||
acts smart while still embracing the NoSQL idea we didn't find a matching solution.
|
|
||||||
This is why we started smartdata.
|
|
||||||
|
|
||||||
How RethinkDB's terms map to the ones of smartdata:
|
|
||||||
|
|
||||||
RethinkDB term | smartdata class
|
|
||||||
--- | ---
|
|
||||||
Database | smartdata.Db
|
|
||||||
Table | smartdata.DbTable
|
|
||||||
Document | smartdata.DbDoc
|
|
||||||
|
|
||||||
### class Db
|
|
||||||
represents a Database. Naturally it has .connect() etc. methods on it.
|
|
||||||
```javascript
|
|
||||||
import * as smartdata from 'smartdata'
|
|
||||||
|
|
||||||
let myRethinkDb1 = new smartdata.Db({
|
|
||||||
// rethinkDb connection options here
|
|
||||||
})
|
|
||||||
|
|
||||||
myDb1.connect()
|
|
||||||
```
|
|
||||||
|
|
||||||
### class DbCollection
|
|
||||||
represents a collection of objects.
|
|
||||||
A collection is defined by the object class (that is extending smartdata.dbdoc) it respresents
|
|
||||||
|
|
||||||
So to get to get access to a specific collection you document
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// continues from the block before...
|
|
||||||
|
|
||||||
@Collection(myRethinkDb1)
|
|
||||||
class MyObject extends smartdata.DbDoc<myObject> { // read the next block about DbDoc
|
|
||||||
@smartdata.svDb() property1: string // @smartdata.svDb() marks the property for db save
|
|
||||||
property2: number // this one is not marked, so it won't be save upon calling this.save()
|
|
||||||
constructor(optionsArg:{
|
|
||||||
property1: string,
|
|
||||||
property2: number
|
|
||||||
}) {
|
|
||||||
super()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let myCollection = myRethinkDb1.getCollectionByName<myObject>(myObject)
|
|
||||||
|
|
||||||
// start to instantiate instances of classes from scratch or database
|
|
||||||
|
|
||||||
let localObject = new MyObject({
|
|
||||||
property1: 'hi',
|
|
||||||
property2: 2
|
|
||||||
})
|
|
||||||
localObject.save() // saves the object to the database
|
|
||||||
```
|
|
||||||
|
|
||||||
> Alert: You NEVER instantiate a collection.
|
|
||||||
This is done for you!!!
|
|
||||||
|
|
||||||
### class DbDoc
|
|
||||||
represents a individual document in a collection
|
|
||||||
and thereby is ideally suited to extend the class you want to actually store.
|
|
||||||
|
|
||||||
DbDoc extends your class with the following methods:
|
|
||||||
|
|
||||||
* `.save()` will save (or update) the object you call it on only. Any referenced non-savable objects will not get stored.
|
|
||||||
* `.saveDeep()` does the same like `.save()`.
|
|
||||||
In addition it will look for properties that reference an object
|
|
||||||
that extends DbDoc as well and call .saveDeep() on them as well.
|
|
||||||
Loops are prevented
|
|
||||||
|
|
||||||
So now we can **store** instances of classes to Db...
|
|
||||||
How do we **get** a new class instance from a Doc in the DB?
|
|
||||||
|
|
||||||
## TypeScript
|
|
||||||
How does TypeScript play into this?
|
|
||||||
Since you define your classes in TypeScript and types flow through smartdata in a generic way
|
|
||||||
you should get all the Intellisense and type checking you love when using smartdata.
|
|
||||||
smartdata itself also bundles typings.
|
|
||||||
So you don't need to install any additional types when importing smartdata.
|
|
||||||
|
|
||||||
For further information read the linked docs at the top of this README.
|
|
||||||
|
|
||||||
> MIT licensed | **©** [Lossless GmbH](https://lossless.gmbh)
|
|
||||||
| By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy.html)
|
|
||||||
|
|
||||||
[](https://push.rocks)
|
|
3
dist/index.d.ts
vendored
3
dist/index.d.ts
vendored
@ -1,3 +0,0 @@
|
|||||||
export * from './smartdata.classes.db';
|
|
||||||
export * from './smartdata.classes.dbcollection';
|
|
||||||
export * from './smartdata.classes.dbdoc';
|
|
9
dist/index.js
vendored
9
dist/index.js
vendored
@ -1,9 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
function __export(m) {
|
|
||||||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
|
|
||||||
}
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
__export(require("./smartdata.classes.db"));
|
|
||||||
__export(require("./smartdata.classes.dbcollection"));
|
|
||||||
__export(require("./smartdata.classes.dbdoc"));
|
|
||||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLDRDQUFzQztBQUN0QyxzREFBZ0Q7QUFDaEQsK0NBQXlDIn0=
|
|
35
dist/smartdata.classes.db.d.ts
vendored
35
dist/smartdata.classes.db.d.ts
vendored
@ -1,35 +0,0 @@
|
|||||||
import * as plugins from './smartdata.plugins';
|
|
||||||
import { Objectmap } from 'lik';
|
|
||||||
import { DbTable } from './smartdata.classes.dbcollection';
|
|
||||||
import { ConnectionOptions } from 'rethinkdb';
|
|
||||||
/**
|
|
||||||
* interface - indicates the connection status of the db
|
|
||||||
*/
|
|
||||||
export declare type TConnectionStatus = 'initial' | 'disconnected' | 'connected' | 'failed';
|
|
||||||
export declare class Db {
|
|
||||||
dbName: string;
|
|
||||||
connectionOptions: plugins.rethinkDb.ConnectionOptions;
|
|
||||||
dbConnection: plugins.rethinkDb.Connection;
|
|
||||||
status: TConnectionStatus;
|
|
||||||
dbTablesMap: Objectmap<DbTable<any>>;
|
|
||||||
constructor(connectionOptionsArg: ConnectionOptions);
|
|
||||||
/**
|
|
||||||
* supply additional SSl options
|
|
||||||
*/
|
|
||||||
setSsl(certificateStringArg: string, formatArg: 'base64' | 'clearText'): void;
|
|
||||||
/**
|
|
||||||
* connects to the database that was specified during instance creation
|
|
||||||
*/
|
|
||||||
connect(): Promise<any>;
|
|
||||||
/**
|
|
||||||
* closes the connection to the databse
|
|
||||||
*/
|
|
||||||
close(): Promise<any>;
|
|
||||||
/**
|
|
||||||
* Gets a table's name and returns smartdata's DbTable class
|
|
||||||
* @param nameArg
|
|
||||||
* @returns DbTable
|
|
||||||
*/
|
|
||||||
getDbTableByName<T>(nameArg: string): Promise<DbTable<T>>;
|
|
||||||
addTable(dbCollectionArg: DbTable<any>): void;
|
|
||||||
}
|
|
76
dist/smartdata.classes.db.js
vendored
76
dist/smartdata.classes.db.js
vendored
@ -1,76 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
||||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
||||||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
const plugins = require("./smartdata.plugins");
|
|
||||||
const lik_1 = require("lik");
|
|
||||||
class Db {
|
|
||||||
constructor(connectionOptionsArg) {
|
|
||||||
this.dbTablesMap = new lik_1.Objectmap();
|
|
||||||
this.dbName = connectionOptionsArg.db;
|
|
||||||
this.connectionOptions = connectionOptionsArg;
|
|
||||||
this.status = 'initial';
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* supply additional SSl options
|
|
||||||
*/
|
|
||||||
setSsl(certificateStringArg, formatArg) {
|
|
||||||
let certificateString;
|
|
||||||
if (formatArg = 'base64') {
|
|
||||||
certificateString = plugins.smartstring.base64.decode(certificateStringArg);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
certificateString = certificateStringArg;
|
|
||||||
}
|
|
||||||
this.connectionOptions['ssl'] = {
|
|
||||||
ca: Buffer.from(certificateString)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// basic connection stuff ----------------------------------------------
|
|
||||||
/**
|
|
||||||
* connects to the database that was specified during instance creation
|
|
||||||
*/
|
|
||||||
connect() {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
this.dbConnection = yield plugins.rethinkDb.connect(this.connectionOptions);
|
|
||||||
this.dbConnection.use(this.dbName);
|
|
||||||
this.status = 'connected';
|
|
||||||
plugins.beautylog.ok(`Connected to database ${this.dbName}`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* closes the connection to the databse
|
|
||||||
*/
|
|
||||||
close() {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
yield this.dbConnection.close();
|
|
||||||
this.status = 'disconnected';
|
|
||||||
plugins.beautylog.ok(`disconnected from database ${this.dbName}`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// handle table to class distribution
|
|
||||||
/**
|
|
||||||
* Gets a table's name and returns smartdata's DbTable class
|
|
||||||
* @param nameArg
|
|
||||||
* @returns DbTable
|
|
||||||
*/
|
|
||||||
getDbTableByName(nameArg) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
let resultCollection = this.dbTablesMap.find((dbCollectionArg) => {
|
|
||||||
return dbCollectionArg.tableName === nameArg;
|
|
||||||
});
|
|
||||||
return resultCollection;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
addTable(dbCollectionArg) {
|
|
||||||
this.dbTablesMap.add(dbCollectionArg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exports.Db = Db;
|
|
||||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRkYXRhLmNsYXNzZXMuZGIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydGRhdGEuY2xhc3Nlcy5kYi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7O0FBQUEsK0NBQThDO0FBQzlDLDZCQUErQjtBQVcvQjtJQU9FLFlBQVksb0JBQXVDO1FBRm5ELGdCQUFXLEdBQUcsSUFBSSxlQUFTLEVBQWdCLENBQUE7UUFHekMsSUFBSSxDQUFDLE1BQU0sR0FBRyxvQkFBb0IsQ0FBQyxFQUFFLENBQUE7UUFDckMsSUFBSSxDQUFDLGlCQUFpQixHQUFHLG9CQUFvQixDQUFBO1FBQzdDLElBQUksQ0FBQyxNQUFNLEdBQUcsU0FBUyxDQUFBO0lBQ3pCLENBQUM7SUFFRDs7T0FFRztJQUNILE1BQU0sQ0FBRSxvQkFBNEIsRUFBRSxTQUFpQztRQUNyRSxJQUFJLGlCQUF5QixDQUFBO1FBQzdCLEVBQUUsQ0FBQSxDQUFDLFNBQVMsR0FBRyxRQUFRLENBQUMsQ0FBQyxDQUFDO1lBQ3hCLGlCQUFpQixHQUFHLE9BQU8sQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFBO1FBQzdFLENBQUM7UUFBQyxJQUFJLENBQUMsQ0FBQztZQUNOLGlCQUFpQixHQUFHLG9CQUFvQixDQUFBO1FBQzFDLENBQUM7UUFDRCxJQUFJLENBQUMsaUJBQWlCLENBQUMsS0FBSyxDQUFDLEdBQUc7WUFDOUIsRUFBRSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUM7U0FDbkMsQ0FBQTtJQUNILENBQUM7SUFFRCx3RUFBd0U7SUFFeEU7O09BRUc7SUFDRyxPQUFPOztZQUNYLElBQUksQ0FBQyxZQUFZLEdBQUcsTUFBTSxPQUFPLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsQ0FBQTtZQUMzRSxJQUFJLENBQUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUE7WUFDbEMsSUFBSSxDQUFDLE1BQU0sR0FBRyxXQUFXLENBQUE7WUFDekIsT0FBTyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMseUJBQXlCLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFBO1FBQzlELENBQUM7S0FBQTtJQUVEOztPQUVHO0lBQ0csS0FBSzs7WUFDVCxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxFQUFFLENBQUE7WUFDL0IsSUFBSSxDQUFDLE1BQU0sR0FBRyxjQUFjLENBQUE7WUFDNUIsT0FBTyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsOEJBQThCLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFBO1FBQ25FLENBQUM7S0FBQTtJQUVELHFDQUFxQztJQUVyQzs7OztPQUlHO0lBQ0csZ0JBQWdCLENBQUksT0FBZTs7WUFDdkMsSUFBSSxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDLGVBQWUsRUFBRSxFQUFFO2dCQUMvRCxNQUFNLENBQUMsZUFBZSxDQUFDLFNBQVMsS0FBSyxPQUFPLENBQUE7WUFDOUMsQ0FBQyxDQUFDLENBQUE7WUFDRixNQUFNLENBQUMsZ0JBQWdCLENBQUE7UUFDekIsQ0FBQztLQUFBO0lBRUQsUUFBUSxDQUFFLGVBQTZCO1FBQ3JDLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLGVBQWUsQ0FBQyxDQUFBO0lBQ3ZDLENBQUM7Q0FDRjtBQWxFRCxnQkFrRUMifQ==
|
|
45
dist/smartdata.classes.dbcollection.d.ts
vendored
45
dist/smartdata.classes.dbcollection.d.ts
vendored
@ -1,45 +0,0 @@
|
|||||||
import * as plugins from './smartdata.plugins';
|
|
||||||
import { Db } from './smartdata.classes.db';
|
|
||||||
import { DbDoc } from './smartdata.classes.dbdoc';
|
|
||||||
import { WriteResult, Cursor } from 'rethinkdb';
|
|
||||||
export interface IFindOptions {
|
|
||||||
limit?: number;
|
|
||||||
}
|
|
||||||
export interface IDocValidation<T> {
|
|
||||||
(doc: T): boolean;
|
|
||||||
}
|
|
||||||
export declare function Collection(db: Db): (constructor: any) => void;
|
|
||||||
export declare class DbTable<T> {
|
|
||||||
/**
|
|
||||||
* the collection that is used, defaults to mongodb collection,
|
|
||||||
* can be nedb datastore (sub api of mongodb)
|
|
||||||
*/
|
|
||||||
table: plugins.rethinkDb.Table;
|
|
||||||
objectValidation: IDocValidation<T>;
|
|
||||||
tableName: string;
|
|
||||||
db: Db;
|
|
||||||
constructor(collectedClassArg: T & DbDoc<T>, dbArg: Db);
|
|
||||||
init(): Promise<void>;
|
|
||||||
/**
|
|
||||||
* adds a validation function that all newly inserted and updated objects have to pass
|
|
||||||
*/
|
|
||||||
addDocValidation(funcArg: IDocValidation<T>): void;
|
|
||||||
/**
|
|
||||||
* finds an object in the DbCollection
|
|
||||||
*/
|
|
||||||
find(): Promise<Cursor>;
|
|
||||||
/**
|
|
||||||
* create an object in the database
|
|
||||||
*/
|
|
||||||
insert(dbDocArg: T & DbDoc<T>): Promise<WriteResult>;
|
|
||||||
/**
|
|
||||||
* inserts object into the DbCollection
|
|
||||||
*/
|
|
||||||
update(dbDocArg: T & DbDoc<T>): Promise<WriteResult>;
|
|
||||||
/**
|
|
||||||
* checks a Doc for constraints
|
|
||||||
* if this.objectValidation is not set it passes.
|
|
||||||
*/
|
|
||||||
private checkDoc(docArg);
|
|
||||||
extractKey(writeResult: WriteResult): void;
|
|
||||||
}
|
|
103
dist/smartdata.classes.dbcollection.js
vendored
103
dist/smartdata.classes.dbcollection.js
vendored
@ -1,103 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
||||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
||||||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
const plugins = require("./smartdata.plugins");
|
|
||||||
function Collection(db) {
|
|
||||||
return function (constructor) {
|
|
||||||
constructor['dbCollection'] = new DbTable(constructor, db);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
exports.Collection = Collection;
|
|
||||||
class DbTable {
|
|
||||||
constructor(collectedClassArg, dbArg) {
|
|
||||||
this.objectValidation = null;
|
|
||||||
// tell the collection where it belongs
|
|
||||||
this.tableName = collectedClassArg.name;
|
|
||||||
this.db = dbArg;
|
|
||||||
// tell the db class about it (important since Db uses different systems under the hood)
|
|
||||||
this.db.addTable(this);
|
|
||||||
}
|
|
||||||
init() {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
if (!this.table) {
|
|
||||||
// connect this instance to a RethinkDB table
|
|
||||||
const availableTables = yield plugins.rethinkDb
|
|
||||||
.db(this.db.dbName)
|
|
||||||
.tableList()
|
|
||||||
.run(this.db.dbConnection);
|
|
||||||
if (availableTables.indexOf(this.tableName)) {
|
|
||||||
yield plugins.rethinkDb
|
|
||||||
.db(this.db.dbName)
|
|
||||||
.tableCreate(this.tableName)
|
|
||||||
.run(this.db.dbConnection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.table = plugins.rethinkDb.table(this.tableName);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* adds a validation function that all newly inserted and updated objects have to pass
|
|
||||||
*/
|
|
||||||
addDocValidation(funcArg) {
|
|
||||||
this.objectValidation = funcArg;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* finds an object in the DbCollection
|
|
||||||
*/
|
|
||||||
find() {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
yield this.init();
|
|
||||||
return yield plugins.rethinkDb.table(this.tableName).filter({}).run(this.db.dbConnection);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* create an object in the database
|
|
||||||
*/
|
|
||||||
insert(dbDocArg) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
yield this.init();
|
|
||||||
yield this.checkDoc(dbDocArg);
|
|
||||||
return yield plugins.rethinkDb.table(this.tableName).insert(dbDocArg.createSavableObject()).run(this.db.dbConnection);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* inserts object into the DbCollection
|
|
||||||
*/
|
|
||||||
update(dbDocArg) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
yield this.init();
|
|
||||||
yield this.checkDoc(dbDocArg);
|
|
||||||
console.log(this.tableName, dbDocArg.createSavableObject());
|
|
||||||
return yield plugins.rethinkDb.table(this.tableName).update(dbDocArg.createSavableObject()).run(this.db.dbConnection);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* checks a Doc for constraints
|
|
||||||
* if this.objectValidation is not set it passes.
|
|
||||||
*/
|
|
||||||
checkDoc(docArg) {
|
|
||||||
let done = plugins.smartq.defer();
|
|
||||||
let validationResult = true;
|
|
||||||
if (this.objectValidation) {
|
|
||||||
validationResult = this.objectValidation(docArg);
|
|
||||||
}
|
|
||||||
if (validationResult) {
|
|
||||||
done.resolve();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
done.reject('validation of object did not pass');
|
|
||||||
}
|
|
||||||
return done.promise;
|
|
||||||
}
|
|
||||||
extractKey(writeResult) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exports.DbTable = DbTable;
|
|
||||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRkYXRhLmNsYXNzZXMuZGJjb2xsZWN0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvc21hcnRkYXRhLmNsYXNzZXMuZGJjb2xsZWN0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7QUFBQSwrQ0FBOEM7QUFlOUMsb0JBQTRCLEVBQU07SUFDaEMsTUFBTSxDQUFDLFVBQVUsV0FBVztRQUMxQixXQUFXLENBQUUsY0FBYyxDQUFFLEdBQUcsSUFBSSxPQUFPLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQyxDQUFBO0lBQzlELENBQUMsQ0FBQTtBQUNILENBQUM7QUFKRCxnQ0FJQztBQUVEO0lBVUUsWUFBYSxpQkFBK0IsRUFBRSxLQUFTO1FBSnZELHFCQUFnQixHQUFzQixJQUFJLENBQUE7UUFLeEMsdUNBQXVDO1FBQ3ZDLElBQUksQ0FBQyxTQUFTLEdBQUcsaUJBQWlCLENBQUMsSUFBSSxDQUFBO1FBQ3ZDLElBQUksQ0FBQyxFQUFFLEdBQUcsS0FBSyxDQUFBO1FBRWYsd0ZBQXdGO1FBQ3hGLElBQUksQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFBO0lBQ3hCLENBQUM7SUFFSyxJQUFJOztZQUNSLEVBQUUsQ0FBQSxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7Z0JBQ2YsNkNBQTZDO2dCQUM3QyxNQUFNLGVBQWUsR0FBRyxNQUFNLE9BQU8sQ0FBQyxTQUFTO3FCQUM1QyxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUM7cUJBQ2xCLFNBQVMsRUFBRTtxQkFDWCxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxZQUFZLENBQUMsQ0FBQTtnQkFDNUIsRUFBRSxDQUFBLENBQUMsZUFBZSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDO29CQUMzQyxNQUFNLE9BQU8sQ0FBQyxTQUFTO3lCQUN0QixFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUM7eUJBQ2xCLFdBQVcsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDO3lCQUMzQixHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxZQUFZLENBQUMsQ0FBQTtnQkFDNUIsQ0FBQztZQUNILENBQUM7WUFDRCxJQUFJLENBQUMsS0FBSyxHQUFHLE9BQU8sQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQTtRQUN0RCxDQUFDO0tBQUE7SUFFRDs7T0FFRztJQUNILGdCQUFnQixDQUFFLE9BQTBCO1FBQzFDLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxPQUFPLENBQUE7SUFDakMsQ0FBQztJQUVEOztPQUVHO0lBQ0csSUFBSTs7WUFDUixNQUFNLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQTtZQUNqQixNQUFNLENBQUMsTUFBTSxPQUFPLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsTUFBTSxDQUFDLEVBRTNELENBQUMsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxZQUFZLENBQUMsQ0FBQTtRQUM5QixDQUFDO0tBQUE7SUFFRDs7T0FFRztJQUNHLE1BQU0sQ0FBRSxRQUFzQjs7WUFDbEMsTUFBTSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUE7WUFDakIsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFBO1lBQzdCLE1BQU0sQ0FBQyxNQUFNLE9BQU8sQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxNQUFNLENBQ3pELFFBQVEsQ0FBQyxtQkFBbUIsRUFBRSxDQUMvQixDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQyxDQUFBO1FBQzdCLENBQUM7S0FBQTtJQUVEOztPQUVHO0lBQ0csTUFBTSxDQUFFLFFBQXNCOztZQUNsQyxNQUFNLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQTtZQUNqQixNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLENBQUE7WUFDN0IsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLFFBQVEsQ0FBQyxtQkFBbUIsRUFBRSxDQUFDLENBQUE7WUFDM0QsTUFBTSxDQUFDLE1BQU0sT0FBTyxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLE1BQU0sQ0FDekQsUUFBUSxDQUFDLG1CQUFtQixFQUFFLENBQy9CLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsWUFBWSxDQUFDLENBQUE7UUFDN0IsQ0FBQztLQUFBO0lBRUQ7OztPQUdHO0lBQ0ssUUFBUSxDQUFFLE1BQVM7UUFDekIsSUFBSSxJQUFJLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQVEsQ0FBQTtRQUN2QyxJQUFJLGdCQUFnQixHQUFHLElBQUksQ0FBQTtRQUMzQixFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDO1lBQzFCLGdCQUFnQixHQUFHLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsQ0FBQTtRQUNsRCxDQUFDO1FBQ0QsRUFBRSxDQUFDLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDO1lBQ3JCLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQTtRQUNoQixDQUFDO1FBQUMsSUFBSSxDQUFDLENBQUM7WUFDTixJQUFJLENBQUMsTUFBTSxDQUFDLG1DQUFtQyxDQUFDLENBQUE7UUFDbEQsQ0FBQztRQUNELE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFBO0lBQ3JCLENBQUM7SUFFRCxVQUFVLENBQUUsV0FBd0I7SUFFcEMsQ0FBQztDQUNGO0FBakdELDBCQWlHQyJ9
|
|
44
dist/smartdata.classes.dbdoc.d.ts
vendored
44
dist/smartdata.classes.dbdoc.d.ts
vendored
@ -1,44 +0,0 @@
|
|||||||
import { Objectmap } from 'lik';
|
|
||||||
import { DbTable } from './smartdata.classes.dbcollection';
|
|
||||||
export declare type TDocCreation = 'db' | 'new' | 'mixed';
|
|
||||||
/**
|
|
||||||
* saveable - saveable decorator to be used on class properties
|
|
||||||
*/
|
|
||||||
export declare function svDb(): (target: DbDoc<any>, key: string) => void;
|
|
||||||
export declare class DbDoc<T> {
|
|
||||||
/**
|
|
||||||
* the collection object an Doc belongs to
|
|
||||||
*/
|
|
||||||
collection: DbTable<T>;
|
|
||||||
/**
|
|
||||||
* how the Doc in memory was created, may prove useful later.
|
|
||||||
*/
|
|
||||||
creationStatus: TDocCreation;
|
|
||||||
/**
|
|
||||||
* an array of saveable properties of a doc
|
|
||||||
*/
|
|
||||||
saveableProperties: string[];
|
|
||||||
/**
|
|
||||||
* name
|
|
||||||
*/
|
|
||||||
name: string;
|
|
||||||
/**
|
|
||||||
* primary id in the database
|
|
||||||
*/
|
|
||||||
dbId: string;
|
|
||||||
/**
|
|
||||||
* class constructor
|
|
||||||
*/
|
|
||||||
constructor();
|
|
||||||
/**
|
|
||||||
* saves this instance but not any connected items
|
|
||||||
* may lead to data inconsistencies, but is faster
|
|
||||||
*/
|
|
||||||
save(): Promise<void>;
|
|
||||||
/**
|
|
||||||
* also store any referenced objects to DB
|
|
||||||
* better for data consistency
|
|
||||||
*/
|
|
||||||
saveDeep(savedMapArg?: Objectmap<DbDoc<any>>): void;
|
|
||||||
createSavableObject(): any;
|
|
||||||
}
|
|
83
dist/smartdata.classes.dbdoc.js
vendored
83
dist/smartdata.classes.dbdoc.js
vendored
@ -1,83 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
||||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
||||||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
const lik_1 = require("lik");
|
|
||||||
/**
|
|
||||||
* saveable - saveable decorator to be used on class properties
|
|
||||||
*/
|
|
||||||
function svDb() {
|
|
||||||
return (target, key) => {
|
|
||||||
console.log('called sva');
|
|
||||||
if (!target.saveableProperties) {
|
|
||||||
target.saveableProperties = [];
|
|
||||||
}
|
|
||||||
target.saveableProperties.push(key);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
exports.svDb = svDb;
|
|
||||||
class DbDoc {
|
|
||||||
/**
|
|
||||||
* class constructor
|
|
||||||
*/
|
|
||||||
constructor() {
|
|
||||||
/**
|
|
||||||
* how the Doc in memory was created, may prove useful later.
|
|
||||||
*/
|
|
||||||
this.creationStatus = 'new';
|
|
||||||
this.name = this.constructor['name'];
|
|
||||||
this.collection = this.constructor['dbCollection'];
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* saves this instance but not any connected items
|
|
||||||
* may lead to data inconsistencies, but is faster
|
|
||||||
*/
|
|
||||||
save() {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
let self = this;
|
|
||||||
switch (this.creationStatus) {
|
|
||||||
case 'db':
|
|
||||||
yield this.collection.update(self);
|
|
||||||
break;
|
|
||||||
case 'new':
|
|
||||||
let writeResult = yield this.collection.insert(self);
|
|
||||||
this.creationStatus = 'db';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.error('neither new nor in db?');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* also store any referenced objects to DB
|
|
||||||
* better for data consistency
|
|
||||||
*/
|
|
||||||
saveDeep(savedMapArg = null) {
|
|
||||||
if (!savedMapArg) {
|
|
||||||
savedMapArg = new lik_1.Objectmap();
|
|
||||||
}
|
|
||||||
savedMapArg.add(this);
|
|
||||||
this.save();
|
|
||||||
for (let propertyKey in this) {
|
|
||||||
let property = this[propertyKey];
|
|
||||||
if (property instanceof DbDoc && !savedMapArg.checkForObject(property)) {
|
|
||||||
property.saveDeep(savedMapArg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
createSavableObject() {
|
|
||||||
let saveableObject = {}; // is not exposed to outside, so any is ok here
|
|
||||||
for (let propertyNameString of this.saveableProperties) {
|
|
||||||
saveableObject[propertyNameString] = this[propertyNameString];
|
|
||||||
}
|
|
||||||
return saveableObject;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exports.DbDoc = DbDoc;
|
|
||||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRkYXRhLmNsYXNzZXMuZGJkb2MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydGRhdGEuY2xhc3Nlcy5kYmRvYy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7O0FBRUEsNkJBQStCO0FBTy9COztHQUVHO0FBQ0g7SUFDRSxNQUFNLENBQUMsQ0FBQyxNQUFrQixFQUFFLEdBQVcsRUFBRSxFQUFFO1FBQ3pDLE9BQU8sQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLENBQUE7UUFDekIsRUFBRSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxDQUFDO1lBQUMsTUFBTSxDQUFDLGtCQUFrQixHQUFHLEVBQUUsQ0FBQTtRQUFDLENBQUM7UUFDbEUsTUFBTSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQTtJQUNyQyxDQUFDLENBQUE7QUFDSCxDQUFDO0FBTkQsb0JBTUM7QUFFRDtJQTJCRTs7T0FFRztJQUNIO1FBdkJBOztXQUVHO1FBQ0gsbUJBQWMsR0FBaUIsS0FBSyxDQUFBO1FBcUJsQyxJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUE7UUFDcEMsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFFLGNBQWMsQ0FBRSxDQUFBO0lBQ3RELENBQUM7SUFFRDs7O09BR0c7SUFDRyxJQUFJOztZQUNSLElBQUksSUFBSSxHQUFRLElBQUksQ0FBQTtZQUNwQixNQUFNLENBQUMsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FBQztnQkFDNUIsS0FBSyxJQUFJO29CQUNQLE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUE7b0JBQ2xDLEtBQUssQ0FBQTtnQkFDUCxLQUFLLEtBQUs7b0JBQ1IsSUFBSSxXQUFXLEdBQUcsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQTtvQkFDcEQsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUE7b0JBQzFCLEtBQUssQ0FBQztnQkFDUjtvQkFDRSxPQUFPLENBQUMsS0FBSyxDQUFDLHdCQUF3QixDQUFDLENBQUE7WUFDM0MsQ0FBQztRQUNILENBQUM7S0FBQTtJQUVEOzs7T0FHRztJQUNILFFBQVEsQ0FBRSxjQUFxQyxJQUFJO1FBQ2pELEVBQUUsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQztZQUNqQixXQUFXLEdBQUcsSUFBSSxlQUFTLEVBQWMsQ0FBQTtRQUMzQyxDQUFDO1FBQ0QsV0FBVyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUNyQixJQUFJLENBQUMsSUFBSSxFQUFFLENBQUE7UUFDWCxHQUFHLENBQUMsQ0FBQyxJQUFJLFdBQVcsSUFBSSxJQUFJLENBQUMsQ0FBQyxDQUFDO1lBQzdCLElBQUksUUFBUSxHQUFRLElBQUksQ0FBRSxXQUFXLENBQUUsQ0FBQTtZQUN2QyxFQUFFLENBQUMsQ0FBQyxRQUFRLFlBQVksS0FBSyxJQUFJLENBQUMsV0FBVyxDQUFDLGNBQWMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBQ3ZFLFFBQVEsQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLENBQUE7WUFDaEMsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBRUQsbUJBQW1CO1FBQ2pCLElBQUksY0FBYyxHQUFRLEVBQUUsQ0FBQSxDQUFDLCtDQUErQztRQUM1RSxHQUFHLENBQUMsQ0FBQyxJQUFJLGtCQUFrQixJQUFJLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLENBQUM7WUFDdkQsY0FBYyxDQUFFLGtCQUFrQixDQUFFLEdBQUcsSUFBSSxDQUFFLGtCQUFrQixDQUFFLENBQUE7UUFDbkUsQ0FBQztRQUNELE1BQU0sQ0FBQyxjQUFjLENBQUE7SUFDdkIsQ0FBQztDQUNGO0FBL0VELHNCQStFQyJ9
|
|
7
dist/smartdata.plugins.d.ts
vendored
7
dist/smartdata.plugins.d.ts
vendored
@ -1,7 +0,0 @@
|
|||||||
import * as assert from 'assert';
|
|
||||||
import * as beautylog from 'beautylog';
|
|
||||||
import * as lodash from 'lodash';
|
|
||||||
import * as rethinkDb from 'rethinkdb';
|
|
||||||
import * as smartq from 'smartq';
|
|
||||||
import * as smartstring from 'smartstring';
|
|
||||||
export { assert, beautylog, lodash, smartq, rethinkDb, smartstring };
|
|
15
dist/smartdata.plugins.js
vendored
15
dist/smartdata.plugins.js
vendored
@ -1,15 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
const assert = require("assert");
|
|
||||||
exports.assert = assert;
|
|
||||||
const beautylog = require("beautylog");
|
|
||||||
exports.beautylog = beautylog;
|
|
||||||
const lodash = require("lodash");
|
|
||||||
exports.lodash = lodash;
|
|
||||||
const rethinkDb = require("rethinkdb");
|
|
||||||
exports.rethinkDb = rethinkDb;
|
|
||||||
const smartq = require("smartq");
|
|
||||||
exports.smartq = smartq;
|
|
||||||
const smartstring = require("smartstring");
|
|
||||||
exports.smartstring = smartstring;
|
|
||||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRkYXRhLnBsdWdpbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydGRhdGEucGx1Z2lucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLGlDQUFnQztBQVE1Qix3QkFBTTtBQVBWLHVDQUFzQztBQVFsQyw4QkFBUztBQVBiLGlDQUFnQztBQVE1Qix3QkFBTTtBQVBWLHVDQUFzQztBQVNsQyw4QkFBUztBQVJiLGlDQUFnQztBQU81Qix3QkFBTTtBQU5WLDJDQUEwQztBQVF0QyxrQ0FBVyJ9
|
|
@ -1,26 +0,0 @@
|
|||||||
# smartdata
|
|
||||||
do more with data
|
|
||||||
|
|
||||||
## Availabililty
|
|
||||||
[](https://www.npmjs.com/package/smartdata)
|
|
||||||
[](https://GitLab.com/pushrocks/smartdata)
|
|
||||||
[](https://github.com/pushrocks/smartdata)
|
|
||||||
[](https://pushrocks.gitlab.io/smartdata/)
|
|
||||||
|
|
||||||
## Status for master
|
|
||||||
[](https://GitLab.com/pushrocks/smartdata/commits/master)
|
|
||||||
[](https://GitLab.com/pushrocks/smartdata/commits/master)
|
|
||||||
[](https://www.npmjs.com/package/smartdata)
|
|
||||||
[](https://david-dm.org/pushrocks/smartdata)
|
|
||||||
[](https://www.bithound.io/github/pushrocks/smartdata/master/dependencies/npm)
|
|
||||||
[](https://www.bithound.io/github/pushrocks/smartdata)
|
|
||||||
[](https://nodejs.org/dist/latest-v6.x/docs/api/)
|
|
||||||
[](https://nodejs.org/dist/latest-v6.x/docs/api/)
|
|
||||||
[](http://standardjs.com/)
|
|
||||||
|
|
||||||
For further information read the linked docs at the top of this README.
|
|
||||||
|
|
||||||
> MIT licensed | **©** [Lossless GmbH](https://lossless.gmbh)
|
|
||||||
| By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy.html)
|
|
||||||
|
|
||||||
[](https://push.rocks)
|
|
@ -5,13 +5,19 @@
|
|||||||
"dockerSock": false
|
"dockerSock": false
|
||||||
},
|
},
|
||||||
"npmci": {
|
"npmci": {
|
||||||
"globalNpmTools": [
|
"npmGlobalTools": [],
|
||||||
"npmts"
|
"npmAccessLevel": "public",
|
||||||
]
|
"npmRegistryUrl": "registry.npmjs.org"
|
||||||
},
|
},
|
||||||
"npmts": {
|
"gitzone": {
|
||||||
"testConfig": {
|
"projectType": "npm",
|
||||||
"parallel": false
|
"module": {
|
||||||
|
"githost": "gitlab.com",
|
||||||
|
"gitscope": "push.rocks",
|
||||||
|
"gitrepo": "smartdata",
|
||||||
|
"description": "do more with data",
|
||||||
|
"npmPackagename": "@push.rocks/smartdata",
|
||||||
|
"license": "MIT"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
223
package-lock.json
generated
223
package-lock.json
generated
@ -1,223 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "smartdata",
|
|
||||||
"version": "2.0.1",
|
|
||||||
"lockfileVersion": 1,
|
|
||||||
"requires": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@types/lodash": {
|
|
||||||
"version": "4.14.92",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.92.tgz",
|
|
||||||
"integrity": "sha512-cdvY1fyUGYgG7/i07a/sR5PnD6+Z+ljUrD0CNVf0qj645VvEdLNtZPjvCp4siPy3rQ/KRXMfUATIqi3+9x57Sw=="
|
|
||||||
},
|
|
||||||
"@types/minimatch": {
|
|
||||||
"version": "3.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
|
|
||||||
"integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA=="
|
|
||||||
},
|
|
||||||
"balanced-match": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
|
||||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
|
||||||
},
|
|
||||||
"brace-expansion": {
|
|
||||||
"version": "1.1.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
|
|
||||||
"integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
|
|
||||||
"requires": {
|
|
||||||
"balanced-match": "1.0.0",
|
|
||||||
"concat-map": "0.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"concat-map": {
|
|
||||||
"version": "0.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
|
||||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
|
||||||
},
|
|
||||||
"conventional-commit-types": {
|
|
||||||
"version": "2.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-2.2.0.tgz",
|
|
||||||
"integrity": "sha1-XblXOdbCEqy+e29lahG5QLqmiUY=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"cz-conventional-changelog": {
|
|
||||||
"version": "2.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-2.1.0.tgz",
|
|
||||||
"integrity": "sha1-L0vHOQ4yROTfKT5ro1Hkx0Cnx2Q=",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"conventional-commit-types": "2.2.0",
|
|
||||||
"lodash.map": "4.6.0",
|
|
||||||
"longest": "1.0.1",
|
|
||||||
"right-pad": "1.0.1",
|
|
||||||
"word-wrap": "1.2.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"define-properties": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz",
|
|
||||||
"integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=",
|
|
||||||
"requires": {
|
|
||||||
"foreach": "2.0.5",
|
|
||||||
"object-keys": "1.0.11"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"es-abstract": {
|
|
||||||
"version": "1.10.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.10.0.tgz",
|
|
||||||
"integrity": "sha512-/uh/DhdqIOSkAWifU+8nG78vlQxdLckUdI/sPgy0VhuXi2qJ7T8czBmqIYtLQVpCIFYafChnsRsB5pyb1JdmCQ==",
|
|
||||||
"requires": {
|
|
||||||
"es-to-primitive": "1.1.1",
|
|
||||||
"function-bind": "1.1.1",
|
|
||||||
"has": "1.0.1",
|
|
||||||
"is-callable": "1.1.3",
|
|
||||||
"is-regex": "1.0.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"es-to-primitive": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz",
|
|
||||||
"integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=",
|
|
||||||
"requires": {
|
|
||||||
"is-callable": "1.1.3",
|
|
||||||
"is-date-object": "1.0.1",
|
|
||||||
"is-symbol": "1.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"foreach": {
|
|
||||||
"version": "2.0.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
|
|
||||||
"integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k="
|
|
||||||
},
|
|
||||||
"function-bind": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
|
|
||||||
},
|
|
||||||
"has": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz",
|
|
||||||
"integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=",
|
|
||||||
"requires": {
|
|
||||||
"function-bind": "1.1.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"is-callable": {
|
|
||||||
"version": "1.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz",
|
|
||||||
"integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI="
|
|
||||||
},
|
|
||||||
"is-date-object": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
|
|
||||||
"integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY="
|
|
||||||
},
|
|
||||||
"is-regex": {
|
|
||||||
"version": "1.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
|
|
||||||
"integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
|
|
||||||
"requires": {
|
|
||||||
"has": "1.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"is-symbol": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz",
|
|
||||||
"integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI="
|
|
||||||
},
|
|
||||||
"lik": {
|
|
||||||
"version": "2.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/lik/-/lik-2.0.2.tgz",
|
|
||||||
"integrity": "sha512-xdNrvQqVLMNkU25Z6tNrJXyOhn0hugZvWZCIPb315M5J4fK2OzgpLacp68J5bYWydRWX4L3Tl/i69BNWHsvcXg==",
|
|
||||||
"requires": {
|
|
||||||
"@types/lodash": "4.14.92",
|
|
||||||
"@types/minimatch": "3.0.3",
|
|
||||||
"lodash": "4.17.4",
|
|
||||||
"minimatch": "3.0.4",
|
|
||||||
"smartq": "1.1.6",
|
|
||||||
"symbol-tree": "3.2.2",
|
|
||||||
"typings-global": "1.0.28"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"lodash": {
|
|
||||||
"version": "4.17.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
|
|
||||||
"integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4="
|
|
||||||
},
|
|
||||||
"smartq": {
|
|
||||||
"version": "1.1.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/smartq/-/smartq-1.1.6.tgz",
|
|
||||||
"integrity": "sha512-W7vTj4kSqN8kHVq+Q6BJTr/UGc36TnO0pzKNU8B4cr7TXG4N98eyubWaaCHPSjCUqDgmUPPru929WXzetai97A==",
|
|
||||||
"requires": {
|
|
||||||
"typings-global": "1.0.28",
|
|
||||||
"util.promisify": "1.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"lodash.map": {
|
|
||||||
"version": "4.6.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz",
|
|
||||||
"integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"longest": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
|
|
||||||
"integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"minimatch": {
|
|
||||||
"version": "3.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
|
||||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
|
||||||
"requires": {
|
|
||||||
"brace-expansion": "1.1.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"object-keys": {
|
|
||||||
"version": "1.0.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz",
|
|
||||||
"integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0="
|
|
||||||
},
|
|
||||||
"object.getownpropertydescriptors": {
|
|
||||||
"version": "2.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz",
|
|
||||||
"integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=",
|
|
||||||
"requires": {
|
|
||||||
"define-properties": "1.1.2",
|
|
||||||
"es-abstract": "1.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"right-pad": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/right-pad/-/right-pad-1.0.1.tgz",
|
|
||||||
"integrity": "sha1-jKCMLLtbVedNr6lr9/0aJ9VoyNA=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"symbol-tree": {
|
|
||||||
"version": "3.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz",
|
|
||||||
"integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY="
|
|
||||||
},
|
|
||||||
"typings-global": {
|
|
||||||
"version": "1.0.28",
|
|
||||||
"resolved": "https://registry.npmjs.org/typings-global/-/typings-global-1.0.28.tgz",
|
|
||||||
"integrity": "sha512-6VOwJWEY2971HOMHu/7sURzUXiD4/LiMJPsMAOqkHHAtS3MVpLFE5gzTiHilsH9KY5VE1mBQirWIgWFsDuo90A=="
|
|
||||||
},
|
|
||||||
"util.promisify": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==",
|
|
||||||
"requires": {
|
|
||||||
"define-properties": "1.1.2",
|
|
||||||
"object.getownpropertydescriptors": "2.0.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"word-wrap": {
|
|
||||||
"version": "1.2.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
|
||||||
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
|
|
||||||
"dev": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
69
package.json
69
package.json
@ -1,12 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "smartdata",
|
"name": "@push.rocks/smartdata",
|
||||||
"version": "2.0.1",
|
"version": "5.0.26",
|
||||||
|
"private": false,
|
||||||
"description": "do more with data",
|
"description": "do more with data",
|
||||||
"main": "dist/index.js",
|
"main": "dist_ts/index.js",
|
||||||
"typings": "dist/index.d.ts",
|
"typings": "dist_ts/index.d.ts",
|
||||||
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "(npmts)",
|
"test": "tstest test/",
|
||||||
"testLocal": "(npmdocker)"
|
"build": "tsbuild --web --allowimplicitany",
|
||||||
|
"buildDocs": "tsdoc"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -19,27 +22,41 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://gitlab.com/pushrocks/smartdata#README",
|
"homepage": "https://gitlab.com/pushrocks/smartdata#README",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/lodash": "^4.14.92",
|
"@push.rocks/lik": "^6.0.2",
|
||||||
"@types/rethinkdb": "^2.3.8",
|
"@push.rocks/smartdelay": "^3.0.1",
|
||||||
"beautylog": "^6.1.10",
|
"@push.rocks/smartlog": "^3.0.2",
|
||||||
"lik": "^2.0.2",
|
"@push.rocks/smartmongo": "^2.0.10",
|
||||||
"lodash": "^4.17.4",
|
"@push.rocks/smartpromise": "^4.0.2",
|
||||||
"rethinkdb": "^2.3.3",
|
"@push.rocks/smartrx": "^3.0.6",
|
||||||
"runtime-type-checks": "0.0.4",
|
"@push.rocks/smartstring": "^4.0.7",
|
||||||
"smartq": "^1.1.6",
|
"@push.rocks/smarttime": "^4.0.1",
|
||||||
"smartstring": "^2.0.28"
|
"@push.rocks/smartunique": "^3.0.3",
|
||||||
|
"@push.rocks/taskbuffer": "^3.1.2",
|
||||||
|
"@tsclass/tsclass": "^4.0.42",
|
||||||
|
"mongodb": "^5.7.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^8.5.7",
|
"@gitzone/tsbuild": "^2.1.66",
|
||||||
"@types/shelljs": "^0.7.4",
|
"@gitzone/tsrun": "^1.2.44",
|
||||||
"cz-conventional-changelog": "^2.1.0",
|
"@gitzone/tstest": "^1.0.77",
|
||||||
"qenv": "^1.1.7",
|
"@push.rocks/qenv": "^6.0.2",
|
||||||
"shelljs": "^0.7.8",
|
"@push.rocks/tapbundle": "^5.0.15",
|
||||||
"tapbundle": "^1.1.1"
|
"@types/node": "^20.4.10",
|
||||||
|
"@types/shortid": "0.0.29"
|
||||||
},
|
},
|
||||||
"config": {
|
"files": [
|
||||||
"commitizen": {
|
"ts/**/*",
|
||||||
"path": "./node_modules/cz-conventional-changelog"
|
"ts_web/**/*",
|
||||||
}
|
"dist/**/*",
|
||||||
}
|
"dist_*/**/*",
|
||||||
|
"dist_ts/**/*",
|
||||||
|
"dist_ts_web/**/*",
|
||||||
|
"assets/**/*",
|
||||||
|
"cli.js",
|
||||||
|
"npmextra.json",
|
||||||
|
"readme.md"
|
||||||
|
],
|
||||||
|
"browserslist": [
|
||||||
|
"last 1 chrome versions"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
7111
pnpm-lock.yaml
generated
Normal file
7111
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
8
qenv.yml
8
qenv.yml
@ -1,7 +1 @@
|
|||||||
vars:
|
required:
|
||||||
- RDB_DB
|
|
||||||
- RDB_HOST
|
|
||||||
- RDB_USER
|
|
||||||
- RDB_PASS
|
|
||||||
- RDB_PORT
|
|
||||||
- RDB_CERT
|
|
||||||
|
154
readme.md
Normal file
154
readme.md
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
# @push.rocks/smartdata
|
||||||
|
do more with data
|
||||||
|
|
||||||
|
## Availabililty and Links
|
||||||
|
* [npmjs.org (npm package)](https://www.npmjs.com/package/@push.rocks/smartdata)
|
||||||
|
* [gitlab.com (source)](https://gitlab.com/push.rocks/smartdata)
|
||||||
|
* [github.com (source mirror)](https://github.com/push.rocks/smartdata)
|
||||||
|
* [docs (typedoc)](https://push.rocks.gitlab.io/smartdata/)
|
||||||
|
|
||||||
|
## Status for master
|
||||||
|
|
||||||
|
Status Category | Status Badge
|
||||||
|
-- | --
|
||||||
|
GitLab Pipelines | [](https://lossless.cloud)
|
||||||
|
GitLab Pipline Test Coverage | [](https://lossless.cloud)
|
||||||
|
npm | [](https://lossless.cloud)
|
||||||
|
Snyk | [](https://lossless.cloud)
|
||||||
|
TypeScript Support | [](https://lossless.cloud)
|
||||||
|
node Support | [](https://nodejs.org/dist/latest-v10.x/docs/api/)
|
||||||
|
Code Style | [](https://lossless.cloud)
|
||||||
|
PackagePhobia (total standalone install weight) | [](https://lossless.cloud)
|
||||||
|
PackagePhobia (package size on registry) | [](https://lossless.cloud)
|
||||||
|
BundlePhobia (total size when bundled) | [](https://lossless.cloud)
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Use TypeScript for best in class instellisense.
|
||||||
|
|
||||||
|
smartdata is an ODM that adheres to TypeScript practices and uses classes to organize data.
|
||||||
|
It uses RethinkDB as persistent storage.
|
||||||
|
|
||||||
|
## Intention
|
||||||
|
|
||||||
|
There are many ODMs out there, however when we searched for an ODM that uses TypeScript,
|
||||||
|
acts smart while still embracing the NoSQL idea we didn't find a matching solution.
|
||||||
|
This is why we started smartdata.
|
||||||
|
|
||||||
|
How RethinkDB's terms map to the ones of smartdata:
|
||||||
|
|
||||||
|
| MongoDb term | smartdata class |
|
||||||
|
| ------------ | ----------------------------- |
|
||||||
|
| Database | smartdata.SmartdataDb |
|
||||||
|
| Collection | smartdata.SmartdataCollection |
|
||||||
|
| Document | smartdata.SmartadataDoc |
|
||||||
|
|
||||||
|
### class Db
|
||||||
|
|
||||||
|
represents a Database. Naturally it has .connect() etc. methods on it.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Assuming toplevel await
|
||||||
|
import * as smartdata from 'smartdata';
|
||||||
|
|
||||||
|
const smartdataDb = new smartdata.SmartdataDb({
|
||||||
|
mongoDbUrl: '//someurl',
|
||||||
|
mongoDbName: 'myDatabase',
|
||||||
|
mongoDbPass: 'mypassword',
|
||||||
|
});
|
||||||
|
|
||||||
|
await smartdataDb.connect();
|
||||||
|
```
|
||||||
|
|
||||||
|
### class DbCollection
|
||||||
|
|
||||||
|
represents a collection of objects.
|
||||||
|
A collection is defined by the object class (that is extending smartdata.dbdoc) it respresents
|
||||||
|
|
||||||
|
So to get to get access to a specific collection you document
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Assuming toplevel await
|
||||||
|
// continues from the block before...
|
||||||
|
|
||||||
|
@smartdata.Collection(smartdataDb)
|
||||||
|
class MyObject extends smartdata.DbDoc<MyObject /* ,[an optional interface to implement] */> {
|
||||||
|
// read the next block about DbDoc
|
||||||
|
@smartdata.svDb()
|
||||||
|
property1: string; // @smartdata.svDb() marks the property for db save
|
||||||
|
|
||||||
|
property2: number; // this one is not marked, so it won't be save upon calling this.save()
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(); // the super call is important ;) But you probably know that.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// start to instantiate instances of classes from scratch or database
|
||||||
|
|
||||||
|
const localObject = new MyObject({
|
||||||
|
property1: 'hi',
|
||||||
|
property2: {
|
||||||
|
deep: 3,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
await localObject.save(); // saves the object to the database
|
||||||
|
|
||||||
|
// start retrieving instances
|
||||||
|
|
||||||
|
// .getInstance is staticly inheritied, yet fully typed static function to get instances with fully typed filters
|
||||||
|
const myInstance = await MyObject.getInstance({
|
||||||
|
property1: 'hi',
|
||||||
|
property2: {
|
||||||
|
deep: {
|
||||||
|
$gt: 2,
|
||||||
|
} as any,
|
||||||
|
},
|
||||||
|
}); // outputs a new instance of MyObject with the values from db assigned
|
||||||
|
```
|
||||||
|
|
||||||
|
### class DbDoc
|
||||||
|
|
||||||
|
represents a individual document in a collection
|
||||||
|
and thereby is ideally suited to extend the class you want to actually store.
|
||||||
|
|
||||||
|
### CRUD operations
|
||||||
|
|
||||||
|
smartdata supports full CRUD operations
|
||||||
|
|
||||||
|
**Store** or **Update** instances of classes to MongoDB:
|
||||||
|
DbDoc extends your class with the following methods:
|
||||||
|
|
||||||
|
- async `.save()` will save (or update) the object you call it on only. Any referenced non-savable objects will not get stored.
|
||||||
|
- async `.saveDeep()` does the same like `.save()`.
|
||||||
|
In addition it will look for properties that reference an object
|
||||||
|
that extends DbDoc as well and call .saveDeep() on them as well.
|
||||||
|
Loops are prevented
|
||||||
|
|
||||||
|
**Get** a new class instance from MongoDB:
|
||||||
|
DbDoc exposes a static method that allows you specify a filter to retrieve a cloned class of the one you used to that doc at some point later in time:
|
||||||
|
|
||||||
|
- static async `.getInstance({ /* filter props here */ })` gets you an instance that has the data of the first matched document as properties.
|
||||||
|
- static async `getInstances({ /* filter props here */ })` get you an array instances (one instance for every matched document).
|
||||||
|
|
||||||
|
**Delete** instances from MongoDb:
|
||||||
|
smartdata extends your class with a method to easily delete the doucment from DB:
|
||||||
|
|
||||||
|
- async `.delete()`will delete the document from DB.
|
||||||
|
|
||||||
|
## TypeScript
|
||||||
|
|
||||||
|
How does TypeScript play into this?
|
||||||
|
Since you define your classes in TypeScript and types flow through smartdata in a generic way
|
||||||
|
you should get all the Intellisense and type checking you love when using smartdata.
|
||||||
|
smartdata itself also bundles typings. You don't need to install any additional types for smartdata.
|
||||||
|
|
||||||
|
## Contribution
|
||||||
|
|
||||||
|
We are always happy for code contributions. If you are not the code contributing type that is ok. Still, maintaining Open Source repositories takes considerable time and thought. If you like the quality of what we do and our modules are useful to you we would appreciate a little monthly contribution: You can [contribute one time](https://lossless.link/contribute-onetime) or [contribute monthly](https://lossless.link/contribute). :)
|
||||||
|
|
||||||
|
For further information read the linked docs at the top of this readme.
|
||||||
|
|
||||||
|
## Legal
|
||||||
|
> MIT licensed | **©** [Task Venture Capital GmbH](https://task.vc)
|
||||||
|
| By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy)
|
104
test/test.distributedcoordinator.ts
Normal file
104
test/test.distributedcoordinator.ts
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import { tap, expect } from '@push.rocks/tapbundle';
|
||||||
|
import * as smartmongo from '@push.rocks/smartmongo';
|
||||||
|
import type * as taskbuffer from '@push.rocks/taskbuffer';
|
||||||
|
|
||||||
|
import * as smartdata from '../ts/index.js';
|
||||||
|
import { SmartdataDistributedCoordinator, DistributedClass } from '../ts/smartdata.classes.distributedcoordinator.js'; // path might need adjusting
|
||||||
|
const totalInstances = 10;
|
||||||
|
|
||||||
|
// =======================================
|
||||||
|
// Connecting to the database server
|
||||||
|
// =======================================
|
||||||
|
|
||||||
|
let smartmongoInstance: smartmongo.SmartMongo;
|
||||||
|
let testDb: smartdata.SmartdataDb;
|
||||||
|
|
||||||
|
tap.test('should create a testinstance as database', async () => {
|
||||||
|
smartmongoInstance = await smartmongo.SmartMongo.createAndStart();
|
||||||
|
testDb = new smartdata.SmartdataDb(await smartmongoInstance.getMongoDescriptor());
|
||||||
|
await testDb.init();
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('should instantiate DistributedClass', async (tools) => {
|
||||||
|
const instance = new DistributedClass();
|
||||||
|
expect(instance).toBeInstanceOf(DistributedClass);
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('DistributedClass should update the time', async (tools) => {
|
||||||
|
const distributedCoordinator = new SmartdataDistributedCoordinator(testDb);
|
||||||
|
await distributedCoordinator.start();
|
||||||
|
console.log('test: started');
|
||||||
|
const initialTime = distributedCoordinator.ownInstance.data.lastUpdated;
|
||||||
|
await distributedCoordinator.sendHeartbeat();
|
||||||
|
console.log('test: sent heartbeat');
|
||||||
|
const updatedTime = distributedCoordinator.ownInstance.data.lastUpdated;
|
||||||
|
expect(updatedTime).toBeGreaterThan(initialTime);
|
||||||
|
await distributedCoordinator.stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('should instantiate SmartdataDistributedCoordinator', async (tools) => {
|
||||||
|
const coordinator = new SmartdataDistributedCoordinator(testDb);
|
||||||
|
await coordinator.start();
|
||||||
|
expect(coordinator).toBeInstanceOf(SmartdataDistributedCoordinator);
|
||||||
|
await coordinator.stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('SmartdataDistributedCoordinator should update leader status', async (tools) => {
|
||||||
|
const coordinator = new SmartdataDistributedCoordinator(testDb);
|
||||||
|
await coordinator.start();
|
||||||
|
await coordinator.checkAndMaybeLead();
|
||||||
|
expect(coordinator.ownInstance.data.elected).toBeOneOf([true, false]);
|
||||||
|
await coordinator.stop();
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('SmartdataDistributedCoordinator should handle distributed task requests', async (tools) => {
|
||||||
|
const coordinator = new SmartdataDistributedCoordinator(testDb);
|
||||||
|
await coordinator.start();
|
||||||
|
|
||||||
|
const mockTaskRequest: taskbuffer.distributedCoordination.IDistributedTaskRequest = {
|
||||||
|
submitterId: "mockSubmitter12345", // Some unique mock submitter ID
|
||||||
|
taskName: "SampleTask",
|
||||||
|
taskVersion: "1.0.0", // Assuming it's a version string
|
||||||
|
taskExecutionTime: Date.now(),
|
||||||
|
taskExecutionTimeout: 60000, // Let's say the timeout is 1 minute (60000 ms)
|
||||||
|
taskExecutionParallel: 5, // Let's assume max 5 parallel executions
|
||||||
|
status: 'requesting'
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await coordinator.fireDistributedTaskRequest(mockTaskRequest);
|
||||||
|
expect(response).toBeTruthy(); // based on your expected structure for the response
|
||||||
|
await coordinator.stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('SmartdataDistributedCoordinator should update distributed task requests', async (tools) => {
|
||||||
|
const coordinator = new SmartdataDistributedCoordinator(testDb);
|
||||||
|
|
||||||
|
await coordinator.start();
|
||||||
|
|
||||||
|
const mockTaskRequest: taskbuffer.distributedCoordination.IDistributedTaskRequest = {
|
||||||
|
submitterId: "mockSubmitter12345", // Some unique mock submitter ID
|
||||||
|
taskName: "SampleTask",
|
||||||
|
taskVersion: "1.0.0", // Assuming it's a version string
|
||||||
|
taskExecutionTime: Date.now(),
|
||||||
|
taskExecutionTimeout: 60000, // Let's say the timeout is 1 minute (60000 ms)
|
||||||
|
taskExecutionParallel: 5, // Let's assume max 5 parallel executions
|
||||||
|
status: 'requesting'
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
await coordinator.updateDistributedTaskRequest(mockTaskRequest);
|
||||||
|
// Here, we can potentially check if a DB entry got updated or some other side-effect of the update method.
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('should elect only one leader amongst multiple instances', async (tools) => {
|
||||||
|
const coordinators = Array.from({ length: totalInstances }).map(() => new SmartdataDistributedCoordinator(testDb));
|
||||||
|
await Promise.all(coordinators.map(coordinator => coordinator.init()));
|
||||||
|
|
||||||
|
await Promise.all(coordinators.map(coordinator => coordinator.checkAndMaybeLead()));
|
||||||
|
|
||||||
|
const leaders = coordinators.filter(coordinator => coordinator.ownInstance.data.elected);
|
||||||
|
expect(leaders.length).toEqual(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.start({ throwOnError: true });
|
55
test/test.easystore.ts
Normal file
55
test/test.easystore.ts
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import { tap, expect } from '@push.rocks/tapbundle';
|
||||||
|
import { Qenv } from '@push.rocks/qenv';
|
||||||
|
import * as smartmongo from '@push.rocks/smartmongo';
|
||||||
|
import { smartunique } from '../ts/smartdata.plugins.js';
|
||||||
|
|
||||||
|
const testQenv = new Qenv(process.cwd(), process.cwd() + '/.nogit/');
|
||||||
|
|
||||||
|
console.log(process.memoryUsage());
|
||||||
|
|
||||||
|
// the tested module
|
||||||
|
import * as smartdata from '../ts/index.js';
|
||||||
|
|
||||||
|
// =======================================
|
||||||
|
// Connecting to the database server
|
||||||
|
// =======================================
|
||||||
|
|
||||||
|
let smartmongoInstance: smartmongo.SmartMongo;
|
||||||
|
let testDb: smartdata.SmartdataDb;
|
||||||
|
|
||||||
|
tap.test('should create a testinstance as database', async () => {
|
||||||
|
smartmongoInstance = await smartmongo.SmartMongo.createAndStart();
|
||||||
|
testDb = new smartdata.SmartdataDb(await smartmongoInstance.getMongoDescriptor());
|
||||||
|
await testDb.init();
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.skip.test('should connect to atlas', async (tools) => {
|
||||||
|
const databaseName = `test-smartdata-${smartunique.shortId()}`;
|
||||||
|
testDb = new smartdata.SmartdataDb({
|
||||||
|
mongoDbUrl: testQenv.getEnvVarOnDemand('MONGO_URL'),
|
||||||
|
mongoDbName: databaseName,
|
||||||
|
});
|
||||||
|
await testDb.init();
|
||||||
|
});
|
||||||
|
|
||||||
|
let easyStore: smartdata.EasyStore<{
|
||||||
|
key1: string;
|
||||||
|
key2: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
tap.test('should create an easystore', async () => {
|
||||||
|
easyStore = await testDb.createEasyStore('hellothere');
|
||||||
|
await easyStore.writeKey('key1', 'hello');
|
||||||
|
const retrievedKey = await easyStore.readKey('key1');
|
||||||
|
expect(retrievedKey).toEqual('hello');
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('close', async () => {
|
||||||
|
await testDb.mongoDb.dropDatabase();
|
||||||
|
await testDb.close();
|
||||||
|
if (smartmongoInstance) {
|
||||||
|
await smartmongoInstance.stop();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.start();
|
230
test/test.ts
230
test/test.ts
@ -1,30 +1,40 @@
|
|||||||
import { tap, expect } from 'tapbundle'
|
import { tap, expect } from '@push.rocks/tapbundle';
|
||||||
import * as smartq from 'smartq'
|
import { Qenv } from '@push.rocks/qenv';
|
||||||
import { Qenv } from 'qenv'
|
import * as smartmongo from '@push.rocks/smartmongo';
|
||||||
|
import { smartunique } from '../ts/smartdata.plugins.js';
|
||||||
|
|
||||||
let testQenv = new Qenv(process.cwd(), process.cwd() + '/.nogit/')
|
import * as mongodb from 'mongodb';
|
||||||
|
|
||||||
|
const testQenv = new Qenv(process.cwd(), process.cwd() + '/.nogit/');
|
||||||
|
|
||||||
|
console.log(process.memoryUsage());
|
||||||
|
|
||||||
// the tested module
|
// the tested module
|
||||||
import * as smartdata from '../ts/index'
|
import * as smartdata from '../ts/index.js';
|
||||||
import { smartstring } from '../ts/smartdata.plugins';
|
|
||||||
|
|
||||||
// =======================================
|
// =======================================
|
||||||
// Connecting to the database server
|
// Connecting to the database server
|
||||||
// =======================================
|
// =======================================
|
||||||
|
|
||||||
let testDb = new smartdata.Db({
|
let smartmongoInstance: smartmongo.SmartMongo;
|
||||||
db: process.env.RDB_DB,
|
let testDb: smartdata.SmartdataDb;
|
||||||
host: process.env.RDB_HOST,
|
|
||||||
user: process.env.RDB_USER,
|
|
||||||
password: process.env.RDB_PASS,
|
|
||||||
port: parseInt(process.env.RDB_PORT)
|
|
||||||
})
|
|
||||||
testDb.setSsl(process.env.RDB_CERT, 'base64')
|
|
||||||
|
|
||||||
tap.test('should establish a connection to the rethink Db cluster', async () => {
|
const totalCars = 2000;
|
||||||
|
|
||||||
await testDb.connect()
|
tap.test('should create a testinstance as database', async () => {
|
||||||
})
|
smartmongoInstance = await smartmongo.SmartMongo.createAndStart();
|
||||||
|
testDb = new smartdata.SmartdataDb(await smartmongoInstance.getMongoDescriptor());
|
||||||
|
await testDb.init();
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.skip.test('should connect to atlas', async (tools) => {
|
||||||
|
const databaseName = `test-smartdata-${smartunique.shortId()}`;
|
||||||
|
testDb = new smartdata.SmartdataDb({
|
||||||
|
mongoDbUrl: await testQenv.getEnvVarOnDemand('MONGO_URL'),
|
||||||
|
mongoDbName: databaseName,
|
||||||
|
});
|
||||||
|
await testDb.init();
|
||||||
|
});
|
||||||
|
|
||||||
// =======================================
|
// =======================================
|
||||||
// The actual tests
|
// The actual tests
|
||||||
@ -34,28 +44,180 @@ tap.test('should establish a connection to the rethink Db cluster', async () =>
|
|||||||
// Collections
|
// Collections
|
||||||
// ------
|
// ------
|
||||||
|
|
||||||
@smartdata.Collection(testDb)
|
@smartdata.Collection(() => {
|
||||||
class Car extends smartdata.DbDoc<Car> {
|
return testDb;
|
||||||
@smartdata.svDb() color: string
|
})
|
||||||
@smartdata.svDb() brand: string
|
class Car extends smartdata.SmartDataDbDoc<Car, Car> {
|
||||||
constructor (colorArg: string, brandArg: string) {
|
@smartdata.unI()
|
||||||
super()
|
public index: string = smartunique.shortId();
|
||||||
this.color = colorArg
|
|
||||||
this.brand = brandArg
|
@smartdata.svDb()
|
||||||
|
public color: string;
|
||||||
|
|
||||||
|
@smartdata.svDb()
|
||||||
|
public brand: string;
|
||||||
|
|
||||||
|
@smartdata.svDb()
|
||||||
|
public testBuffer = Buffer.from('hello');
|
||||||
|
|
||||||
|
@smartdata.svDb()
|
||||||
|
deepData = {
|
||||||
|
sodeep: 'yes',
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(colorArg: string, brandArg: string) {
|
||||||
|
super();
|
||||||
|
this.color = colorArg;
|
||||||
|
this.brand = brandArg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tap.test('should save the car to the db', async () => {
|
tap.test('should save the car to the db', async (toolsArg) => {
|
||||||
const myCar = new Car('red','Volvo')
|
const myCar = new Car('red', 'Volvo');
|
||||||
await myCar.save()
|
await myCar.save();
|
||||||
})
|
|
||||||
|
|
||||||
|
const myCar2 = new Car('red', 'Volvo');
|
||||||
|
await myCar2.save();
|
||||||
|
|
||||||
|
let counter = 0;
|
||||||
|
|
||||||
|
const gottenCarInstance = await Car.getInstance({});
|
||||||
|
console.log(gottenCarInstance.testBuffer instanceof mongodb.Binary);
|
||||||
|
process.memoryUsage();
|
||||||
|
do {
|
||||||
|
const myCar3 = new Car('red', 'Renault');
|
||||||
|
await myCar3.save();
|
||||||
|
counter++;
|
||||||
|
if (counter % 100 === 0) {
|
||||||
|
console.log(
|
||||||
|
`Filled database with ${counter} of ${totalCars} Cars and memory usage ${
|
||||||
|
process.memoryUsage().rss / 1e6
|
||||||
|
} MB`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} while (counter < totalCars);
|
||||||
|
console.log(process.memoryUsage());
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('expect to get instance of Car with shallow match', async () => {
|
||||||
|
const totalQueryCycles = totalCars / 2;
|
||||||
|
let counter = 0;
|
||||||
|
do {
|
||||||
|
const timeStart = Date.now();
|
||||||
|
const myCars = await Car.getInstances({
|
||||||
|
brand: 'Renault',
|
||||||
|
});
|
||||||
|
if (counter % 10 === 0) {
|
||||||
|
console.log(
|
||||||
|
`performed ${counter} of ${totalQueryCycles} total query cycles: took ${
|
||||||
|
Date.now() - timeStart
|
||||||
|
}ms to query a set of 2000 with memory footprint ${process.memoryUsage().rss / 1e6} MB`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
expect(myCars[0].deepData.sodeep).toEqual('yes');
|
||||||
|
expect(myCars[0].brand).toEqual('Renault');
|
||||||
|
counter++;
|
||||||
|
} while (counter < totalQueryCycles);
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('expect to get instance of Car with deep match', async () => {
|
||||||
|
const totalQueryCycles = totalCars / 6;
|
||||||
|
let counter = 0;
|
||||||
|
do {
|
||||||
|
const timeStart = Date.now();
|
||||||
|
const myCars2 = await Car.getInstances({
|
||||||
|
deepData: {
|
||||||
|
sodeep: 'yes',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (counter % 10 === 0) {
|
||||||
|
console.log(
|
||||||
|
`performed ${counter} of ${totalQueryCycles} total query cycles: took ${
|
||||||
|
Date.now() - timeStart
|
||||||
|
}ms to deep query a set of 2000 with memory footprint ${process.memoryUsage().rss / 1e6} MB`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
expect(myCars2[0].deepData.sodeep).toEqual('yes');
|
||||||
|
expect(myCars2[0].brand).toEqual('Volvo');
|
||||||
|
counter++;
|
||||||
|
} while (counter < totalQueryCycles);
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('expect to get instance of Car and update it', async () => {
|
||||||
|
const myCar = await Car.getInstance<Car>({
|
||||||
|
brand: 'Volvo',
|
||||||
|
});
|
||||||
|
expect(myCar.color).toEqual('red');
|
||||||
|
myCar.color = 'blue';
|
||||||
|
await myCar.save();
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('should be able to delete an instance of car', async () => {
|
||||||
|
const myCars = await Car.getInstances({
|
||||||
|
brand: 'Volvo',
|
||||||
|
color: 'blue',
|
||||||
|
});
|
||||||
|
console.log(myCars);
|
||||||
|
expect(myCars[0].color).toEqual('blue');
|
||||||
|
for (const myCar of myCars) {
|
||||||
|
await myCar.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
const myCar2 = await Car.getInstance<Car>({
|
||||||
|
brand: 'Volvo',
|
||||||
|
});
|
||||||
|
expect(myCar2.color).toEqual('red');
|
||||||
|
});
|
||||||
|
|
||||||
|
// tslint:disable-next-line: max-classes-per-file
|
||||||
|
@smartdata.Collection(() => {
|
||||||
|
return testDb;
|
||||||
|
})
|
||||||
|
class Truck extends smartdata.SmartDataDbDoc<Car, Car> {
|
||||||
|
@smartdata.unI()
|
||||||
|
public id: string = smartunique.shortId();
|
||||||
|
|
||||||
|
@smartdata.svDb()
|
||||||
|
public color: string;
|
||||||
|
|
||||||
|
@smartdata.svDb()
|
||||||
|
public brand: string;
|
||||||
|
|
||||||
|
constructor(colorArg: string, brandArg: string) {
|
||||||
|
super();
|
||||||
|
this.color = colorArg;
|
||||||
|
this.brand = brandArg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tap.test('should store a new Truck', async () => {
|
||||||
|
const truck = new Truck('blue', 'MAN');
|
||||||
|
await truck.save();
|
||||||
|
const myTruck2 = await Truck.getInstance({ color: 'blue' });
|
||||||
|
myTruck2.color = 'red';
|
||||||
|
await myTruck2.save();
|
||||||
|
const myTruck3 = await Truck.getInstance({ color: 'blue' });
|
||||||
|
console.log(myTruck3);
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('should use a cursor', async () => {
|
||||||
|
const cursor = await Car.getCursor({});
|
||||||
|
let counter = 0;
|
||||||
|
await cursor.forEach(async (carArg) => {
|
||||||
|
counter++;
|
||||||
|
counter % 50 === 0 ? console.log(`50 more of ${carArg.color}`) : null;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// =======================================
|
// =======================================
|
||||||
// close the database connection
|
// close the database connection
|
||||||
// =======================================
|
// =======================================
|
||||||
tap.test('should close the database connection', async (tools) => {
|
tap.test('close', async () => {
|
||||||
await testDb.close()
|
await testDb.mongoDb.dropDatabase();
|
||||||
})
|
await testDb.close();
|
||||||
|
if (smartmongoInstance) {
|
||||||
|
await smartmongoInstance.stop();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
tap.start()
|
tap.start({ throwOnError: true });
|
||||||
|
95
test/test.typescript.ts
Normal file
95
test/test.typescript.ts
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
import { tap, expect } from '@push.rocks/tapbundle';
|
||||||
|
import { Qenv } from '@push.rocks/qenv';
|
||||||
|
import * as smartmongo from '@push.rocks/smartmongo';
|
||||||
|
import { smartunique } from '../ts/smartdata.plugins.js';
|
||||||
|
|
||||||
|
const testQenv = new Qenv(process.cwd(), process.cwd() + '/.nogit/');
|
||||||
|
|
||||||
|
console.log(process.memoryUsage());
|
||||||
|
|
||||||
|
// the tested module
|
||||||
|
import * as smartdata from '../ts/index.js';
|
||||||
|
|
||||||
|
// =======================================
|
||||||
|
// Connecting to the database server
|
||||||
|
// =======================================
|
||||||
|
|
||||||
|
let smartmongoInstance: smartmongo.SmartMongo;
|
||||||
|
let testDb: smartdata.SmartdataDb;
|
||||||
|
|
||||||
|
const totalCars = 2000;
|
||||||
|
|
||||||
|
tap.test('should create a testinstance as database', async () => {
|
||||||
|
smartmongoInstance = await smartmongo.SmartMongo.createAndStart();
|
||||||
|
testDb = new smartdata.SmartdataDb(await smartmongoInstance.getMongoDescriptor());
|
||||||
|
await testDb.init();
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.skip.test('should connect to atlas', async (tools) => {
|
||||||
|
const databaseName = `test-smartdata-${smartunique.shortId()}`;
|
||||||
|
testDb = new smartdata.SmartdataDb({
|
||||||
|
mongoDbUrl: await testQenv.getEnvVarOnDemand('MONGO_URL'),
|
||||||
|
mongoDbName: databaseName,
|
||||||
|
});
|
||||||
|
await testDb.init();
|
||||||
|
});
|
||||||
|
|
||||||
|
// =======================================
|
||||||
|
// The actual tests
|
||||||
|
// =======================================
|
||||||
|
|
||||||
|
// ------
|
||||||
|
// Collections
|
||||||
|
// ------
|
||||||
|
@smartdata.Manager()
|
||||||
|
class Car extends smartdata.SmartDataDbDoc<Car, Car> {
|
||||||
|
@smartdata.unI()
|
||||||
|
public index: string = smartunique.shortId();
|
||||||
|
|
||||||
|
@smartdata.svDb()
|
||||||
|
public color: string;
|
||||||
|
|
||||||
|
@smartdata.svDb()
|
||||||
|
public brand: string;
|
||||||
|
|
||||||
|
@smartdata.svDb()
|
||||||
|
deepData = {
|
||||||
|
sodeep: 'yes',
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(colorArg: string, brandArg: string) {
|
||||||
|
super();
|
||||||
|
this.color = colorArg;
|
||||||
|
this.brand = brandArg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const createCarClass = (dbArg: smartdata.SmartdataDb) => {
|
||||||
|
smartdata.setDefaultManagerForDoc({ db: dbArg }, Car);
|
||||||
|
return Car;
|
||||||
|
};
|
||||||
|
|
||||||
|
tap.test('should produce a car', async () => {
|
||||||
|
const CarClass = createCarClass(testDb);
|
||||||
|
const carInstance = new CarClass('red', 'Mercedes');
|
||||||
|
await carInstance.save();
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('should get a car', async () => {
|
||||||
|
const car = Car.getInstance({
|
||||||
|
color: 'red',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// =======================================
|
||||||
|
// close the database connection
|
||||||
|
// =======================================
|
||||||
|
tap.test('close', async () => {
|
||||||
|
await testDb.mongoDb.dropDatabase();
|
||||||
|
await testDb.close();
|
||||||
|
if (smartmongoInstance) {
|
||||||
|
await smartmongoInstance.stop();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.start({ throwOnError: true });
|
74
test/test.watch.ts
Normal file
74
test/test.watch.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import { tap, expect } from '@push.rocks/tapbundle';
|
||||||
|
import { Qenv } from '@push.rocks/qenv';
|
||||||
|
import * as smartmongo from '@push.rocks/smartmongo';
|
||||||
|
import { smartunique } from '../ts/smartdata.plugins.js';
|
||||||
|
|
||||||
|
const testQenv = new Qenv(process.cwd(), process.cwd() + '/.nogit/');
|
||||||
|
|
||||||
|
console.log(process.memoryUsage());
|
||||||
|
|
||||||
|
// the tested module
|
||||||
|
import * as smartdata from '../ts/index.js';
|
||||||
|
|
||||||
|
// =======================================
|
||||||
|
// Connecting to the database server
|
||||||
|
// =======================================
|
||||||
|
|
||||||
|
let smartmongoInstance: smartmongo.SmartMongo;
|
||||||
|
let testDb: smartdata.SmartdataDb;
|
||||||
|
|
||||||
|
const totalCars = 2000;
|
||||||
|
|
||||||
|
tap.test('should create a testinstance as database', async () => {
|
||||||
|
smartmongoInstance = await smartmongo.SmartMongo.createAndStart();
|
||||||
|
testDb = new smartdata.SmartdataDb(await smartmongoInstance.getMongoDescriptor());
|
||||||
|
await testDb.init();
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.skip.test('should connect to atlas', async (tools) => {
|
||||||
|
const databaseName = `test-smartdata-${smartunique.shortId()}`;
|
||||||
|
testDb = new smartdata.SmartdataDb({
|
||||||
|
mongoDbUrl: testQenv.getEnvVarOnDemand('MONGO_URL'),
|
||||||
|
mongoDbName: databaseName,
|
||||||
|
});
|
||||||
|
await testDb.init();
|
||||||
|
});
|
||||||
|
|
||||||
|
@smartdata.Collection(() => testDb)
|
||||||
|
class House extends smartdata.SmartDataDbDoc<House, House> {
|
||||||
|
@smartdata.unI()
|
||||||
|
public id: string = smartunique.shortId();
|
||||||
|
|
||||||
|
@smartdata.svDb()
|
||||||
|
public data = {
|
||||||
|
id: smartunique.shortId(),
|
||||||
|
hello: 'hello',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
tap.test('should watch a collection', async (toolsArg) => {
|
||||||
|
const done = toolsArg.defer();
|
||||||
|
const watcher = await House.watch({});
|
||||||
|
watcher.changeSubject.subscribe(async (houseArg) => {
|
||||||
|
console.log('hey there, we observed a house');
|
||||||
|
await watcher.close();
|
||||||
|
done.resolve();
|
||||||
|
});
|
||||||
|
const newHouse = new House();
|
||||||
|
await newHouse.save();
|
||||||
|
console.log('saved a house');
|
||||||
|
await done.promise;
|
||||||
|
});
|
||||||
|
|
||||||
|
// =======================================
|
||||||
|
// close the database connection
|
||||||
|
// =======================================
|
||||||
|
tap.test('close', async () => {
|
||||||
|
await testDb.mongoDb.dropDatabase();
|
||||||
|
await testDb.close();
|
||||||
|
if (smartmongoInstance) {
|
||||||
|
await smartmongoInstance.stop();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.start({ throwOnError: true });
|
8
ts/00_commitinfo_data.ts
Normal file
8
ts/00_commitinfo_data.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* autocreated commitinfo by @pushrocks/commitinfo
|
||||||
|
*/
|
||||||
|
export const commitinfo = {
|
||||||
|
name: '@push.rocks/smartdata',
|
||||||
|
version: '5.0.26',
|
||||||
|
description: 'do more with data'
|
||||||
|
}
|
17
ts/index.ts
17
ts/index.ts
@ -1,3 +1,14 @@
|
|||||||
export * from './smartdata.classes.db'
|
export * from './smartdata.classes.db.js';
|
||||||
export * from './smartdata.classes.dbcollection'
|
export * from './smartdata.classes.collection.js';
|
||||||
export * from './smartdata.classes.dbdoc'
|
export * from './smartdata.classes.doc.js';
|
||||||
|
export * from './smartdata.classes.easystore.js';
|
||||||
|
export * from './smartdata.classes.cursor.js';
|
||||||
|
|
||||||
|
import * as convenience from './smartadata.convenience.js';
|
||||||
|
|
||||||
|
export { convenience };
|
||||||
|
|
||||||
|
// to be removed with the next breaking update
|
||||||
|
import type * as plugins from './smartdata.plugins.js';
|
||||||
|
type IMongoDescriptor = plugins.tsclass.database.IMongoDescriptor;
|
||||||
|
export type { IMongoDescriptor };
|
||||||
|
5
ts/smartadata.convenience.ts
Normal file
5
ts/smartadata.convenience.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import * as plugins from './smartdata.plugins.js';
|
||||||
|
|
||||||
|
export const getNewUniqueId = async (prefixArg?: string) => {
|
||||||
|
return plugins.smartunique.uni(prefixArg);
|
||||||
|
};
|
284
ts/smartdata.classes.collection.ts
Normal file
284
ts/smartdata.classes.collection.ts
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
import * as plugins from './smartdata.plugins.js';
|
||||||
|
import { SmartdataDb } from './smartdata.classes.db.js';
|
||||||
|
import { SmartdataDbCursor } from './smartdata.classes.cursor.js';
|
||||||
|
import { SmartDataDbDoc } from './smartdata.classes.doc.js';
|
||||||
|
import { SmartdataDbWatcher } from './smartdata.classes.watcher.js';
|
||||||
|
import { CollectionFactory } from './smartdata.classes.collectionfactory.js';
|
||||||
|
|
||||||
|
export interface IFindOptions {
|
||||||
|
limit?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export interface IDocValidationFunc<T> {
|
||||||
|
(doc: T): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TDelayed<TDelayedArg> = () => TDelayedArg;
|
||||||
|
|
||||||
|
const collectionFactory = new CollectionFactory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a decorator that will tell the decorated class what dbTable to use
|
||||||
|
* @param dbArg
|
||||||
|
*/
|
||||||
|
export function Collection(dbArg: SmartdataDb | TDelayed<SmartdataDb>) {
|
||||||
|
return function classDecorator<T extends { new (...args: any[]): {} }>(constructor: T) {
|
||||||
|
return class extends constructor {
|
||||||
|
public static get collection() {
|
||||||
|
if (!(dbArg instanceof SmartdataDb)) {
|
||||||
|
dbArg = dbArg();
|
||||||
|
}
|
||||||
|
return collectionFactory.getCollection(constructor.name, dbArg);
|
||||||
|
}
|
||||||
|
public get collection() {
|
||||||
|
if (!(dbArg instanceof SmartdataDb)) {
|
||||||
|
dbArg = dbArg();
|
||||||
|
}
|
||||||
|
return collectionFactory.getCollection(constructor.name, dbArg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IManager {
|
||||||
|
db: SmartdataDb;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const setDefaultManagerForDoc = <T>(managerArg: IManager, dbDocArg: T): T => {
|
||||||
|
(dbDocArg as any).prototype.defaultManager = managerArg;
|
||||||
|
return dbDocArg;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a decorator that will tell the decorated class what dbTable to use
|
||||||
|
* @param dbArg
|
||||||
|
*/
|
||||||
|
export function Manager<TManager extends IManager>(managerArg?: TManager | TDelayed<TManager>) {
|
||||||
|
return function classDecorator<T extends { new (...args: any[]): any }>(constructor: T) {
|
||||||
|
return class extends constructor {
|
||||||
|
public static get collection() {
|
||||||
|
let dbArg: SmartdataDb;
|
||||||
|
if (!managerArg) {
|
||||||
|
dbArg = this.prototype.defaultManager.db;
|
||||||
|
} else if (managerArg['db']) {
|
||||||
|
dbArg = (managerArg as TManager).db;
|
||||||
|
} else {
|
||||||
|
dbArg = (managerArg as TDelayed<TManager>)().db;
|
||||||
|
}
|
||||||
|
return collectionFactory.getCollection(constructor.name, dbArg);
|
||||||
|
}
|
||||||
|
public get collection() {
|
||||||
|
let dbArg: SmartdataDb;
|
||||||
|
if (!managerArg) {
|
||||||
|
//console.log(this.defaultManager.db);
|
||||||
|
//process.exit(0)
|
||||||
|
dbArg = this.defaultManager.db;
|
||||||
|
} else if (managerArg['db']) {
|
||||||
|
dbArg = (managerArg as TManager).db;
|
||||||
|
} else {
|
||||||
|
dbArg = (managerArg as TDelayed<TManager>)().db;
|
||||||
|
}
|
||||||
|
return collectionFactory.getCollection(constructor.name, dbArg);
|
||||||
|
}
|
||||||
|
public static get manager() {
|
||||||
|
let manager: TManager;
|
||||||
|
if (!managerArg) {
|
||||||
|
manager = this.prototype.defaultManager;
|
||||||
|
} else if (managerArg['db']) {
|
||||||
|
manager = managerArg as TManager;
|
||||||
|
} else {
|
||||||
|
manager = (managerArg as TDelayed<TManager>)();
|
||||||
|
}
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
public get manager() {
|
||||||
|
let manager: TManager;
|
||||||
|
if (!managerArg) {
|
||||||
|
manager = this.defaultManager;
|
||||||
|
} else if (managerArg['db']) {
|
||||||
|
manager = managerArg as TManager;
|
||||||
|
} else {
|
||||||
|
manager = (managerArg as TDelayed<TManager>)();
|
||||||
|
}
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SmartdataCollection<T> {
|
||||||
|
/**
|
||||||
|
* the collection that is used
|
||||||
|
*/
|
||||||
|
public mongoDbCollection: plugins.mongodb.Collection;
|
||||||
|
public objectValidation: IDocValidationFunc<T> = null;
|
||||||
|
public collectionName: string;
|
||||||
|
public smartdataDb: SmartdataDb;
|
||||||
|
public uniqueIndexes: string[] = [];
|
||||||
|
|
||||||
|
constructor(classNameArg: string, smartDataDbArg: SmartdataDb) {
|
||||||
|
// tell the collection where it belongs
|
||||||
|
this.collectionName = classNameArg;
|
||||||
|
this.smartdataDb = smartDataDbArg;
|
||||||
|
|
||||||
|
// tell the db class about it (important since Db uses different systems under the hood)
|
||||||
|
this.smartdataDb.addCollection(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* makes sure a collection exists within MongoDb that maps to the SmartdataCollection
|
||||||
|
*/
|
||||||
|
public async init() {
|
||||||
|
if (!this.mongoDbCollection) {
|
||||||
|
// connect this instance to a MongoDB collection
|
||||||
|
const availableMongoDbCollections = await this.smartdataDb.mongoDb.collections();
|
||||||
|
const wantedCollection = availableMongoDbCollections.find((collection) => {
|
||||||
|
return collection.collectionName === this.collectionName;
|
||||||
|
});
|
||||||
|
if (!wantedCollection) {
|
||||||
|
await this.smartdataDb.mongoDb.createCollection(this.collectionName);
|
||||||
|
console.log(`Successfully initiated Collection ${this.collectionName}`);
|
||||||
|
}
|
||||||
|
this.mongoDbCollection = this.smartdataDb.mongoDb.collection(this.collectionName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mark unique index
|
||||||
|
*/
|
||||||
|
public markUniqueIndexes(keyArrayArg: string[] = []) {
|
||||||
|
for (const key of keyArrayArg) {
|
||||||
|
if (!this.uniqueIndexes.includes(key)) {
|
||||||
|
this.mongoDbCollection.createIndex(key, {
|
||||||
|
unique: true,
|
||||||
|
});
|
||||||
|
// make sure we only call this once and not for every doc we create
|
||||||
|
this.uniqueIndexes.push(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adds a validation function that all newly inserted and updated objects have to pass
|
||||||
|
*/
|
||||||
|
public addDocValidation(funcArg: IDocValidationFunc<T>) {
|
||||||
|
this.objectValidation = funcArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* finds an object in the DbCollection
|
||||||
|
*/
|
||||||
|
public async findOne(filterObject: any): Promise<any> {
|
||||||
|
await this.init();
|
||||||
|
const cursor = this.mongoDbCollection.find(filterObject);
|
||||||
|
const result = await cursor.next();
|
||||||
|
cursor.close();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getCursor(
|
||||||
|
filterObjectArg: any,
|
||||||
|
dbDocArg: typeof SmartDataDbDoc
|
||||||
|
): Promise<SmartdataDbCursor<any>> {
|
||||||
|
await this.init();
|
||||||
|
const cursor = this.mongoDbCollection.find(filterObjectArg);
|
||||||
|
return new SmartdataDbCursor(cursor, dbDocArg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* finds an object in the DbCollection
|
||||||
|
*/
|
||||||
|
public async findAll(filterObject: any): Promise<any[]> {
|
||||||
|
await this.init();
|
||||||
|
const cursor = this.mongoDbCollection.find(filterObject);
|
||||||
|
const result = await cursor.toArray();
|
||||||
|
cursor.close();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* watches the collection while applying a filter
|
||||||
|
*/
|
||||||
|
public async watch(
|
||||||
|
filterObject: any,
|
||||||
|
smartdataDbDocArg: typeof SmartDataDbDoc
|
||||||
|
): Promise<SmartdataDbWatcher> {
|
||||||
|
await this.init();
|
||||||
|
const changeStream = this.mongoDbCollection.watch(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
$match: filterObject,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{
|
||||||
|
fullDocument: 'updateLookup',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const smartdataWatcher = new SmartdataDbWatcher(changeStream, smartdataDbDocArg);
|
||||||
|
await smartdataWatcher.readyDeferred.promise;
|
||||||
|
return smartdataWatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create an object in the database
|
||||||
|
*/
|
||||||
|
public async insert(dbDocArg: T & SmartDataDbDoc<T, unknown>): Promise<any> {
|
||||||
|
await this.init();
|
||||||
|
await this.checkDoc(dbDocArg);
|
||||||
|
this.markUniqueIndexes(dbDocArg.uniqueIndexes);
|
||||||
|
const saveableObject = await dbDocArg.createSavableObject();
|
||||||
|
const result = await this.mongoDbCollection.insertOne(saveableObject);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* inserts object into the DbCollection
|
||||||
|
*/
|
||||||
|
public async update(dbDocArg: T & SmartDataDbDoc<T, unknown>): Promise<any> {
|
||||||
|
await this.init();
|
||||||
|
await this.checkDoc(dbDocArg);
|
||||||
|
const identifiableObject = await dbDocArg.createIdentifiableObject();
|
||||||
|
const saveableObject = await dbDocArg.createSavableObject();
|
||||||
|
const updateableObject: any = {};
|
||||||
|
for (const key of Object.keys(saveableObject)) {
|
||||||
|
if (identifiableObject[key]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
updateableObject[key] = saveableObject[key];
|
||||||
|
}
|
||||||
|
const result = await this.mongoDbCollection.updateOne(
|
||||||
|
identifiableObject,
|
||||||
|
{ $set: updateableObject },
|
||||||
|
{ upsert: true }
|
||||||
|
);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async delete(dbDocArg: T & SmartDataDbDoc<T, unknown>): Promise<any> {
|
||||||
|
await this.init();
|
||||||
|
await this.checkDoc(dbDocArg);
|
||||||
|
const identifiableObject = await dbDocArg.createIdentifiableObject();
|
||||||
|
await this.mongoDbCollection.deleteOne(identifiableObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checks a Doc for constraints
|
||||||
|
* if this.objectValidation is not set it passes.
|
||||||
|
*/
|
||||||
|
private checkDoc(docArg: T): Promise<void> {
|
||||||
|
const done = plugins.smartq.defer<void>();
|
||||||
|
let validationResult = true;
|
||||||
|
if (this.objectValidation) {
|
||||||
|
validationResult = this.objectValidation(docArg);
|
||||||
|
}
|
||||||
|
if (validationResult) {
|
||||||
|
done.resolve();
|
||||||
|
} else {
|
||||||
|
done.reject('validation of object did not pass');
|
||||||
|
}
|
||||||
|
return done.promise;
|
||||||
|
}
|
||||||
|
}
|
19
ts/smartdata.classes.collectionfactory.ts
Normal file
19
ts/smartdata.classes.collectionfactory.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import * as plugins from './smartdata.plugins.js';
|
||||||
|
import { SmartdataCollection } from './smartdata.classes.collection.js';
|
||||||
|
import { SmartdataDb } from './smartdata.classes.db.js';
|
||||||
|
|
||||||
|
export class CollectionFactory {
|
||||||
|
public collections: { [key: string]: SmartdataCollection<any> } = {};
|
||||||
|
|
||||||
|
public getCollection = (nameArg: string, dbArg: SmartdataDb): SmartdataCollection<any> => {
|
||||||
|
if (!this.collections[nameArg]) {
|
||||||
|
this.collections[nameArg] = (() => {
|
||||||
|
if (dbArg instanceof SmartdataDb) {
|
||||||
|
// tslint:disable-next-line: no-string-literal
|
||||||
|
return new SmartdataCollection(nameArg, dbArg);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
return this.collections[nameArg];
|
||||||
|
};
|
||||||
|
}
|
46
ts/smartdata.classes.cursor.ts
Normal file
46
ts/smartdata.classes.cursor.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { SmartDataDbDoc } from './smartdata.classes.doc.js';
|
||||||
|
import * as plugins from './smartdata.plugins.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a wrapper for the native mongodb cursor. Exposes better
|
||||||
|
*/
|
||||||
|
export class SmartdataDbCursor<T = any> {
|
||||||
|
// STATIC
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
public mongodbCursor: plugins.mongodb.FindCursor<T>;
|
||||||
|
private smartdataDbDoc: typeof SmartDataDbDoc;
|
||||||
|
constructor(cursorArg: plugins.mongodb.FindCursor<T>, dbDocArg: typeof SmartDataDbDoc) {
|
||||||
|
this.mongodbCursor = cursorArg;
|
||||||
|
this.smartdataDbDoc = dbDocArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async next(closeAtEnd = true) {
|
||||||
|
const result = this.smartdataDbDoc.createInstanceFromMongoDbNativeDoc(
|
||||||
|
await this.mongodbCursor.next()
|
||||||
|
);
|
||||||
|
if (!result && closeAtEnd) {
|
||||||
|
await this.close();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async forEach(forEachFuncArg: (itemArg: T) => Promise<any>, closeCursorAtEnd = true) {
|
||||||
|
let nextDocument: any;
|
||||||
|
do {
|
||||||
|
nextDocument = await this.mongodbCursor.next();
|
||||||
|
if (nextDocument) {
|
||||||
|
const nextClassInstance =
|
||||||
|
this.smartdataDbDoc.createInstanceFromMongoDbNativeDoc(nextDocument);
|
||||||
|
await forEachFuncArg(nextClassInstance as any);
|
||||||
|
}
|
||||||
|
} while (nextDocument);
|
||||||
|
if (closeCursorAtEnd) {
|
||||||
|
await this.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async close() {
|
||||||
|
await this.mongodbCursor.close();
|
||||||
|
}
|
||||||
|
}
|
@ -1,41 +1,32 @@
|
|||||||
import * as plugins from './smartdata.plugins'
|
import * as plugins from './smartdata.plugins.js';
|
||||||
import { Objectmap } from 'lik'
|
|
||||||
|
|
||||||
import { DbTable } from './smartdata.classes.dbcollection'
|
import { SmartdataCollection } from './smartdata.classes.collection.js';
|
||||||
|
import { EasyStore } from './smartdata.classes.easystore.js';
|
||||||
|
|
||||||
import { Connection as dbConnection, ConnectionOptions } from 'rethinkdb'
|
import { logger } from './smartdata.logging.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* interface - indicates the connection status of the db
|
* interface - indicates the connection status of the db
|
||||||
*/
|
*/
|
||||||
export type TConnectionStatus = 'initial' | 'disconnected' | 'connected' | 'failed'
|
export type TConnectionStatus = 'initial' | 'disconnected' | 'connected' | 'failed';
|
||||||
|
|
||||||
export class Db {
|
export class SmartdataDb {
|
||||||
dbName: string
|
smartdataOptions: plugins.tsclass.database.IMongoDescriptor;
|
||||||
connectionOptions: plugins.rethinkDb.ConnectionOptions
|
mongoDbClient: plugins.mongodb.MongoClient;
|
||||||
dbConnection: plugins.rethinkDb.Connection
|
mongoDb: plugins.mongodb.Db;
|
||||||
status: TConnectionStatus
|
status: TConnectionStatus;
|
||||||
dbTablesMap = new Objectmap<DbTable<any>>()
|
statusConnectedDeferred = plugins.smartpromise.defer();
|
||||||
|
smartdataCollectionMap = new plugins.lik.ObjectMap<SmartdataCollection<any>>();
|
||||||
|
|
||||||
constructor(connectionOptionsArg: ConnectionOptions) {
|
constructor(smartdataOptions: plugins.tsclass.database.IMongoDescriptor) {
|
||||||
this.dbName = connectionOptionsArg.db
|
this.smartdataOptions = smartdataOptions;
|
||||||
this.connectionOptions = connectionOptionsArg
|
this.status = 'initial';
|
||||||
this.status = 'initial'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// easystore
|
||||||
* supply additional SSl options
|
public async createEasyStore(nameIdArg: string) {
|
||||||
*/
|
const easyStore = new EasyStore(nameIdArg, this);
|
||||||
setSsl (certificateStringArg: string, formatArg: 'base64' | 'clearText') {
|
return easyStore;
|
||||||
let certificateString: string
|
|
||||||
if(formatArg = 'base64') {
|
|
||||||
certificateString = plugins.smartstring.base64.decode(certificateStringArg)
|
|
||||||
} else {
|
|
||||||
certificateString = certificateStringArg
|
|
||||||
}
|
|
||||||
this.connectionOptions['ssl'] = {
|
|
||||||
ca: Buffer.from(certificateString)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// basic connection stuff ----------------------------------------------
|
// basic connection stuff ----------------------------------------------
|
||||||
@ -43,37 +34,51 @@ export class Db {
|
|||||||
/**
|
/**
|
||||||
* connects to the database that was specified during instance creation
|
* connects to the database that was specified during instance creation
|
||||||
*/
|
*/
|
||||||
async connect (): Promise<any> {
|
public async init(): Promise<any> {
|
||||||
this.dbConnection = await plugins.rethinkDb.connect(this.connectionOptions)
|
const finalConnectionUrl = this.smartdataOptions.mongoDbUrl
|
||||||
this.dbConnection.use(this.dbName)
|
.replace('<USERNAME>', this.smartdataOptions.mongoDbUser)
|
||||||
this.status = 'connected'
|
.replace('<username>', this.smartdataOptions.mongoDbUser)
|
||||||
plugins.beautylog.ok(`Connected to database ${this.dbName}`)
|
.replace('<USER>', this.smartdataOptions.mongoDbUser)
|
||||||
|
.replace('<user>', this.smartdataOptions.mongoDbUser)
|
||||||
|
.replace('<PASSWORD>', this.smartdataOptions.mongoDbPass)
|
||||||
|
.replace('<password>', this.smartdataOptions.mongoDbPass)
|
||||||
|
.replace('<DBNAME>', this.smartdataOptions.mongoDbName)
|
||||||
|
.replace('<dbname>', this.smartdataOptions.mongoDbName);
|
||||||
|
|
||||||
|
this.mongoDbClient = await plugins.mongodb.MongoClient.connect(finalConnectionUrl, {
|
||||||
|
maxPoolSize: 100,
|
||||||
|
maxIdleTimeMS: 10,
|
||||||
|
});
|
||||||
|
this.mongoDb = this.mongoDbClient.db(this.smartdataOptions.mongoDbName);
|
||||||
|
this.status = 'connected';
|
||||||
|
this.statusConnectedDeferred.resolve();
|
||||||
|
console.log(`Connected to database ${this.smartdataOptions.mongoDbName}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* closes the connection to the databse
|
* closes the connection to the databse
|
||||||
*/
|
*/
|
||||||
async close (): Promise<any> {
|
public async close(): Promise<any> {
|
||||||
await this.dbConnection.close()
|
await this.mongoDbClient.close();
|
||||||
this.status = 'disconnected'
|
this.status = 'disconnected';
|
||||||
plugins.beautylog.ok(`disconnected from database ${this.dbName}`)
|
logger.log('info', `disconnected from database ${this.smartdataOptions.mongoDbName}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle table to class distribution
|
// handle table to class distribution
|
||||||
|
|
||||||
|
public addCollection(SmartdataCollectionArg: SmartdataCollection<any>) {
|
||||||
|
this.smartdataCollectionMap.add(SmartdataCollectionArg);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a table's name and returns smartdata's DbTable class
|
* Gets a collection's name and returns a SmartdataCollection instance
|
||||||
* @param nameArg
|
* @param nameArg
|
||||||
* @returns DbTable
|
* @returns DbTable
|
||||||
*/
|
*/
|
||||||
async getDbTableByName<T>(nameArg: string): Promise<DbTable<T>> {
|
public async getSmartdataCollectionByName<T>(nameArg: string): Promise<SmartdataCollection<T>> {
|
||||||
let resultCollection = this.dbTablesMap.find((dbCollectionArg) => {
|
const resultCollection = await this.smartdataCollectionMap.find(async (dbTableArg) => {
|
||||||
return dbCollectionArg.tableName === nameArg
|
return dbTableArg.collectionName === nameArg;
|
||||||
})
|
});
|
||||||
return resultCollection
|
return resultCollection;
|
||||||
}
|
|
||||||
|
|
||||||
addTable (dbCollectionArg: DbTable<any>) {
|
|
||||||
this.dbTablesMap.add(dbCollectionArg)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,119 +0,0 @@
|
|||||||
import * as plugins from './smartdata.plugins'
|
|
||||||
import { Db } from './smartdata.classes.db'
|
|
||||||
import { DbDoc } from './smartdata.classes.dbdoc'
|
|
||||||
|
|
||||||
// RethinkDb Interfaces
|
|
||||||
import { WriteResult, Cursor } from 'rethinkdb'
|
|
||||||
|
|
||||||
export interface IFindOptions {
|
|
||||||
limit?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IDocValidation<T> {
|
|
||||||
(doc: T): boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Collection (db: Db) {
|
|
||||||
return function (constructor) {
|
|
||||||
constructor[ 'dbCollection' ] = new DbTable(constructor, db)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DbTable<T> {
|
|
||||||
/**
|
|
||||||
* the collection that is used, defaults to mongodb collection,
|
|
||||||
* can be nedb datastore (sub api of mongodb)
|
|
||||||
*/
|
|
||||||
table: plugins.rethinkDb.Table
|
|
||||||
objectValidation: IDocValidation<T> = null
|
|
||||||
tableName: string
|
|
||||||
db: Db
|
|
||||||
|
|
||||||
constructor (collectedClassArg: T & DbDoc<T>, dbArg: Db) {
|
|
||||||
// tell the collection where it belongs
|
|
||||||
this.tableName = collectedClassArg.name
|
|
||||||
this.db = dbArg
|
|
||||||
|
|
||||||
// tell the db class about it (important since Db uses different systems under the hood)
|
|
||||||
this.db.addTable(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
async init() {
|
|
||||||
if(!this.table) {
|
|
||||||
// connect this instance to a RethinkDB table
|
|
||||||
const availableTables = await plugins.rethinkDb
|
|
||||||
.db(this.db.dbName)
|
|
||||||
.tableList()
|
|
||||||
.run(this.db.dbConnection)
|
|
||||||
if(availableTables.indexOf(this.tableName)) {
|
|
||||||
await plugins.rethinkDb
|
|
||||||
.db(this.db.dbName)
|
|
||||||
.tableCreate(this.tableName)
|
|
||||||
.run(this.db.dbConnection)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.table = plugins.rethinkDb.table(this.tableName)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* adds a validation function that all newly inserted and updated objects have to pass
|
|
||||||
*/
|
|
||||||
addDocValidation (funcArg: IDocValidation<T>) {
|
|
||||||
this.objectValidation = funcArg
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* finds an object in the DbCollection
|
|
||||||
*/
|
|
||||||
async find (): Promise<Cursor> {
|
|
||||||
await this.init()
|
|
||||||
return await plugins.rethinkDb.table(this.tableName).filter({
|
|
||||||
/* TODO: */
|
|
||||||
}).run(this.db.dbConnection)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create an object in the database
|
|
||||||
*/
|
|
||||||
async insert (dbDocArg: T & DbDoc<T>): Promise<WriteResult> {
|
|
||||||
await this.init()
|
|
||||||
await this.checkDoc(dbDocArg)
|
|
||||||
return await plugins.rethinkDb.table(this.tableName).insert(
|
|
||||||
dbDocArg.createSavableObject()
|
|
||||||
).run(this.db.dbConnection)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* inserts object into the DbCollection
|
|
||||||
*/
|
|
||||||
async update (dbDocArg: T & DbDoc<T>): Promise<WriteResult> {
|
|
||||||
await this.init()
|
|
||||||
await this.checkDoc(dbDocArg)
|
|
||||||
console.log(this.tableName, dbDocArg.createSavableObject())
|
|
||||||
return await plugins.rethinkDb.table(this.tableName).update(
|
|
||||||
dbDocArg.createSavableObject()
|
|
||||||
).run(this.db.dbConnection)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* checks a Doc for constraints
|
|
||||||
* if this.objectValidation is not set it passes.
|
|
||||||
*/
|
|
||||||
private checkDoc (docArg: T): Promise<void> {
|
|
||||||
let done = plugins.smartq.defer<void>()
|
|
||||||
let validationResult = true
|
|
||||||
if (this.objectValidation) {
|
|
||||||
validationResult = this.objectValidation(docArg)
|
|
||||||
}
|
|
||||||
if (validationResult) {
|
|
||||||
done.resolve()
|
|
||||||
} else {
|
|
||||||
done.reject('validation of object did not pass')
|
|
||||||
}
|
|
||||||
return done.promise
|
|
||||||
}
|
|
||||||
|
|
||||||
extractKey (writeResult: WriteResult) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,100 +0,0 @@
|
|||||||
import * as plugins from './smartdata.plugins'
|
|
||||||
|
|
||||||
import { Objectmap } from 'lik'
|
|
||||||
|
|
||||||
import { Db } from './smartdata.classes.db'
|
|
||||||
import { DbTable } from './smartdata.classes.dbcollection'
|
|
||||||
|
|
||||||
export type TDocCreation = 'db' | 'new' | 'mixed'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* saveable - saveable decorator to be used on class properties
|
|
||||||
*/
|
|
||||||
export function svDb() {
|
|
||||||
return (target: DbDoc<any>, key: string) => {
|
|
||||||
console.log('called sva')
|
|
||||||
if (!target.saveableProperties) { target.saveableProperties = [] }
|
|
||||||
target.saveableProperties.push(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DbDoc<T> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* the collection object an Doc belongs to
|
|
||||||
*/
|
|
||||||
collection: DbTable<T>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* how the Doc in memory was created, may prove useful later.
|
|
||||||
*/
|
|
||||||
creationStatus: TDocCreation = 'new'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* an array of saveable properties of a doc
|
|
||||||
*/
|
|
||||||
saveableProperties: string[]
|
|
||||||
|
|
||||||
/**
|
|
||||||
* name
|
|
||||||
*/
|
|
||||||
name: string
|
|
||||||
|
|
||||||
/**
|
|
||||||
* primary id in the database
|
|
||||||
*/
|
|
||||||
dbId: string
|
|
||||||
|
|
||||||
/**
|
|
||||||
* class constructor
|
|
||||||
*/
|
|
||||||
constructor () {
|
|
||||||
this.name = this.constructor['name']
|
|
||||||
this.collection = this.constructor[ 'dbCollection' ]
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* saves this instance but not any connected items
|
|
||||||
* may lead to data inconsistencies, but is faster
|
|
||||||
*/
|
|
||||||
async save () {
|
|
||||||
let self: any = this
|
|
||||||
switch (this.creationStatus) {
|
|
||||||
case 'db':
|
|
||||||
await this.collection.update(self)
|
|
||||||
break
|
|
||||||
case 'new':
|
|
||||||
let writeResult = await this.collection.insert(self)
|
|
||||||
this.creationStatus = 'db'
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.error('neither new nor in db?')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* also store any referenced objects to DB
|
|
||||||
* better for data consistency
|
|
||||||
*/
|
|
||||||
saveDeep (savedMapArg: Objectmap<DbDoc<any>> = null) {
|
|
||||||
if (!savedMapArg) {
|
|
||||||
savedMapArg = new Objectmap<DbDoc<any>>()
|
|
||||||
}
|
|
||||||
savedMapArg.add(this)
|
|
||||||
this.save()
|
|
||||||
for (let propertyKey in this) {
|
|
||||||
let property: any = this[ propertyKey ]
|
|
||||||
if (property instanceof DbDoc && !savedMapArg.checkForObject(property)) {
|
|
||||||
property.saveDeep(savedMapArg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createSavableObject () {
|
|
||||||
let saveableObject: any = {} // is not exposed to outside, so any is ok here
|
|
||||||
for (let propertyNameString of this.saveableProperties) {
|
|
||||||
saveableObject[ propertyNameString ] = this[ propertyNameString ]
|
|
||||||
}
|
|
||||||
return saveableObject
|
|
||||||
}
|
|
||||||
}
|
|
204
ts/smartdata.classes.distributedcoordinator.ts
Normal file
204
ts/smartdata.classes.distributedcoordinator.ts
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
import * as plugins from './smartdata.plugins.js';
|
||||||
|
import { SmartdataDb } from './smartdata.classes.db.js';
|
||||||
|
import { Manager, setDefaultManagerForDoc } from './smartdata.classes.collection.js';
|
||||||
|
import { SmartDataDbDoc, svDb, unI } from './smartdata.classes.doc.js';
|
||||||
|
|
||||||
|
@Manager()
|
||||||
|
export class DistributedClass extends SmartDataDbDoc<DistributedClass, DistributedClass> {
|
||||||
|
// INSTANCE
|
||||||
|
@unI()
|
||||||
|
public id: string;
|
||||||
|
|
||||||
|
@svDb()
|
||||||
|
public data: {
|
||||||
|
status: 'bidding' | 'settled' | 'initializing' | 'stopped';
|
||||||
|
biddingShortcode?: string;
|
||||||
|
lastUpdated: number;
|
||||||
|
elected: boolean;
|
||||||
|
/**
|
||||||
|
* used to store request
|
||||||
|
*/
|
||||||
|
taskRequests: plugins.taskbuffer.distributedCoordination.IDistributedTaskRequest[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* only used by the leader to convey consultation results
|
||||||
|
*/
|
||||||
|
taskRequestResults: plugins.taskbuffer.distributedCoordination.IDistributedTaskRequestResult[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file implements a distributed coordinator according to the @pushrocks/taskbuffer standard.
|
||||||
|
* you should not set up this yourself. Instead, there is a factory on the SmartdataDb class
|
||||||
|
* that will take care of setting this up.
|
||||||
|
*/
|
||||||
|
export class SmartdataDistributedCoordinator extends plugins.taskbuffer.distributedCoordination
|
||||||
|
.AbstractDistributedCoordinator {
|
||||||
|
public readyPromise: Promise<any>;
|
||||||
|
public db: SmartdataDb;
|
||||||
|
private asyncExecutionStack = new plugins.lik.AsyncExecutionStack();
|
||||||
|
public ownInstance: DistributedClass;
|
||||||
|
|
||||||
|
constructor(dbArg: SmartdataDb) {
|
||||||
|
super();
|
||||||
|
this.db = dbArg;
|
||||||
|
setDefaultManagerForDoc(this, DistributedClass);
|
||||||
|
this.readyPromise = this.db.statusConnectedDeferred.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
// smartdata specific stuff
|
||||||
|
public async start() {
|
||||||
|
await this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async stop() {
|
||||||
|
if (this.ownInstance?.data.elected) {
|
||||||
|
this.ownInstance.data.elected = false;
|
||||||
|
} else {
|
||||||
|
console.log(`can't stop a distributed instance that has not been started yet.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public id = plugins.smartunique.uni('distributedInstance');
|
||||||
|
|
||||||
|
private startHeartbeat = async () => {
|
||||||
|
while (this.ownInstance.data.status !== 'stopped') {
|
||||||
|
await this.sendHeartbeat();
|
||||||
|
await plugins.smartdelay.delayFor(10000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public async sendHeartbeat() {
|
||||||
|
await this.asyncExecutionStack.getExclusiveExecutionSlot(async () => {
|
||||||
|
await this.ownInstance.updateFromDb();
|
||||||
|
this.ownInstance.data.lastUpdated = Date.now();
|
||||||
|
await this.ownInstance.save();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
private async init() {
|
||||||
|
await this.readyPromise;
|
||||||
|
if (!this.ownInstance) {
|
||||||
|
await this.asyncExecutionStack.getExclusiveExecutionSlot(async () => {
|
||||||
|
this.ownInstance = new DistributedClass();
|
||||||
|
this.ownInstance.id = this.id;
|
||||||
|
this.ownInstance.data = {
|
||||||
|
elected: false,
|
||||||
|
lastUpdated: Date.now(),
|
||||||
|
status: 'initializing',
|
||||||
|
taskRequests: [],
|
||||||
|
taskRequestResults: [],
|
||||||
|
};
|
||||||
|
await this.ownInstance.save();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// lets enable the heartbeat
|
||||||
|
this.startHeartbeat();
|
||||||
|
|
||||||
|
// lets do a leader check
|
||||||
|
await this.checkAndMaybeLead();
|
||||||
|
|
||||||
|
return this.ownInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --> leader election
|
||||||
|
public async checkAndMaybeLead() {
|
||||||
|
const allInstances = await DistributedClass.getInstances({});
|
||||||
|
let leader = allInstances.find((instanceArg) => instanceArg.data.elected === true);
|
||||||
|
if (
|
||||||
|
leader &&
|
||||||
|
leader.data.lastUpdated >=
|
||||||
|
Date.now() - plugins.smarttime.getMilliSecondsFromUnits({ minutes: 1 })
|
||||||
|
) {
|
||||||
|
await this.asyncExecutionStack.getExclusiveExecutionSlot(async () => {
|
||||||
|
await this.ownInstance.updateFromDb();
|
||||||
|
this.ownInstance.data.status = 'settled';
|
||||||
|
await this.ownInstance.save();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
await this.asyncExecutionStack.getExclusiveExecutionSlot(async () => {
|
||||||
|
this.ownInstance.data.status = 'bidding';
|
||||||
|
this.ownInstance.data.biddingShortcode = plugins.smartunique.shortId();
|
||||||
|
await this.ownInstance.save();
|
||||||
|
});
|
||||||
|
await plugins.smartdelay.delayFor(plugins.smarttime.getMilliSecondsFromUnits({ minutes: 2 }));
|
||||||
|
await this.asyncExecutionStack.getExclusiveExecutionSlot(async () => {
|
||||||
|
let biddingInstances = await DistributedClass.getInstances({});
|
||||||
|
biddingInstances = biddingInstances.filter(
|
||||||
|
(instanceArg) =>
|
||||||
|
!instanceArg.data.elected &&
|
||||||
|
instanceArg.data.lastUpdated >=
|
||||||
|
Date.now() - plugins.smarttime.getMilliSecondsFromUnits({ minutes: 1 })
|
||||||
|
);
|
||||||
|
this.ownInstance.data.elected = true;
|
||||||
|
for (const biddingInstance of biddingInstances) {
|
||||||
|
if (biddingInstance.data.biddingShortcode < this.ownInstance.data.biddingShortcode) {
|
||||||
|
this.ownInstance.data.elected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await this.ownInstance.save();
|
||||||
|
});
|
||||||
|
if (this.ownInstance.data.elected) {
|
||||||
|
this.leadFunction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* when it has been determined
|
||||||
|
* that this instance is leading
|
||||||
|
* the leading is implemented here
|
||||||
|
*/
|
||||||
|
public async leadFunction() {
|
||||||
|
const ownInstance = await this.init();
|
||||||
|
const watcher = await DistributedClass.watch({});
|
||||||
|
/**
|
||||||
|
* this function is started once per unique job request
|
||||||
|
*/
|
||||||
|
const startResultTimer = async () => {};
|
||||||
|
|
||||||
|
watcher.changeSubject.subscribe({
|
||||||
|
next: async (distributedDoc) => {
|
||||||
|
distributedDoc;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
while (this.ownInstance.data.status !== 'stopped') {
|
||||||
|
await plugins.smartdelay.delayFor(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// abstract implemented methods
|
||||||
|
public async fireDistributedTaskRequest(
|
||||||
|
taskRequestArg: plugins.taskbuffer.distributedCoordination.IDistributedTaskRequest
|
||||||
|
): Promise<plugins.taskbuffer.distributedCoordination.IDistributedTaskRequestResult> {
|
||||||
|
const ownInstance = await this.init();
|
||||||
|
await this.asyncExecutionStack.getExclusiveExecutionSlot(async () => {
|
||||||
|
this.ownInstance.data.taskRequests.push(taskRequestArg);
|
||||||
|
await this.ownInstance.save();
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async updateDistributedTaskRequest(
|
||||||
|
infoBasisArg: plugins.taskbuffer.distributedCoordination.IDistributedTaskRequest
|
||||||
|
): Promise<void> {
|
||||||
|
await this.asyncExecutionStack.getExclusiveExecutionSlot(async () => {
|
||||||
|
const existingInfoBasis = this.ownInstance.data.taskRequests.find((infoBasisItem) => {
|
||||||
|
return (
|
||||||
|
infoBasisItem.taskName === infoBasisArg.taskName &&
|
||||||
|
infoBasisItem.taskExecutionTime === infoBasisArg.taskExecutionTime
|
||||||
|
);
|
||||||
|
});
|
||||||
|
Object.assign(existingInfoBasis, infoBasisArg);
|
||||||
|
await this.ownInstance.save();
|
||||||
|
plugins.smartdelay.delayFor(60000).then(() => {
|
||||||
|
this.asyncExecutionStack.getExclusiveExecutionSlot(async () => {
|
||||||
|
const indexToRemove = this.ownInstance.data.taskRequests.indexOf(existingInfoBasis);
|
||||||
|
this.ownInstance.data.taskRequests.splice(indexToRemove, indexToRemove);
|
||||||
|
await this.ownInstance.save();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
287
ts/smartdata.classes.doc.ts
Normal file
287
ts/smartdata.classes.doc.ts
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
import * as plugins from './smartdata.plugins.js';
|
||||||
|
|
||||||
|
import { SmartdataDb } from './smartdata.classes.db.js';
|
||||||
|
import { SmartdataDbCursor } from './smartdata.classes.cursor.js';
|
||||||
|
import { type IManager, SmartdataCollection } from './smartdata.classes.collection.js';
|
||||||
|
import { SmartdataDbWatcher } from './smartdata.classes.watcher.js';
|
||||||
|
|
||||||
|
export type TDocCreation = 'db' | 'new' | 'mixed';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* saveable - saveable decorator to be used on class properties
|
||||||
|
*/
|
||||||
|
export function svDb() {
|
||||||
|
return (target: SmartDataDbDoc<unknown, unknown>, key: string) => {
|
||||||
|
console.log(`called svDb() on >${target.constructor.name}.${key}<`);
|
||||||
|
if (!target.saveableProperties) {
|
||||||
|
target.saveableProperties = [];
|
||||||
|
}
|
||||||
|
target.saveableProperties.push(key);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* unique index - decorator to mark a unique index
|
||||||
|
*/
|
||||||
|
export function unI() {
|
||||||
|
return (target: SmartDataDbDoc<unknown, unknown>, key: string) => {
|
||||||
|
console.log(`called unI on >>${target.constructor.name}.${key}<<`);
|
||||||
|
|
||||||
|
// mark the index as unique
|
||||||
|
if (!target.uniqueIndexes) {
|
||||||
|
target.uniqueIndexes = [];
|
||||||
|
}
|
||||||
|
target.uniqueIndexes.push(key);
|
||||||
|
|
||||||
|
// and also save it
|
||||||
|
if (!target.saveableProperties) {
|
||||||
|
target.saveableProperties = [];
|
||||||
|
}
|
||||||
|
target.saveableProperties.push(key);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const convertFilterForMongoDb = (filterArg: { [key: string]: any }) => {
|
||||||
|
const convertedFilter: { [key: string]: any } = {};
|
||||||
|
const convertFilterArgument = (keyPathArg2: string, filterArg2: any) => {
|
||||||
|
if (typeof filterArg2 === 'object') {
|
||||||
|
for (const key of Object.keys(filterArg2)) {
|
||||||
|
if (key.startsWith('$')) {
|
||||||
|
convertedFilter[keyPathArg2] = filterArg2;
|
||||||
|
return;
|
||||||
|
} else if (key.includes('.')) {
|
||||||
|
throw new Error('keys cannot contain dots');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const key of Object.keys(filterArg2)) {
|
||||||
|
convertFilterArgument(`${keyPathArg2}.${key}`, filterArg2[key]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
convertedFilter[keyPathArg2] = filterArg2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (const key of Object.keys(filterArg)) {
|
||||||
|
convertFilterArgument(key, filterArg[key]);
|
||||||
|
}
|
||||||
|
return convertedFilter;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends IManager = any> {
|
||||||
|
/**
|
||||||
|
* the collection object an Doc belongs to
|
||||||
|
*/
|
||||||
|
public static collection: SmartdataCollection<any>;
|
||||||
|
public collection: SmartdataCollection<any>;
|
||||||
|
public static defaultManager;
|
||||||
|
public static manager;
|
||||||
|
public manager: TManager;
|
||||||
|
|
||||||
|
// STATIC
|
||||||
|
public static createInstanceFromMongoDbNativeDoc<T>(
|
||||||
|
this: plugins.tsclass.typeFest.Class<T>,
|
||||||
|
mongoDbNativeDocArg: any
|
||||||
|
): T {
|
||||||
|
const newInstance = new this();
|
||||||
|
(newInstance as any).creationStatus = 'db';
|
||||||
|
for (const key of Object.keys(mongoDbNativeDocArg)) {
|
||||||
|
newInstance[key] = mongoDbNativeDocArg[key];
|
||||||
|
}
|
||||||
|
return newInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets all instances as array
|
||||||
|
* @param this
|
||||||
|
* @param filterArg
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
public static async getInstances<T>(
|
||||||
|
this: plugins.tsclass.typeFest.Class<T>,
|
||||||
|
filterArg: plugins.tsclass.typeFest.PartialDeep<T>
|
||||||
|
): Promise<T[]> {
|
||||||
|
const foundDocs = await (this as any).collection.findAll(convertFilterForMongoDb(filterArg));
|
||||||
|
const returnArray = [];
|
||||||
|
for (const foundDoc of foundDocs) {
|
||||||
|
const newInstance: T = (this as any).createInstanceFromMongoDbNativeDoc(foundDoc);
|
||||||
|
returnArray.push(newInstance);
|
||||||
|
}
|
||||||
|
return returnArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets the first matching instance
|
||||||
|
* @param this
|
||||||
|
* @param filterArg
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
public static async getInstance<T>(
|
||||||
|
this: plugins.tsclass.typeFest.Class<T>,
|
||||||
|
filterArg: plugins.tsclass.typeFest.PartialDeep<T>
|
||||||
|
): Promise<T> {
|
||||||
|
const foundDoc = await (this as any).collection.findOne(convertFilterForMongoDb(filterArg));
|
||||||
|
if (foundDoc) {
|
||||||
|
const newInstance: T = (this as any).createInstanceFromMongoDbNativeDoc(foundDoc);
|
||||||
|
return newInstance;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get cursor
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
public static async getCursor<T>(
|
||||||
|
this: plugins.tsclass.typeFest.Class<T>,
|
||||||
|
filterArg: plugins.tsclass.typeFest.PartialDeep<T>
|
||||||
|
) {
|
||||||
|
const collection: SmartdataCollection<T> = (this as any).collection;
|
||||||
|
const cursor: SmartdataDbCursor<T> = await collection.getCursor(
|
||||||
|
convertFilterForMongoDb(filterArg),
|
||||||
|
this as any as typeof SmartDataDbDoc
|
||||||
|
);
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* watch the collection
|
||||||
|
* @param this
|
||||||
|
* @param filterArg
|
||||||
|
* @param forEachFunction
|
||||||
|
*/
|
||||||
|
public static async watch<T>(
|
||||||
|
this: plugins.tsclass.typeFest.Class<T>,
|
||||||
|
filterArg: plugins.tsclass.typeFest.PartialDeep<T>
|
||||||
|
) {
|
||||||
|
const collection: SmartdataCollection<T> = (this as any).collection;
|
||||||
|
const watcher: SmartdataDbWatcher<T> = await collection.watch(
|
||||||
|
convertFilterForMongoDb(filterArg),
|
||||||
|
this as any
|
||||||
|
);
|
||||||
|
return watcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* run a function for all instances
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
public static async forEach<T>(
|
||||||
|
this: plugins.tsclass.typeFest.Class<T>,
|
||||||
|
filterArg: plugins.tsclass.typeFest.PartialDeep<T>,
|
||||||
|
forEachFunction: (itemArg: T) => Promise<any>
|
||||||
|
) {
|
||||||
|
const cursor: SmartdataDbCursor<T> = await (this as any).getCursor(filterArg);
|
||||||
|
await cursor.forEach(forEachFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* how the Doc in memory was created, may prove useful later.
|
||||||
|
*/
|
||||||
|
public creationStatus: TDocCreation = 'new';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* unique indexes
|
||||||
|
*/
|
||||||
|
public uniqueIndexes: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* an array of saveable properties of a doc
|
||||||
|
*/
|
||||||
|
public saveableProperties: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* name
|
||||||
|
*/
|
||||||
|
public name: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* primary id in the database
|
||||||
|
*/
|
||||||
|
public dbDocUniqueId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class constructor
|
||||||
|
*/
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* saves this instance but not any connected items
|
||||||
|
* may lead to data inconsistencies, but is faster
|
||||||
|
*/
|
||||||
|
public async save() {
|
||||||
|
// tslint:disable-next-line: no-this-assignment
|
||||||
|
const self: any = this;
|
||||||
|
let dbResult: any;
|
||||||
|
switch (this.creationStatus) {
|
||||||
|
case 'db':
|
||||||
|
dbResult = await this.collection.update(self);
|
||||||
|
break;
|
||||||
|
case 'new':
|
||||||
|
dbResult = await this.collection.insert(self);
|
||||||
|
this.creationStatus = 'db';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.error('neither new nor in db?');
|
||||||
|
}
|
||||||
|
return dbResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* deletes a document from the database
|
||||||
|
*/
|
||||||
|
public async delete() {
|
||||||
|
await this.collection.delete(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* also store any referenced objects to DB
|
||||||
|
* better for data consistency
|
||||||
|
*/
|
||||||
|
public saveDeep(savedMapArg: plugins.lik.ObjectMap<SmartDataDbDoc<any, any>> = null) {
|
||||||
|
if (!savedMapArg) {
|
||||||
|
savedMapArg = new plugins.lik.ObjectMap<SmartDataDbDoc<any, any>>();
|
||||||
|
}
|
||||||
|
savedMapArg.add(this);
|
||||||
|
this.save();
|
||||||
|
for (const propertyKey of Object.keys(this)) {
|
||||||
|
const property: any = this[propertyKey];
|
||||||
|
if (property instanceof SmartDataDbDoc && !savedMapArg.checkForObject(property)) {
|
||||||
|
property.saveDeep(savedMapArg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* updates an object from db
|
||||||
|
*/
|
||||||
|
public async updateFromDb() {
|
||||||
|
const mongoDbNativeDoc = await this.collection.findOne(this.createIdentifiableObject());
|
||||||
|
for (const key of Object.keys(mongoDbNativeDoc)) {
|
||||||
|
this[key] = mongoDbNativeDoc[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a saveable object so the instance can be persisted as json in the database
|
||||||
|
*/
|
||||||
|
public async createSavableObject(): Promise<TImplements> {
|
||||||
|
const saveableObject: unknown = {}; // is not exposed to outside, so any is ok here
|
||||||
|
for (const propertyNameString of this.saveableProperties) {
|
||||||
|
saveableObject[propertyNameString] = this[propertyNameString];
|
||||||
|
}
|
||||||
|
return saveableObject as TImplements;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates an identifiable object for operations that require filtering
|
||||||
|
*/
|
||||||
|
public async createIdentifiableObject() {
|
||||||
|
const identifiableObject: any = {}; // is not exposed to outside, so any is ok here
|
||||||
|
for (const propertyNameString of this.uniqueIndexes) {
|
||||||
|
identifiableObject[propertyNameString] = this[propertyNameString];
|
||||||
|
}
|
||||||
|
return identifiableObject;
|
||||||
|
}
|
||||||
|
}
|
109
ts/smartdata.classes.easystore.ts
Normal file
109
ts/smartdata.classes.easystore.ts
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import * as plugins from './smartdata.plugins.js';
|
||||||
|
import { Collection } from './smartdata.classes.collection.js';
|
||||||
|
import { SmartdataDb } from './smartdata.classes.db.js';
|
||||||
|
import { SmartDataDbDoc, svDb, unI } from './smartdata.classes.doc.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EasyStore allows the storage of easy objects. It also allows easy sharing of the object between different instances
|
||||||
|
*/
|
||||||
|
export class EasyStore<T> {
|
||||||
|
// instance
|
||||||
|
public smartdataDbRef: SmartdataDb;
|
||||||
|
public nameId: string;
|
||||||
|
|
||||||
|
private easyStoreClass = (() => {
|
||||||
|
@Collection(() => this.smartdataDbRef)
|
||||||
|
class SmartdataEasyStore extends SmartDataDbDoc<SmartdataEasyStore, SmartdataEasyStore> {
|
||||||
|
@unI()
|
||||||
|
public nameId: string;
|
||||||
|
|
||||||
|
@svDb()
|
||||||
|
public ephermal: {
|
||||||
|
activated: boolean;
|
||||||
|
timeout: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
@svDb()
|
||||||
|
lastEdit: number;
|
||||||
|
|
||||||
|
@svDb()
|
||||||
|
public data: Partial<T>;
|
||||||
|
}
|
||||||
|
return SmartdataEasyStore;
|
||||||
|
})();
|
||||||
|
|
||||||
|
constructor(nameIdArg: string, smnartdataDbRefArg: SmartdataDb) {
|
||||||
|
this.smartdataDbRef = smnartdataDbRefArg;
|
||||||
|
this.nameId = nameIdArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getEasyStore() {
|
||||||
|
let easyStore = await this.easyStoreClass.getInstance({
|
||||||
|
nameId: this.nameId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!easyStore) {
|
||||||
|
easyStore = new this.easyStoreClass();
|
||||||
|
easyStore.nameId = this.nameId;
|
||||||
|
easyStore.data = {};
|
||||||
|
await easyStore.save();
|
||||||
|
}
|
||||||
|
return easyStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* reads all keyValue pairs at once and returns them
|
||||||
|
*/
|
||||||
|
public async readAll() {
|
||||||
|
const easyStore = await this.getEasyStore();
|
||||||
|
return easyStore.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* reads a keyValueFile from disk
|
||||||
|
*/
|
||||||
|
public async readKey(keyArg: keyof T) {
|
||||||
|
const easyStore = await this.getEasyStore();
|
||||||
|
return easyStore.data[keyArg];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* writes a specific key to the keyValueStore
|
||||||
|
*/
|
||||||
|
public async writeKey(keyArg: keyof T, valueArg: any) {
|
||||||
|
const easyStore = await this.getEasyStore();
|
||||||
|
easyStore.data[keyArg] = valueArg;
|
||||||
|
await easyStore.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async deleteKey(keyArg: keyof T) {
|
||||||
|
const easyStore = await this.getEasyStore();
|
||||||
|
delete easyStore.data[keyArg];
|
||||||
|
await easyStore.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* writes all keyValue pairs in the object argument
|
||||||
|
*/
|
||||||
|
public async writeAll(keyValueObject: Partial<T>) {
|
||||||
|
const easyStore = await this.getEasyStore();
|
||||||
|
easyStore.data = { ...easyStore.data, ...keyValueObject };
|
||||||
|
await easyStore.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wipes a key value store from disk
|
||||||
|
*/
|
||||||
|
public async wipe() {
|
||||||
|
const easyStore = await this.getEasyStore();
|
||||||
|
easyStore.data = {};
|
||||||
|
await easyStore.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async cleanUpEphermal() {
|
||||||
|
while (
|
||||||
|
(await this.smartdataDbRef.statusConnectedDeferred.promise) &&
|
||||||
|
this.smartdataDbRef.status === 'connected'
|
||||||
|
) {}
|
||||||
|
}
|
||||||
|
}
|
33
ts/smartdata.classes.watcher.ts
Normal file
33
ts/smartdata.classes.watcher.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { SmartDataDbDoc } from './smartdata.classes.doc.js';
|
||||||
|
import * as plugins from './smartdata.plugins.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a wrapper for the native mongodb cursor. Exposes better
|
||||||
|
*/
|
||||||
|
export class SmartdataDbWatcher<T = any> {
|
||||||
|
// STATIC
|
||||||
|
public readyDeferred = plugins.smartpromise.defer();
|
||||||
|
|
||||||
|
// INSTANCE
|
||||||
|
private changeStream: plugins.mongodb.ChangeStream<T>;
|
||||||
|
|
||||||
|
public changeSubject = new plugins.smartrx.rxjs.Subject<T>();
|
||||||
|
constructor(
|
||||||
|
changeStreamArg: plugins.mongodb.ChangeStream<T>,
|
||||||
|
smartdataDbDocArg: typeof SmartDataDbDoc
|
||||||
|
) {
|
||||||
|
this.changeStream = changeStreamArg;
|
||||||
|
this.changeStream.on('change', async (item: T) => {
|
||||||
|
this.changeSubject.next(
|
||||||
|
smartdataDbDocArg.createInstanceFromMongoDbNativeDoc(item) as any as T
|
||||||
|
);
|
||||||
|
});
|
||||||
|
plugins.smartdelay.delayFor(0).then(() => {
|
||||||
|
this.readyDeferred.resolve();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async close() {
|
||||||
|
await this.changeStream.close();
|
||||||
|
}
|
||||||
|
}
|
3
ts/smartdata.logging.ts
Normal file
3
ts/smartdata.logging.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import * as plugins from './smartdata.plugins.js';
|
||||||
|
|
||||||
|
export const logger = new plugins.smartlog.ConsoleLog();
|
@ -1,15 +1,31 @@
|
|||||||
import * as assert from 'assert'
|
// tsclass scope
|
||||||
import * as beautylog from 'beautylog'
|
import * as tsclass from '@tsclass/tsclass';
|
||||||
import * as lodash from 'lodash'
|
|
||||||
import * as rethinkDb from 'rethinkdb'
|
export { tsclass };
|
||||||
import * as smartq from 'smartq'
|
|
||||||
import * as smartstring from 'smartstring'
|
// @pushrocks scope
|
||||||
|
import * as lik from '@push.rocks/lik';
|
||||||
|
import * as smartdelay from '@push.rocks/smartdelay';
|
||||||
|
import * as smartlog from '@push.rocks/smartlog';
|
||||||
|
import * as smartpromise from '@push.rocks/smartpromise';
|
||||||
|
import * as smartq from '@push.rocks/smartpromise';
|
||||||
|
import * as smartrx from '@push.rocks/smartrx';
|
||||||
|
import * as smartstring from '@push.rocks/smartstring';
|
||||||
|
import * as smarttime from '@push.rocks/smarttime';
|
||||||
|
import * as smartunique from '@push.rocks/smartunique';
|
||||||
|
import * as taskbuffer from '@push.rocks/taskbuffer';
|
||||||
|
import * as mongodb from 'mongodb';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
assert,
|
lik,
|
||||||
beautylog,
|
smartdelay,
|
||||||
lodash,
|
smartpromise,
|
||||||
smartq,
|
smartlog,
|
||||||
rethinkDb,
|
smartq,
|
||||||
smartstring
|
smartrx,
|
||||||
}
|
mongodb,
|
||||||
|
smartstring,
|
||||||
|
smarttime,
|
||||||
|
smartunique,
|
||||||
|
taskbuffer,
|
||||||
|
};
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"lib": [
|
"useDefineForClassFields": false,
|
||||||
"es2015"
|
"target": "ES2022",
|
||||||
]
|
"module": "ES2022",
|
||||||
}
|
"moduleResolution": "nodenext"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "tslint-config-standard"
|
|
||||||
}
|
|
788
yarn.lock
788
yarn.lock
@ -1,788 +0,0 @@
|
|||||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
||||||
# yarn lockfile v1
|
|
||||||
|
|
||||||
|
|
||||||
"@types/code@^4.0.3":
|
|
||||||
version "4.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/code/-/code-4.0.3.tgz#9c4de39f86eb3eba070146d2dab7dbc3f8eac35f"
|
|
||||||
|
|
||||||
"@types/events@*":
|
|
||||||
version "1.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/events/-/events-1.1.0.tgz#93b1be91f63c184450385272c47b6496fd028e02"
|
|
||||||
|
|
||||||
"@types/fs-extra@4.x.x":
|
|
||||||
version "4.0.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-4.0.7.tgz#02533262386b5a6b9a49797dc82feffdf269140a"
|
|
||||||
dependencies:
|
|
||||||
"@types/node" "*"
|
|
||||||
|
|
||||||
"@types/glob@*":
|
|
||||||
version "5.0.34"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-5.0.34.tgz#ee626c9be3da877d717911c6101eee0a9871bbf4"
|
|
||||||
dependencies:
|
|
||||||
"@types/events" "*"
|
|
||||||
"@types/minimatch" "*"
|
|
||||||
"@types/node" "*"
|
|
||||||
|
|
||||||
"@types/lodash@^4.14.55", "@types/lodash@^4.14.74", "@types/lodash@^4.14.92":
|
|
||||||
version "4.14.92"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.92.tgz#6e3cb0b71a1e12180a47a42a744e856c3ae99a57"
|
|
||||||
|
|
||||||
"@types/minimatch@*", "@types/minimatch@3.x.x":
|
|
||||||
version "3.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
|
|
||||||
|
|
||||||
"@types/node@*", "@types/node@^8.0.33", "@types/node@^8.5.7":
|
|
||||||
version "8.5.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.5.7.tgz#9c498c35af354dcfbca3790fb2e81129e93cf0e2"
|
|
||||||
|
|
||||||
"@types/rethinkdb@^2.3.8":
|
|
||||||
version "2.3.8"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/rethinkdb/-/rethinkdb-2.3.8.tgz#961f78f0e731668631891bd1199722bb4a2258a8"
|
|
||||||
dependencies:
|
|
||||||
"@types/node" "*"
|
|
||||||
|
|
||||||
"@types/shelljs@^0.7.4":
|
|
||||||
version "0.7.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.7.7.tgz#1f7bfa28947661afea06365db9b1135bbc903ec4"
|
|
||||||
dependencies:
|
|
||||||
"@types/glob" "*"
|
|
||||||
"@types/node" "*"
|
|
||||||
|
|
||||||
"@types/vinyl@^2.0.1":
|
|
||||||
version "2.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/vinyl/-/vinyl-2.0.2.tgz#4f3b8dae8f5828d3800ef709b0cff488ee852de3"
|
|
||||||
dependencies:
|
|
||||||
"@types/node" "*"
|
|
||||||
|
|
||||||
ansi-256-colors@^1.1.0:
|
|
||||||
version "1.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/ansi-256-colors/-/ansi-256-colors-1.1.0.tgz#910de50efcc7c09e3d82f2f87abd6b700c18818a"
|
|
||||||
|
|
||||||
ansi-regex@^2.0.0:
|
|
||||||
version "2.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
|
|
||||||
|
|
||||||
ansi-styles@^2.2.1:
|
|
||||||
version "2.2.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
|
|
||||||
|
|
||||||
argparse@^1.0.7:
|
|
||||||
version "1.0.9"
|
|
||||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86"
|
|
||||||
dependencies:
|
|
||||||
sprintf-js "~1.0.2"
|
|
||||||
|
|
||||||
balanced-match@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
|
||||||
|
|
||||||
beautycolor@^1.0.7:
|
|
||||||
version "1.0.11"
|
|
||||||
resolved "https://registry.yarnpkg.com/beautycolor/-/beautycolor-1.0.11.tgz#71c5568d5a7ed5c144d3a54f753ad1b08862aea5"
|
|
||||||
dependencies:
|
|
||||||
ansi-256-colors "^1.1.0"
|
|
||||||
typings-global "^1.0.14"
|
|
||||||
|
|
||||||
beautylog@^6.1.10:
|
|
||||||
version "6.1.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/beautylog/-/beautylog-6.1.10.tgz#9c27e566937684cb689f9372d98cfa5415d50b72"
|
|
||||||
dependencies:
|
|
||||||
"@types/lodash" "^4.14.55"
|
|
||||||
beautycolor "^1.0.7"
|
|
||||||
figlet "^1.2.0"
|
|
||||||
lodash "^4.17.4"
|
|
||||||
ora "^1.1.0"
|
|
||||||
smartenv "^2.0.0"
|
|
||||||
smartq "^1.1.1"
|
|
||||||
typings-global "^1.0.14"
|
|
||||||
|
|
||||||
bindings@^1.2.1:
|
|
||||||
version "1.3.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.0.tgz#b346f6ecf6a95f5a815c5839fc7cdb22502f1ed7"
|
|
||||||
|
|
||||||
"bluebird@>= 2.3.2 < 3":
|
|
||||||
version "2.11.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1"
|
|
||||||
|
|
||||||
brace-expansion@^1.1.7:
|
|
||||||
version "1.1.8"
|
|
||||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292"
|
|
||||||
dependencies:
|
|
||||||
balanced-match "^1.0.0"
|
|
||||||
concat-map "0.0.1"
|
|
||||||
|
|
||||||
chalk@^1.0.0, chalk@^1.1.1:
|
|
||||||
version "1.1.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
|
|
||||||
dependencies:
|
|
||||||
ansi-styles "^2.2.1"
|
|
||||||
escape-string-regexp "^1.0.2"
|
|
||||||
has-ansi "^2.0.0"
|
|
||||||
strip-ansi "^3.0.0"
|
|
||||||
supports-color "^2.0.0"
|
|
||||||
|
|
||||||
cli-cursor@^2.1.0:
|
|
||||||
version "2.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5"
|
|
||||||
dependencies:
|
|
||||||
restore-cursor "^2.0.0"
|
|
||||||
|
|
||||||
cli-spinners@^1.0.0:
|
|
||||||
version "1.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.1.0.tgz#f1847b168844d917a671eb9d147e3df497c90d06"
|
|
||||||
|
|
||||||
clone-buffer@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58"
|
|
||||||
|
|
||||||
clone-stats@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680"
|
|
||||||
|
|
||||||
clone@^2.1.1:
|
|
||||||
version "2.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb"
|
|
||||||
|
|
||||||
cloneable-readable@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.0.0.tgz#a6290d413f217a61232f95e458ff38418cfb0117"
|
|
||||||
dependencies:
|
|
||||||
inherits "^2.0.1"
|
|
||||||
process-nextick-args "^1.0.6"
|
|
||||||
through2 "^2.0.1"
|
|
||||||
|
|
||||||
code@^5.1.0:
|
|
||||||
version "5.1.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/code/-/code-5.1.2.tgz#e3310c2078ca7dc0b49b9c39a8b0a7b06bd75efe"
|
|
||||||
dependencies:
|
|
||||||
hoek "5.x.x"
|
|
||||||
|
|
||||||
concat-map@0.0.1:
|
|
||||||
version "0.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
|
||||||
|
|
||||||
conventional-commit-types@^2.0.0:
|
|
||||||
version "2.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/conventional-commit-types/-/conventional-commit-types-2.2.0.tgz#5db95739d6c212acbe7b6f656a11b940baa68946"
|
|
||||||
|
|
||||||
core-util-is@~1.0.0:
|
|
||||||
version "1.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
|
||||||
|
|
||||||
crypto-random-string@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
|
|
||||||
|
|
||||||
cz-conventional-changelog@^2.1.0:
|
|
||||||
version "2.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/cz-conventional-changelog/-/cz-conventional-changelog-2.1.0.tgz#2f4bc7390e3244e4df293e6ba351e4c740a7c764"
|
|
||||||
dependencies:
|
|
||||||
conventional-commit-types "^2.0.0"
|
|
||||||
lodash.map "^4.5.1"
|
|
||||||
longest "^1.0.1"
|
|
||||||
right-pad "^1.0.1"
|
|
||||||
word-wrap "^1.0.3"
|
|
||||||
|
|
||||||
define-properties@^1.1.2:
|
|
||||||
version "1.1.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94"
|
|
||||||
dependencies:
|
|
||||||
foreach "^2.0.5"
|
|
||||||
object-keys "^1.0.8"
|
|
||||||
|
|
||||||
early@^2.1.1:
|
|
||||||
version "2.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/early/-/early-2.1.1.tgz#841e23254ea5dc54d8afaeee82f5ab65c00ee23c"
|
|
||||||
dependencies:
|
|
||||||
beautycolor "^1.0.7"
|
|
||||||
smartq "^1.1.1"
|
|
||||||
typings-global "^1.0.16"
|
|
||||||
|
|
||||||
es-abstract@^1.5.1:
|
|
||||||
version "1.10.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.10.0.tgz#1ecb36c197842a00d8ee4c2dfd8646bb97d60864"
|
|
||||||
dependencies:
|
|
||||||
es-to-primitive "^1.1.1"
|
|
||||||
function-bind "^1.1.1"
|
|
||||||
has "^1.0.1"
|
|
||||||
is-callable "^1.1.3"
|
|
||||||
is-regex "^1.0.4"
|
|
||||||
|
|
||||||
es-to-primitive@^1.1.1:
|
|
||||||
version "1.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d"
|
|
||||||
dependencies:
|
|
||||||
is-callable "^1.1.1"
|
|
||||||
is-date-object "^1.0.1"
|
|
||||||
is-symbol "^1.0.1"
|
|
||||||
|
|
||||||
es6-error@^4.0.2:
|
|
||||||
version "4.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d"
|
|
||||||
|
|
||||||
escape-string-regexp@^1.0.2:
|
|
||||||
version "1.0.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
|
||||||
|
|
||||||
esprima@^4.0.0:
|
|
||||||
version "4.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804"
|
|
||||||
|
|
||||||
figlet@^1.2.0:
|
|
||||||
version "1.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/figlet/-/figlet-1.2.0.tgz#6c46537378fab649146b5a6143dda019b430b410"
|
|
||||||
|
|
||||||
first-chunk-stream@^2.0.0:
|
|
||||||
version "2.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz#1bdecdb8e083c0664b91945581577a43a9f31d70"
|
|
||||||
dependencies:
|
|
||||||
readable-stream "^2.0.2"
|
|
||||||
|
|
||||||
foreach@^2.0.5:
|
|
||||||
version "2.0.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
|
|
||||||
|
|
||||||
fs-extra@^4.0.2:
|
|
||||||
version "4.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94"
|
|
||||||
dependencies:
|
|
||||||
graceful-fs "^4.1.2"
|
|
||||||
jsonfile "^4.0.0"
|
|
||||||
universalify "^0.1.0"
|
|
||||||
|
|
||||||
fs.realpath@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
|
||||||
|
|
||||||
function-bind@^1.0.2, function-bind@^1.1.1:
|
|
||||||
version "1.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
|
|
||||||
|
|
||||||
glob@^7.0.0, glob@^7.1.2:
|
|
||||||
version "7.1.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
|
|
||||||
dependencies:
|
|
||||||
fs.realpath "^1.0.0"
|
|
||||||
inflight "^1.0.4"
|
|
||||||
inherits "2"
|
|
||||||
minimatch "^3.0.4"
|
|
||||||
once "^1.3.0"
|
|
||||||
path-is-absolute "^1.0.0"
|
|
||||||
|
|
||||||
graceful-fs@^4.1.2, graceful-fs@^4.1.6:
|
|
||||||
version "4.1.11"
|
|
||||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
|
|
||||||
|
|
||||||
has-ansi@^2.0.0:
|
|
||||||
version "2.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
|
|
||||||
dependencies:
|
|
||||||
ansi-regex "^2.0.0"
|
|
||||||
|
|
||||||
has@^1.0.1:
|
|
||||||
version "1.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28"
|
|
||||||
dependencies:
|
|
||||||
function-bind "^1.0.2"
|
|
||||||
|
|
||||||
hoek@5.x.x:
|
|
||||||
version "5.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/hoek/-/hoek-5.0.2.tgz#d2f2c95d36fe7189cf8aa8c237abc1950eca1378"
|
|
||||||
|
|
||||||
home@^1.0.1:
|
|
||||||
version "1.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/home/-/home-1.0.1.tgz#96a423ceb49b98378ff5ef3ceae059a557f9dd35"
|
|
||||||
dependencies:
|
|
||||||
os-homedir "^1.0.1"
|
|
||||||
|
|
||||||
inflight@^1.0.4:
|
|
||||||
version "1.0.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
|
|
||||||
dependencies:
|
|
||||||
once "^1.3.0"
|
|
||||||
wrappy "1"
|
|
||||||
|
|
||||||
inherits@2, inherits@^2.0.1, inherits@~2.0.3:
|
|
||||||
version "2.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
|
||||||
|
|
||||||
interpret@^1.0.0:
|
|
||||||
version "1.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614"
|
|
||||||
|
|
||||||
is-buffer@^1.1.5:
|
|
||||||
version "1.1.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
|
|
||||||
|
|
||||||
is-callable@^1.1.1, is-callable@^1.1.3:
|
|
||||||
version "1.1.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2"
|
|
||||||
|
|
||||||
is-date-object@^1.0.1:
|
|
||||||
version "1.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16"
|
|
||||||
|
|
||||||
is-number@^3.0.0:
|
|
||||||
version "3.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
|
|
||||||
dependencies:
|
|
||||||
kind-of "^3.0.2"
|
|
||||||
|
|
||||||
is-regex@^1.0.4:
|
|
||||||
version "1.0.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491"
|
|
||||||
dependencies:
|
|
||||||
has "^1.0.1"
|
|
||||||
|
|
||||||
is-symbol@^1.0.1:
|
|
||||||
version "1.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572"
|
|
||||||
|
|
||||||
is-utf8@^0.2.0, is-utf8@^0.2.1:
|
|
||||||
version "0.2.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
|
|
||||||
|
|
||||||
isarray@~1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
|
||||||
|
|
||||||
js-base64@^2.3.2:
|
|
||||||
version "2.4.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.0.tgz#9e566fee624751a1d720c966cd6226d29d4025aa"
|
|
||||||
|
|
||||||
js-yaml@^3.10.0:
|
|
||||||
version "3.10.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc"
|
|
||||||
dependencies:
|
|
||||||
argparse "^1.0.7"
|
|
||||||
esprima "^4.0.0"
|
|
||||||
|
|
||||||
jsonfile@^4.0.0:
|
|
||||||
version "4.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
|
|
||||||
optionalDependencies:
|
|
||||||
graceful-fs "^4.1.6"
|
|
||||||
|
|
||||||
kind-of@^3.0.2:
|
|
||||||
version "3.2.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
|
|
||||||
dependencies:
|
|
||||||
is-buffer "^1.1.5"
|
|
||||||
|
|
||||||
kind-of@^4.0.0:
|
|
||||||
version "4.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
|
|
||||||
dependencies:
|
|
||||||
is-buffer "^1.1.5"
|
|
||||||
|
|
||||||
leakage@^0.3.0:
|
|
||||||
version "0.3.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/leakage/-/leakage-0.3.0.tgz#15d698abdc76bbc6439601f4f3020e77e2d50c39"
|
|
||||||
dependencies:
|
|
||||||
es6-error "^4.0.2"
|
|
||||||
left-pad "^1.1.3"
|
|
||||||
memwatch-next "^0.3.0"
|
|
||||||
minimist "^1.2.0"
|
|
||||||
pretty-bytes "^4.0.2"
|
|
||||||
|
|
||||||
left-pad@^1.1.3:
|
|
||||||
version "1.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.2.0.tgz#d30a73c6b8201d8f7d8e7956ba9616087a68e0ee"
|
|
||||||
|
|
||||||
lik@^2.0.2:
|
|
||||||
version "2.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/lik/-/lik-2.0.2.tgz#da4e67458ab81fac9e62848e8e76dc1efe1c646f"
|
|
||||||
dependencies:
|
|
||||||
"@types/lodash" "^4.14.74"
|
|
||||||
"@types/minimatch" "3.x.x"
|
|
||||||
lodash "^4.17.4"
|
|
||||||
minimatch "^3.0.4"
|
|
||||||
smartq "^1.1.6"
|
|
||||||
symbol-tree "^3.2.2"
|
|
||||||
typings-global "^1.0.20"
|
|
||||||
|
|
||||||
lodash.map@^4.5.1:
|
|
||||||
version "4.6.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3"
|
|
||||||
|
|
||||||
lodash@^4.17.4:
|
|
||||||
version "4.17.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
|
|
||||||
|
|
||||||
log-symbols@^1.0.2:
|
|
||||||
version "1.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18"
|
|
||||||
dependencies:
|
|
||||||
chalk "^1.0.0"
|
|
||||||
|
|
||||||
longest@^1.0.1:
|
|
||||||
version "1.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
|
|
||||||
|
|
||||||
memwatch-next@^0.3.0:
|
|
||||||
version "0.3.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/memwatch-next/-/memwatch-next-0.3.0.tgz#2111050f9a906e0aa2d72a4ec0f0089c78726f8f"
|
|
||||||
dependencies:
|
|
||||||
bindings "^1.2.1"
|
|
||||||
nan "^2.3.2"
|
|
||||||
|
|
||||||
mimic-fn@^1.0.0:
|
|
||||||
version "1.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18"
|
|
||||||
|
|
||||||
minimatch@^3.0.4:
|
|
||||||
version "3.0.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
|
|
||||||
dependencies:
|
|
||||||
brace-expansion "^1.1.7"
|
|
||||||
|
|
||||||
minimist@^1.2.0:
|
|
||||||
version "1.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
|
|
||||||
|
|
||||||
nan@^2.3.2:
|
|
||||||
version "2.8.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a"
|
|
||||||
|
|
||||||
normalize-newline@^3.0.0:
|
|
||||||
version "3.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/normalize-newline/-/normalize-newline-3.0.0.tgz#1cbea804aba436001f83938ab21ec039d69ae9d3"
|
|
||||||
|
|
||||||
object-keys@^1.0.8:
|
|
||||||
version "1.0.11"
|
|
||||||
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d"
|
|
||||||
|
|
||||||
object.getownpropertydescriptors@^2.0.3:
|
|
||||||
version "2.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16"
|
|
||||||
dependencies:
|
|
||||||
define-properties "^1.1.2"
|
|
||||||
es-abstract "^1.5.1"
|
|
||||||
|
|
||||||
once@^1.3.0:
|
|
||||||
version "1.4.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
|
||||||
dependencies:
|
|
||||||
wrappy "1"
|
|
||||||
|
|
||||||
onetime@^2.0.0:
|
|
||||||
version "2.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4"
|
|
||||||
dependencies:
|
|
||||||
mimic-fn "^1.0.0"
|
|
||||||
|
|
||||||
ora@^1.1.0:
|
|
||||||
version "1.3.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/ora/-/ora-1.3.0.tgz#80078dd2b92a934af66a3ad72a5b910694ede51a"
|
|
||||||
dependencies:
|
|
||||||
chalk "^1.1.1"
|
|
||||||
cli-cursor "^2.1.0"
|
|
||||||
cli-spinners "^1.0.0"
|
|
||||||
log-symbols "^1.0.2"
|
|
||||||
|
|
||||||
os-homedir@^1.0.1:
|
|
||||||
version "1.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
|
|
||||||
|
|
||||||
path-is-absolute@^1.0.0:
|
|
||||||
version "1.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
|
|
||||||
|
|
||||||
path-parse@^1.0.5:
|
|
||||||
version "1.0.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1"
|
|
||||||
|
|
||||||
pify@^2.3.0:
|
|
||||||
version "2.3.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
|
|
||||||
|
|
||||||
pretty-bytes@^4.0.2:
|
|
||||||
version "4.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-4.0.2.tgz#b2bf82e7350d65c6c33aa95aaa5a4f6327f61cd9"
|
|
||||||
|
|
||||||
process-nextick-args@^1.0.6, process-nextick-args@~1.0.6:
|
|
||||||
version "1.0.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
|
|
||||||
|
|
||||||
qenv@^1.1.7:
|
|
||||||
version "1.1.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/qenv/-/qenv-1.1.7.tgz#d03f8bf8fe37494cf08d0919fe765dca84d9afae"
|
|
||||||
dependencies:
|
|
||||||
lodash "^4.17.4"
|
|
||||||
smartfile "^4.2.11"
|
|
||||||
typings-global "^1.0.16"
|
|
||||||
|
|
||||||
randomatic@^1.1.7:
|
|
||||||
version "1.1.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c"
|
|
||||||
dependencies:
|
|
||||||
is-number "^3.0.0"
|
|
||||||
kind-of "^4.0.0"
|
|
||||||
|
|
||||||
readable-stream@^2.0.2, readable-stream@^2.1.5:
|
|
||||||
version "2.3.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c"
|
|
||||||
dependencies:
|
|
||||||
core-util-is "~1.0.0"
|
|
||||||
inherits "~2.0.3"
|
|
||||||
isarray "~1.0.0"
|
|
||||||
process-nextick-args "~1.0.6"
|
|
||||||
safe-buffer "~5.1.1"
|
|
||||||
string_decoder "~1.0.3"
|
|
||||||
util-deprecate "~1.0.1"
|
|
||||||
|
|
||||||
rechoir@^0.6.2:
|
|
||||||
version "0.6.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
|
|
||||||
dependencies:
|
|
||||||
resolve "^1.1.6"
|
|
||||||
|
|
||||||
reflect-metadata@^0.1.2:
|
|
||||||
version "0.1.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.10.tgz#b4f83704416acad89988c9b15635d47e03b9344a"
|
|
||||||
|
|
||||||
remove-trailing-separator@^1.0.1:
|
|
||||||
version "1.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
|
|
||||||
|
|
||||||
replace-ext@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb"
|
|
||||||
|
|
||||||
require-reload@0.2.2:
|
|
||||||
version "0.2.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/require-reload/-/require-reload-0.2.2.tgz#29a7591846caf91b6e8a3cda991683f95f8d7d42"
|
|
||||||
|
|
||||||
resolve@^1.1.6:
|
|
||||||
version "1.5.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36"
|
|
||||||
dependencies:
|
|
||||||
path-parse "^1.0.5"
|
|
||||||
|
|
||||||
restore-cursor@^2.0.0:
|
|
||||||
version "2.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
|
|
||||||
dependencies:
|
|
||||||
onetime "^2.0.0"
|
|
||||||
signal-exit "^3.0.2"
|
|
||||||
|
|
||||||
rethinkdb@^2.3.3:
|
|
||||||
version "2.3.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/rethinkdb/-/rethinkdb-2.3.3.tgz#3dc6586e22fa1dabee0d254e64bd0e379fad2f72"
|
|
||||||
dependencies:
|
|
||||||
bluebird ">= 2.3.2 < 3"
|
|
||||||
|
|
||||||
right-pad@^1.0.1:
|
|
||||||
version "1.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/right-pad/-/right-pad-1.0.1.tgz#8ca08c2cbb5b55e74dafa96bf7fd1a27d568c8d0"
|
|
||||||
|
|
||||||
runtime-type-checks@0.0.4:
|
|
||||||
version "0.0.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/runtime-type-checks/-/runtime-type-checks-0.0.4.tgz#5682baf2ffe53f955fe3e065b40a0a09943845c8"
|
|
||||||
dependencies:
|
|
||||||
reflect-metadata "^0.1.2"
|
|
||||||
|
|
||||||
safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
|
||||||
version "5.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
|
|
||||||
|
|
||||||
shelljs@^0.7.8:
|
|
||||||
version "0.7.8"
|
|
||||||
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.8.tgz#decbcf874b0d1e5fb72e14b164a9683048e9acb3"
|
|
||||||
dependencies:
|
|
||||||
glob "^7.0.0"
|
|
||||||
interpret "^1.0.0"
|
|
||||||
rechoir "^0.6.2"
|
|
||||||
|
|
||||||
signal-exit@^3.0.2:
|
|
||||||
version "3.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
|
|
||||||
|
|
||||||
smartchai@^1.0.3:
|
|
||||||
version "1.0.8"
|
|
||||||
resolved "https://registry.yarnpkg.com/smartchai/-/smartchai-1.0.8.tgz#a074836f4ddd4b98c50f1e7ae9e8e8ad9f6f1902"
|
|
||||||
dependencies:
|
|
||||||
"@types/code" "^4.0.3"
|
|
||||||
code "^5.1.0"
|
|
||||||
typings-global "^1.0.20"
|
|
||||||
|
|
||||||
smartdelay@^1.0.3:
|
|
||||||
version "1.0.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/smartdelay/-/smartdelay-1.0.4.tgz#791c1a4ee6770494064c10b1d2d2b8e6f3105b82"
|
|
||||||
dependencies:
|
|
||||||
smartq "^1.1.1"
|
|
||||||
typings-global "^1.0.16"
|
|
||||||
|
|
||||||
smartenv@^2.0.0:
|
|
||||||
version "2.0.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/smartenv/-/smartenv-2.0.6.tgz#b38c679b0c151b9af548f68c3a072c29d1417e8d"
|
|
||||||
dependencies:
|
|
||||||
lodash "^4.17.4"
|
|
||||||
smartq "^1.1.1"
|
|
||||||
typings-global "^1.0.14"
|
|
||||||
|
|
||||||
smartfile@^4.2.11:
|
|
||||||
version "4.2.26"
|
|
||||||
resolved "https://registry.yarnpkg.com/smartfile/-/smartfile-4.2.26.tgz#800f08b1089e153b7fd8e0ba165da465a071d407"
|
|
||||||
dependencies:
|
|
||||||
"@types/fs-extra" "4.x.x"
|
|
||||||
"@types/vinyl" "^2.0.1"
|
|
||||||
fs-extra "^4.0.2"
|
|
||||||
glob "^7.1.2"
|
|
||||||
js-yaml "^3.10.0"
|
|
||||||
require-reload "0.2.2"
|
|
||||||
smartpath "^3.2.8"
|
|
||||||
smartq "^1.1.6"
|
|
||||||
smartrequest "^1.0.6"
|
|
||||||
typings-global "^1.0.20"
|
|
||||||
vinyl-file "^3.0.0"
|
|
||||||
|
|
||||||
smartpath@^3.2.8:
|
|
||||||
version "3.2.8"
|
|
||||||
resolved "https://registry.yarnpkg.com/smartpath/-/smartpath-3.2.8.tgz#4834bd3a8bae2295baacadba23c87a501952f940"
|
|
||||||
dependencies:
|
|
||||||
home "^1.0.1"
|
|
||||||
typings-global "^1.0.14"
|
|
||||||
|
|
||||||
smartq@^1.1.1, smartq@^1.1.6:
|
|
||||||
version "1.1.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/smartq/-/smartq-1.1.6.tgz#0c1ff4336d95e95b4f1fdd8ccd7e2c5a323b8412"
|
|
||||||
dependencies:
|
|
||||||
typings-global "^1.0.19"
|
|
||||||
util.promisify "^1.0.0"
|
|
||||||
|
|
||||||
smartrequest@^1.0.6:
|
|
||||||
version "1.0.8"
|
|
||||||
resolved "https://registry.yarnpkg.com/smartrequest/-/smartrequest-1.0.8.tgz#9af18dde34efa7d43b4ecfc92ccb157a98eda3b1"
|
|
||||||
dependencies:
|
|
||||||
smartq "^1.1.1"
|
|
||||||
|
|
||||||
smartstring@^2.0.28:
|
|
||||||
version "2.0.28"
|
|
||||||
resolved "https://registry.yarnpkg.com/smartstring/-/smartstring-2.0.28.tgz#384b808dc3780eff0031ce7925c1b1668abbcad5"
|
|
||||||
dependencies:
|
|
||||||
crypto-random-string "^1.0.0"
|
|
||||||
js-base64 "^2.3.2"
|
|
||||||
normalize-newline "^3.0.0"
|
|
||||||
randomatic "^1.1.7"
|
|
||||||
strip-indent "^2.0.0"
|
|
||||||
typings-global "^1.0.20"
|
|
||||||
|
|
||||||
sprintf-js@~1.0.2:
|
|
||||||
version "1.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
|
||||||
|
|
||||||
string_decoder@~1.0.3:
|
|
||||||
version "1.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab"
|
|
||||||
dependencies:
|
|
||||||
safe-buffer "~5.1.0"
|
|
||||||
|
|
||||||
strip-ansi@^3.0.0:
|
|
||||||
version "3.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
|
|
||||||
dependencies:
|
|
||||||
ansi-regex "^2.0.0"
|
|
||||||
|
|
||||||
strip-bom-buf@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/strip-bom-buf/-/strip-bom-buf-1.0.0.tgz#1cb45aaf57530f4caf86c7f75179d2c9a51dd572"
|
|
||||||
dependencies:
|
|
||||||
is-utf8 "^0.2.1"
|
|
||||||
|
|
||||||
strip-bom-stream@^2.0.0:
|
|
||||||
version "2.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz#f87db5ef2613f6968aa545abfe1ec728b6a829ca"
|
|
||||||
dependencies:
|
|
||||||
first-chunk-stream "^2.0.0"
|
|
||||||
strip-bom "^2.0.0"
|
|
||||||
|
|
||||||
strip-bom@^2.0.0:
|
|
||||||
version "2.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
|
|
||||||
dependencies:
|
|
||||||
is-utf8 "^0.2.0"
|
|
||||||
|
|
||||||
strip-indent@^2.0.0:
|
|
||||||
version "2.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68"
|
|
||||||
|
|
||||||
supports-color@^2.0.0:
|
|
||||||
version "2.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
|
|
||||||
|
|
||||||
symbol-tree@^3.2.2:
|
|
||||||
version "3.2.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"
|
|
||||||
|
|
||||||
tapbundle@^1.1.1:
|
|
||||||
version "1.1.8"
|
|
||||||
resolved "https://registry.yarnpkg.com/tapbundle/-/tapbundle-1.1.8.tgz#e08aee0e100a830d8a26a583a85d37ce53312e02"
|
|
||||||
dependencies:
|
|
||||||
"@types/node" "^8.0.33"
|
|
||||||
early "^2.1.1"
|
|
||||||
leakage "^0.3.0"
|
|
||||||
smartchai "^1.0.3"
|
|
||||||
smartdelay "^1.0.3"
|
|
||||||
smartq "^1.1.1"
|
|
||||||
typings-global "^1.0.19"
|
|
||||||
|
|
||||||
through2@^2.0.1:
|
|
||||||
version "2.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be"
|
|
||||||
dependencies:
|
|
||||||
readable-stream "^2.1.5"
|
|
||||||
xtend "~4.0.1"
|
|
||||||
|
|
||||||
typings-global@^1.0.14, typings-global@^1.0.16, typings-global@^1.0.19, typings-global@^1.0.20:
|
|
||||||
version "1.0.28"
|
|
||||||
resolved "https://registry.yarnpkg.com/typings-global/-/typings-global-1.0.28.tgz#e28cc965476564cbc00e438739e0aa0735d323d4"
|
|
||||||
|
|
||||||
universalify@^0.1.0:
|
|
||||||
version "0.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7"
|
|
||||||
|
|
||||||
util-deprecate@~1.0.1:
|
|
||||||
version "1.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
|
||||||
|
|
||||||
util.promisify@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030"
|
|
||||||
dependencies:
|
|
||||||
define-properties "^1.1.2"
|
|
||||||
object.getownpropertydescriptors "^2.0.3"
|
|
||||||
|
|
||||||
vinyl-file@^3.0.0:
|
|
||||||
version "3.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/vinyl-file/-/vinyl-file-3.0.0.tgz#b104d9e4409ffa325faadd520642d0a3b488b365"
|
|
||||||
dependencies:
|
|
||||||
graceful-fs "^4.1.2"
|
|
||||||
pify "^2.3.0"
|
|
||||||
strip-bom-buf "^1.0.0"
|
|
||||||
strip-bom-stream "^2.0.0"
|
|
||||||
vinyl "^2.0.1"
|
|
||||||
|
|
||||||
vinyl@^2.0.1:
|
|
||||||
version "2.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.1.0.tgz#021f9c2cf951d6b939943c89eb5ee5add4fd924c"
|
|
||||||
dependencies:
|
|
||||||
clone "^2.1.1"
|
|
||||||
clone-buffer "^1.0.0"
|
|
||||||
clone-stats "^1.0.0"
|
|
||||||
cloneable-readable "^1.0.0"
|
|
||||||
remove-trailing-separator "^1.0.1"
|
|
||||||
replace-ext "^1.0.0"
|
|
||||||
|
|
||||||
word-wrap@^1.0.3:
|
|
||||||
version "1.2.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
|
|
||||||
|
|
||||||
wrappy@1:
|
|
||||||
version "1.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
|
||||||
|
|
||||||
xtend@~4.0.1:
|
|
||||||
version "4.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
|
|
Reference in New Issue
Block a user