├── packages ├── rxdb │ ├── .eslintignore │ ├── sonar-project.properties │ ├── config │ │ ├── src │ │ │ ├── index.ts │ │ │ └── lib │ │ │ │ └── config.spec.ts │ │ ├── ng-package.json │ │ └── README.md │ ├── utils │ │ ├── src │ │ │ ├── index.ts │ │ │ └── lib │ │ │ │ └── utils.spec.ts │ │ ├── ng-package.json │ │ └── README.md │ ├── prepare │ │ ├── src │ │ │ ├── index.ts │ │ │ └── lib │ │ │ │ └── prepare.plugin.spec.ts │ │ ├── ng-package.json │ │ └── README.md │ ├── .eslintrc.json │ ├── collection │ │ ├── src │ │ │ ├── index.ts │ │ │ └── lib │ │ │ │ ├── helpers.spec.ts │ │ │ │ └── helpers.ts │ │ ├── ng-package.json │ │ └── README.md │ ├── query-params │ │ ├── src │ │ │ ├── index.ts │ │ │ ├── utils.ts │ │ │ ├── utils.spec.ts │ │ │ ├── query-params.plugin.spec.ts │ │ │ └── query-params.plugin.ts │ │ ├── ng-package.json │ │ └── README.md │ ├── signals │ │ ├── src │ │ │ └── index.ts │ │ ├── ng-package.json │ │ └── README.md │ ├── testing │ │ ├── src │ │ │ ├── index.ts │ │ │ └── lib │ │ │ │ └── stubs.ts │ │ ├── ng-package.json │ │ └── README.md │ ├── core │ │ ├── ng-package.json │ │ ├── src │ │ │ ├── index.ts │ │ │ └── lib │ │ │ │ ├── plugin.loader.ts │ │ │ │ └── service.ts │ │ └── README.md │ ├── replication-kinto │ │ ├── ng-package.json │ │ ├── src │ │ │ ├── index.ts │ │ │ ├── replication-kinto.spec.ts │ │ │ └── types.ts │ │ └── README.md │ ├── src │ │ ├── index.ts │ │ ├── test-setup.ts │ │ └── lib │ │ │ ├── rxdb.module.puml │ │ │ ├── rxdb.providers.spec.ts │ │ │ └── rxdb.module.spec.ts │ ├── tsconfig.spec.json │ ├── ng-package.json │ ├── tsconfig.lib.prod.json │ ├── tsconfig.lib.json │ ├── tsconfig.json │ ├── package.json │ ├── jest.config.ts │ ├── sequence.puml │ └── project.json └── streamlit-rxdb-dataframe │ ├── rxdb_dataframe │ ├── frontend │ │ ├── .eslintignore │ │ ├── src │ │ │ ├── main.tsx │ │ │ └── lib │ │ │ │ ├── RxDBDataframeArgs.ts │ │ │ │ ├── useNullableRenderData.ts │ │ │ │ ├── useEditingState.ts │ │ │ │ └── RxDBDataframe.tsx │ │ ├── project.json │ │ ├── index.html │ │ ├── build │ │ │ ├── index.html │ │ │ └── assets │ │ │ │ └── data │ │ │ │ ├── col.dump.json │ │ │ │ ├── db.dump.json │ │ │ │ └── todo.schema.json │ │ ├── .eslintrc.json │ │ ├── tsconfig.json │ │ ├── tsconfig.app.json │ │ ├── tsconfig.spec.json │ │ ├── public │ │ │ └── assets │ │ │ │ └── data │ │ │ │ ├── col.dump.json │ │ │ │ ├── db.dump.json │ │ │ │ └── todo.schema.json │ │ └── vite.config.ts │ └── test___init__.py │ ├── MANIFEST.in │ ├── screencast.gif │ ├── screenshot.png │ ├── sonar-project.properties │ ├── .streamlit │ └── config.toml │ ├── setup.py │ ├── LICENSE │ ├── e2e │ └── test_rxdb_dataframe.py │ ├── pyproject.toml │ ├── tests │ └── test_rxdb_dataframe.py │ └── example.py ├── tools ├── generators │ └── .gitkeep ├── .eslintrc.json ├── tsconfig.json ├── tsconfig.compodoc.json ├── tsconfig.tools.json ├── scripts │ ├── publish-tagged-builds.ts │ ├── conventional-changelog-config.js │ ├── publish-dev-builds.ts │ ├── semantic-release.js │ ├── set-metadata.ts │ ├── build-packages.ts │ └── utils.ts └── project.json ├── examples ├── demo │ ├── src │ │ ├── assets │ │ │ ├── .gitkeep │ │ │ ├── logo.png │ │ │ ├── images │ │ │ │ └── screenshot.png │ │ │ └── data │ │ │ │ ├── col.dump.json │ │ │ │ ├── todo.schema.json │ │ │ │ └── db.dump.json │ │ ├── test-setup.ts │ │ ├── favicon.ico │ │ ├── main.ts │ │ ├── app │ │ │ ├── todos │ │ │ │ ├── todos.pipe.ts │ │ │ │ ├── todos.module.ts │ │ │ │ ├── todos.component.css │ │ │ │ ├── todos.component.ts │ │ │ │ └── todos.service.ts │ │ │ ├── app.component.ts │ │ │ └── app.module.ts │ │ ├── polyfills.ts │ │ └── index.html │ ├── tsconfig.editor.json │ ├── tsconfig.spec.json │ ├── proxy.conf.js │ ├── tsconfig.json │ ├── tsconfig.app.json │ ├── .browserslistrc │ ├── jest.config.ts │ ├── .eslintrc.json │ └── project.json ├── standalone │ ├── src │ │ ├── assets │ │ │ ├── .gitkeep │ │ │ ├── logo.png │ │ │ ├── images │ │ │ │ └── screenshot.png │ │ │ └── data │ │ │ │ ├── col.dump.json │ │ │ │ ├── todo.schema.json │ │ │ │ └── db.dump.json │ │ ├── styles.css │ │ ├── favicon.ico │ │ ├── main.ts │ │ ├── test-setup.ts │ │ ├── app │ │ │ ├── app.routes.ts │ │ │ ├── todos │ │ │ │ ├── todos.component.css │ │ │ │ ├── todos.component.ts │ │ │ │ └── todos.component.html │ │ │ ├── app.component.ts │ │ │ └── app.config.ts │ │ └── index.html │ ├── tsconfig.editor.json │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ ├── .eslintrc.json │ ├── tsconfig.json │ ├── jest.config.ts │ └── project.json ├── screencast.gif ├── uml.NgxRxdbModule.png ├── uml.NgxRxdbService.png └── shared │ ├── index.ts │ ├── environment.prod.ts │ ├── todos.migration.ts │ ├── environment.ts │ ├── todos.animation.ts │ ├── todos.schema.ts │ ├── todos.conflictHandler.ts │ ├── todos.model.ts │ ├── todos.config.ts │ └── todos.replication.ts ├── image.png ├── tsconfig.json ├── .commitlintrc.json ├── .npmrc ├── .eslintignore ├── .husky ├── pre-push ├── commit-msg └── pre-commit ├── .lintstagedrc.json ├── .npmignore ├── .prettierignore ├── kinto.env ├── .vscode ├── extensions.json ├── tasks.json ├── settings.json └── launch.json ├── docker-compose.couch.yml ├── .prettierrc ├── .editorconfig ├── jest.config.ts ├── .env.example ├── jest.preset.js ├── .compodocrc.json ├── .gitignore ├── .renovaterc.json ├── docker-compose.kinto.yml ├── .github ├── workflows │ └── nx-release.yaml ├── PULL_REQUEST_TEMPLATE.md └── ISSUE_TEMPLATE.md ├── LICENSE.txt ├── tsconfig.base.json ├── decorate-angular-cli.js ├── nx.json ├── CODE_OF_CONDUCT.md └── CONTRIBUTING.md /packages/rxdb/.eslintignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tools/generators/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/demo/src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/rxdb/sonar-project.properties: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/standalone/src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/demo/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular'; 2 | -------------------------------------------------------------------------------- /image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voznik/ngx-odm/HEAD/image.png -------------------------------------------------------------------------------- /packages/rxdb/config/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/config'; 2 | -------------------------------------------------------------------------------- /packages/rxdb/utils/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/utils'; 2 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json" 3 | } 4 | -------------------------------------------------------------------------------- /tools/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../.eslintrc.json"] 3 | } 4 | -------------------------------------------------------------------------------- /tools/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.tools.json" 3 | } 4 | -------------------------------------------------------------------------------- /packages/rxdb/prepare/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/prepare.plugin'; 2 | -------------------------------------------------------------------------------- /.commitlintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@commitlint/config-conventional"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/rxdb/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/rxdb/collection/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/collection.service'; 2 | -------------------------------------------------------------------------------- /packages/rxdb/query-params/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './query-params.plugin'; 2 | -------------------------------------------------------------------------------- /packages/rxdb/signals/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './with-collection-service'; 2 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/rxdb_dataframe/frontend/.eslintignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # https://registry.npmjs.org 2 | allow-same-version=true 3 | scope=@ngx-odm 4 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | !.commitlintrc.json 3 | **/package.json 4 | tools/scripts 5 | -------------------------------------------------------------------------------- /.husky/pre-push: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npm run lint 5 | -------------------------------------------------------------------------------- /examples/screencast.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voznik/ngx-odm/HEAD/examples/screencast.gif -------------------------------------------------------------------------------- /packages/rxdb/testing/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/mocks'; 2 | export * from './lib/stubs'; 3 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include rxdb_dataframe/frontend/build * 2 | -------------------------------------------------------------------------------- /examples/demo/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voznik/ngx-odm/HEAD/examples/demo/src/favicon.ico -------------------------------------------------------------------------------- /packages/rxdb/config/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "lib": { 3 | "entryFile": "src/index.ts" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/rxdb/core/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "lib": { 3 | "entryFile": "src/index.ts" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/rxdb/core/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/service'; 2 | export * from './lib/plugin.loader'; 3 | -------------------------------------------------------------------------------- /packages/rxdb/prepare/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "lib": { 3 | "entryFile": "src/index.ts" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/rxdb/signals/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "lib": { 3 | "entryFile": "src/index.ts" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/rxdb/testing/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "lib": { 3 | "entryFile": "src/index.ts" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/rxdb/utils/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "lib": { 3 | "entryFile": "src/index.ts" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx --no-install commitlint --edit $1 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx --no-install lint-staged 5 | -------------------------------------------------------------------------------- /examples/uml.NgxRxdbModule.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voznik/ngx-odm/HEAD/examples/uml.NgxRxdbModule.png -------------------------------------------------------------------------------- /examples/uml.NgxRxdbService.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voznik/ngx-odm/HEAD/examples/uml.NgxRxdbService.png -------------------------------------------------------------------------------- /packages/rxdb/collection/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "lib": { 3 | "entryFile": "src/index.ts" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/rxdb/query-params/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "lib": { 3 | "entryFile": "src/index.ts" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /examples/demo/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voznik/ngx-odm/HEAD/examples/demo/src/assets/logo.png -------------------------------------------------------------------------------- /examples/standalone/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /packages/rxdb/replication-kinto/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "lib": { 3 | "entryFile": "src/index.ts" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /examples/standalone/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voznik/ngx-odm/HEAD/examples/standalone/src/favicon.ico -------------------------------------------------------------------------------- /examples/standalone/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voznik/ngx-odm/HEAD/examples/standalone/src/assets/logo.png -------------------------------------------------------------------------------- /examples/demo/src/assets/images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voznik/ngx-odm/HEAD/examples/demo/src/assets/images/screenshot.png -------------------------------------------------------------------------------- /.lintstagedrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "*.{ts,js}": ["eslint --fix", "git add"], 3 | "*.{html,css,scss,md,yml}": ["prettier --write", "git add"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/screencast.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voznik/ngx-odm/HEAD/packages/streamlit-rxdb-dataframe/screencast.gif -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voznik/ngx-odm/HEAD/packages/streamlit-rxdb-dataframe/screenshot.png -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vscode 3 | docs 4 | node_modules 5 | src/ 6 | tests/ 7 | **/*.ts 8 | 9 | typings.d.ts 10 | tslint.json 11 | tsconfig.json 12 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Add files here to ignore them from prettier formatting 2 | 3 | /dist 4 | /coverage 5 | 6 | /.nx/cache 7 | .angular 8 | **/index.html 9 | -------------------------------------------------------------------------------- /examples/standalone/src/assets/images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/voznik/ngx-odm/HEAD/examples/standalone/src/assets/images/screenshot.png -------------------------------------------------------------------------------- /packages/rxdb/src/index.ts: -------------------------------------------------------------------------------- 1 | // start:ng42.barrel 2 | export * from './lib/rxdb.module'; 3 | export * from './lib/rxdb.providers'; 4 | // end:ng42.barrel 5 | -------------------------------------------------------------------------------- /packages/rxdb/core/README.md: -------------------------------------------------------------------------------- 1 | # @ngx-odm/rxdb/core 2 | 3 | Secondary entry point of `@ngx-odm/rxdb`. It can be used by importing from `@ngx-odm/rxdb/core`. 4 | -------------------------------------------------------------------------------- /packages/rxdb/utils/README.md: -------------------------------------------------------------------------------- 1 | # @ngx-odm/rxdb/utils 2 | 3 | Secondary entry point of `@ngx-odm/rxdb`. It can be used by importing from `@ngx-odm/rxdb/utils`. 4 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/sonar-project.properties: -------------------------------------------------------------------------------- 1 | sonar.exclusions=example.py,rxdb_dataframe/frontend/vite.config.ts,rxdb_dataframe/frontend/build 2 | -------------------------------------------------------------------------------- /packages/rxdb/config/README.md: -------------------------------------------------------------------------------- 1 | # @ngx-odm/rxdb/config 2 | 3 | Secondary entry point of `@ngx-odm/rxdb`. It can be used by importing from `@ngx-odm/rxdb/config`. 4 | -------------------------------------------------------------------------------- /packages/rxdb/prepare/README.md: -------------------------------------------------------------------------------- 1 | # @ngx-odm/rxdb/utils 2 | 3 | Secondary entry point of `@ngx-odm/rxdb`. It can be used by importing from `@ngx-odm/rxdb/utils`. 4 | -------------------------------------------------------------------------------- /packages/rxdb/signals/README.md: -------------------------------------------------------------------------------- 1 | # @ngx-odm/rxdb/signals 2 | 3 | Secondary entry point of `@ngx-odm/rxdb`. It can be used by importing from `@ngx-odm/rxdb/signals`. 4 | -------------------------------------------------------------------------------- /packages/rxdb/testing/README.md: -------------------------------------------------------------------------------- 1 | # @ngx-odm/rxdb/testing 2 | 3 | Secondary entry point of `@ngx-odm/rxdb`. It can be used by importing from `@ngx-odm/rxdb/testing`. 4 | -------------------------------------------------------------------------------- /tools/tsconfig.compodoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.base.json", 3 | "include": [ 4 | // "../apps/**/*.ts", 5 | "../packages/**/*.ts" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /packages/rxdb/collection/README.md: -------------------------------------------------------------------------------- 1 | # @ngx-odm/rxdb/collection 2 | 3 | Secondary entry point of `@ngx-odm/rxdb`. It can be used by importing from `@ngx-odm/rxdb/collection`. 4 | -------------------------------------------------------------------------------- /examples/demo/tsconfig.editor.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["**/*.ts"], 4 | "compilerOptions": { 5 | "types": ["jest", "node"] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/rxdb/query-params/README.md: -------------------------------------------------------------------------------- 1 | # @ngx-odm/rxdb/query-params 2 | 3 | Secondary entry point of `@ngx-odm/rxdb`. It can be used by importing from `@ngx-odm/rxdb/query-params`. 4 | -------------------------------------------------------------------------------- /packages/rxdb/replication-kinto/src/index.ts: -------------------------------------------------------------------------------- 1 | // start:ng42.barrel 2 | export { replicateKintoDB } from './replication-kinto'; 3 | export * from './types'; 4 | // end:ng42.barrel 5 | -------------------------------------------------------------------------------- /examples/standalone/tsconfig.editor.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["src/**/*.ts"], 4 | "compilerOptions": { 5 | "types": ["jest", "node"] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/rxdb/replication-kinto/README.md: -------------------------------------------------------------------------------- 1 | # @ngx-odm/rxdb/replication-kinto 2 | 3 | Secondary entry point of `@ngx-odm/rxdb`. It can be used by importing from `@ngx-odm/rxdb/replication-kinto`. 4 | -------------------------------------------------------------------------------- /kinto.env: -------------------------------------------------------------------------------- 1 | # kinto.env 2 | KINTO_BATCH_MAX_REQUESTS = 60 3 | KINTO_CORS_ORIGINS = * 4 | # KINTO_STORAGE_BACKEND = kinto.core.storage.postgresql 5 | # KINTO_STORAGE_URL = postgresql://user:pass@localhost/kintodb 6 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "nrwl.angular-console", 4 | "angular.ng-template", 5 | "dbaeumer.vscode-eslint", 6 | "esbenp.prettier-vscode", 7 | "firsttris.vscode-jest-runner" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/.streamlit/config.toml: -------------------------------------------------------------------------------- 1 | [server] 2 | headless = true 3 | runOnSave = true 4 | allowRunOnSave = true 5 | # fastReruns = true 6 | fileWatcherType = "auto" 7 | 8 | [browser] 9 | gatherUsageStats = false 10 | 11 | [logger] 12 | level = "info" 13 | -------------------------------------------------------------------------------- /docker-compose.couch.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | db: 4 | image: couchdb:3 5 | environment: 6 | COUCHDB_USER: ${COUCHDB_USER} 7 | COUCHDB_PASSWORD: ${COUCHDB_PASSWORD} 8 | ports: 9 | - '5984:5984' 10 | volumes: 11 | - ./tmp/couchdb:/opt/couchdb/data 12 | -------------------------------------------------------------------------------- /examples/demo/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "files": ["src/test-setup.ts"], 9 | "include": ["**/*.spec.ts", "**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 92, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "semi": true, 6 | "singleQuote": true, 7 | "trailingComma": "es5", 8 | "bracketSpacing": true, 9 | "arrowParens": "avoid", 10 | "htmlWhitespaceSensitivity": "ignore", 11 | "jsxBracketSameLine": true 12 | } 13 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "eslint", 6 | "problemMatcher": ["$eslint-stylish"], 7 | "label": "eslint: lint whole folder", 8 | "isBackground": true 9 | // "runOptions": { "runOn": "folderOpen" } 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /examples/demo/proxy.conf.js: -------------------------------------------------------------------------------- 1 | const PROXY_CONFIG = { 2 | '/kinto/*': { 3 | target: 'http://localhost:8888', 4 | pathRewrite: { 5 | '^/kinto/': '/', 6 | }, 7 | changeOrigin: true, 8 | secure: false, 9 | logLevel: 'debug', 10 | }, 11 | }; 12 | 13 | module.exports = PROXY_CONFIG; 14 | -------------------------------------------------------------------------------- /examples/standalone/src/main.ts: -------------------------------------------------------------------------------- 1 | import { bootstrapApplication } from '@angular/platform-browser'; 2 | import 'process/browser'; 3 | import { AppComponent } from './app/app.component'; 4 | import { appConfig } from './app/app.config'; 5 | 6 | bootstrapApplication(AppComponent, appConfig).catch(err => console.error(err)); 7 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-default-export */ 2 | import { getJestProjects } from '@nx/jest'; 3 | import type { Config } from 'jest'; 4 | 5 | const config: Config = { 6 | projects: getJestProjects(), 7 | globalSetup: 'jest-preset-angular/global-setup', 8 | }; 9 | 10 | export default config; 11 | -------------------------------------------------------------------------------- /examples/standalone/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc" 5 | }, 6 | "files": ["src/main.ts"], 7 | "include": ["src/**/*.d.ts", "../../typings.d.ts"], 8 | "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /examples/shared/index.ts: -------------------------------------------------------------------------------- 1 | // start:ng42.barrel 2 | export * from './todos.animation'; 3 | export * from './todos.config'; 4 | export * from './todos.model'; 5 | export * from './todos.schema'; 6 | export * from './todos.replication'; 7 | export * from './todos.migration'; 8 | export * from './environment'; 9 | // end:ng42.barrel 10 | -------------------------------------------------------------------------------- /examples/standalone/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | // @ts-expect-error https://thymikee.github.io/jest-preset-angular/docs/getting-started/test-environment 2 | globalThis.ngJest = { 3 | testEnvironmentOptions: { 4 | errorOnUnknownElements: true, 5 | errorOnUnknownProperties: true, 6 | }, 7 | }; 8 | import 'jest-preset-angular/setup-jest'; 9 | -------------------------------------------------------------------------------- /packages/rxdb/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"], 7 | "allowJs": true 8 | }, 9 | "files": ["src/test-setup.ts"], 10 | "include": ["jest.config.ts", "**/*.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/rxdb_dataframe/frontend/src/main.tsx: -------------------------------------------------------------------------------- 1 | // import { StrictMode } from 'react'; 2 | import * as ReactDOM from 'react-dom/client'; 3 | 4 | import RxDBDataframe from './lib/RxDBDataframe'; 5 | 6 | const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement); 7 | root.render(); 8 | -------------------------------------------------------------------------------- /packages/rxdb/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "../../dist/packages/rxdb", 4 | "lib": { 5 | "flatModuleFile": "ngx-odm-rxdb", 6 | "entryFile": "src/index.ts" 7 | }, 8 | "allowedNonPeerDependencies": ["dexie", "rxdb"], 9 | "deleteDestPath": true 10 | } 11 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/rxdb_dataframe/frontend/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "streamlit-rxdb-dataframe-frontend", 3 | "$schema": "../../../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "packages/streamlit-rxdb-dataframe/frontend/src", 5 | "projectType": "application", 6 | "targets": {}, 7 | "tags": [] 8 | } 9 | -------------------------------------------------------------------------------- /examples/demo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": ["../../shared/*.ts"], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.app.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | }, 12 | { 13 | "path": "./tsconfig.editor.json" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /examples/shared/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | baseUrl: '/api/v1', 4 | kintoServer: 'https://demo.kinto-storage.org/v1/', 5 | bucket: 'default', 6 | collection: 'todos', 7 | couchDbRemote: 'localhost:5983', // process.env.COUCHDB_SERVER, 8 | couchDbSyncLive: true, 9 | couchDbSyncHeartbeat: 60, 10 | }; 11 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | COUCHDB_USER=admin 2 | COUCHDB_PASSWORD=adminadmin 3 | POSTGRES_NAME=postgres 4 | POSTGRES_USER=postgres 5 | POSTGRES_PASSWORD=postgres 6 | KINTO_CACHE_BACKEND=kinto.core.cache.memcached 7 | KINTO_CACHE_HOSTS=cache:11211 cache:11212 8 | KINTO_STORAGE_BACKEND=kinto.core.storage.postgresql 9 | KINTO_STORAGE_URL=postgresql://postgres:postgres@db/postgres 10 | -------------------------------------------------------------------------------- /examples/standalone/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "target": "es2016", 7 | "types": ["jest", "node"] 8 | }, 9 | "files": ["src/test-setup.ts"], 10 | "include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /examples/standalone/src/app/app.routes.ts: -------------------------------------------------------------------------------- 1 | import { Route } from '@angular/router'; 2 | 3 | export const appRoutes: Route[] = [ 4 | { 5 | path: 'todos', 6 | loadComponent: () => import('./todos/todos.component').then(mod => mod.TodosComponent), 7 | runGuardsAndResolvers: 'always', 8 | }, 9 | { 10 | path: '', 11 | redirectTo: 'todos', 12 | pathMatch: 'full', 13 | }, 14 | ]; 15 | -------------------------------------------------------------------------------- /examples/standalone/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | standalone 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/rxdb_dataframe/frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | RxdbDataframe 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/rxdb/tsconfig.lib.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.lib.json", 3 | "compilerOptions": { 4 | "declarationMap": false, 5 | "sourceMap": false, 6 | "inlineSources": false, 7 | "inlineSourceMap": false, 8 | "stripInternal": true, 9 | "removeComments": true, 10 | "listEmittedFiles": true 11 | }, 12 | "angularCompilerOptions": { 13 | "compilationMode": "partial" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/rxdb_dataframe/frontend/build/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | RxdbDataframe 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/demo/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | import 'process/browser'; 4 | import { environment } from '@shared'; 5 | import { AppModule } from './app/app.module'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic() 12 | .bootstrapModule(AppModule) 13 | .catch(err => console.error(err)); 14 | -------------------------------------------------------------------------------- /packages/rxdb/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../dist/out-tsc", 5 | "lib": ["dom", "es2020"], 6 | "types": ["node"], 7 | "declaration": true, 8 | "declarationMap": true 9 | }, 10 | "exclude": [ 11 | "**/*.spec.ts", 12 | "test-setup.ts", 13 | "jest.config.ts", 14 | "**/*.test.ts", 15 | "**/*.mock.ts" 16 | ], 17 | "include": ["**/*.ts"] 18 | } 19 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/rxdb_dataframe/frontend/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:@nx/react", "../../../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /examples/demo/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": ["node"] 6 | }, 7 | "include": ["../../typings.d.ts"], 8 | "files": ["src/main.ts", "src/polyfills.ts"], 9 | "angularCompilerOptions": { 10 | "enableI18nLegacyMessageIdFormat": false, 11 | "strictInjectionParameters": true, 12 | "strictInputAccessModifiers": true, 13 | "strictTemplates": true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/standalone/src/app/todos/todos.component.css: -------------------------------------------------------------------------------- 1 | .clear-completed:disabled { 2 | color: #999; 3 | cursor: not-allowed; 4 | text-decoration: none; 5 | } 6 | 7 | .todo-list li label + .last-modified { 8 | position: absolute; 9 | bottom: 4px; 10 | right: 24px; 11 | display: none; 12 | font-size: small; 13 | color: #999; 14 | text-decoration: none !important; 15 | } 16 | 17 | .todo-list li:hover label:not(.editing) + .last-modified { 18 | display: block; 19 | } 20 | -------------------------------------------------------------------------------- /tools/tsconfig.tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "ts-node": { 3 | "esm": true, 4 | "experimentalSpecifierResolution": "node", 5 | "compilerOptions": { 6 | "module": "CommonJS" 7 | } 8 | }, 9 | "compilerOptions": { 10 | "outDir": "../dist/out-tsc/tools", 11 | "rootDir": ".", 12 | "allowSyntheticDefaultImports": true, 13 | "esModuleInterop": true, 14 | "moduleResolution": "node", 15 | "module": "ESNext", 16 | "types": ["node"] 17 | }, 18 | "include": ["**/*.ts"] 19 | } 20 | -------------------------------------------------------------------------------- /tools/scripts/publish-tagged-builds.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | import { setMetadata } from './set-metadata'; 3 | import { publishAllPackagesToNpm } from './utils'; 4 | 5 | async function main() { 6 | const json = require('../../package.json'); 7 | console.log('publishing new version', json.version); 8 | 9 | setMetadata(); 10 | 11 | // run through all our packages and push them to npm 12 | await publishAllPackagesToNpm(json.version, 'latest'); 13 | } 14 | 15 | main(); 16 | -------------------------------------------------------------------------------- /tools/scripts/conventional-changelog-config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | types: [ 5 | { type: 'feat', section: 'Features' }, 6 | { type: 'fix', section: 'Bug Fixes' }, 7 | { type: 'chore', hidden: false }, 8 | { type: 'docs', hidden: false }, 9 | { type: 'style', hidden: false }, 10 | { type: 'refactor', section: 'Features', hidden: false }, 11 | { type: 'perf', section: 'Features', hidden: false }, 12 | { type: 'test', hidden: true }, 13 | { type: 'build', hidden: true }, 14 | ], 15 | }; 16 | -------------------------------------------------------------------------------- /examples/shared/todos.migration.ts: -------------------------------------------------------------------------------- 1 | // in this example we have 3 migrations, since the beginning of development 2 | export const todosMigrations = { 3 | 1: function (doc) { 4 | if (doc._deleted) { 5 | return null; 6 | } 7 | doc.last_modified = new Date(doc.createdAt).getTime(); // string to unix 8 | return doc; 9 | }, 10 | 2: function (doc) { 11 | if (doc._deleted) { 12 | return null; 13 | } 14 | doc.createdAt = new Date(doc.createdAt).toISOString(); // to string 15 | return doc; 16 | }, 17 | 3: d => d, 18 | }; 19 | -------------------------------------------------------------------------------- /examples/shared/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false, 7 | baseUrl: '/api/v1', 8 | kintoServer: '/kinto/v1', 9 | bucket: 'todo', 10 | collection: 'todos', 11 | couchDbRemote: 'localhost:5983', // process.env.COUCHDB_SERVER, 12 | couchDbSyncLive: true, 13 | couchDbSyncHeartbeat: 60, 14 | }; 15 | -------------------------------------------------------------------------------- /examples/shared/todos.animation.ts: -------------------------------------------------------------------------------- 1 | import { animate, query, stagger, style, transition, trigger } from '@angular/animations'; 2 | 3 | export const todosListAnimation = trigger('listAnimation', [ 4 | transition('* <=> *', [ 5 | query( 6 | ':enter', 7 | [ 8 | style({ opacity: 0 }), 9 | stagger('50ms', animate('60ms ease-in', style({ opacity: 1 }))), 10 | ], 11 | { optional: true } 12 | ), 13 | query(':leave', stagger('10ms', animate('50ms ease-out', style({ opacity: 0 }))), { 14 | optional: true, 15 | }), 16 | ]), 17 | ]); 18 | -------------------------------------------------------------------------------- /examples/standalone/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts"], 7 | "extends": [ 8 | "plugin:@nx/angular", 9 | "plugin:@angular-eslint/template/process-inline-templates" 10 | ], 11 | "rules": { 12 | "@angular-eslint/directive-selector": 2, 13 | "@angular-eslint/component-selector": 2 14 | } 15 | }, 16 | { 17 | "files": ["*.html"], 18 | "extends": ["plugin:@nx/angular-template"], 19 | "rules": {} 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /jest.preset.js: -------------------------------------------------------------------------------- 1 | const nxPreset = require('@nx/jest/preset').default; 2 | 3 | const CI = process.env.CI === 'true' || true; 4 | 5 | /** @type {import('jest').Config} */ 6 | const config = { 7 | ...nxPreset, 8 | collectCoverage: CI, 9 | coverageReporters: [ 10 | 'html', 11 | 'text-summary', 12 | 'json', 13 | ['lcov', { file: 'rxdb-coverage.lcov' }], 14 | ['json-summary', { file: 'rxdb-coverage-summary.json' }], 15 | ], 16 | bail: true, 17 | verbose: true, 18 | // resetModules: true, 19 | // clearMocks: true, 20 | passWithNoTests: true, 21 | }; 22 | 23 | module.exports = config; 24 | -------------------------------------------------------------------------------- /packages/rxdb/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "target": "es2020", 5 | "useDefineForClassFields": false, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": false, 10 | "noImplicitReturns": false, 11 | "noFallthroughCasesInSwitch": true 12 | }, 13 | "files": [], 14 | "include": [], 15 | "references": [ 16 | { 17 | "path": "./tsconfig.lib.json" 18 | }, 19 | { 20 | "path": "./tsconfig.spec.json" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/rxdb_dataframe/frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "jsx": "react-jsx", 4 | "allowJs": false, 5 | "esModuleInterop": false, 6 | "allowSyntheticDefaultImports": true, 7 | "strict": true, 8 | "isolatedModules": true, 9 | "noEmit": true, 10 | "types": ["vite/client", "vitest"] 11 | }, 12 | "files": [], 13 | "include": [], 14 | "references": [ 15 | { 16 | "path": "./tsconfig.app.json" 17 | }, 18 | { 19 | "path": "./tsconfig.spec.json" 20 | } 21 | ], 22 | "extends": "../../../../tsconfig.base.json" 23 | } 24 | -------------------------------------------------------------------------------- /examples/demo/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # For the full list of supported browsers by the Angular framework, please see: 6 | # https://angular.io/guide/browser-support 7 | 8 | # You can see what browsers were selected by your queries by running: 9 | # npx browserslist 10 | 11 | last 1 version 12 | > 1% 13 | Firefox ESR 14 | maintained node versions 15 | not dead 16 | not IE 9-11 17 | -------------------------------------------------------------------------------- /examples/standalone/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "types": ["node"] 5 | }, 6 | "files": [], 7 | "include": ["../../shared/*.ts"], 8 | "references": [ 9 | { 10 | "path": "./tsconfig.app.json" 11 | }, 12 | { 13 | "path": "./tsconfig.spec.json" 14 | }, 15 | { 16 | "path": "./tsconfig.editor.json" 17 | } 18 | ], 19 | "angularCompilerOptions": { 20 | "enableI18nLegacyMessageIdFormat": false, 21 | "strictInjectionParameters": true, 22 | "strictInputAccessModifiers": true, 23 | "strictTemplates": true 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/demo/src/app/todos/todos.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform, inject } from '@angular/core'; 2 | import { RXDB_CONFIG_COLLECTION } from '@ngx-odm/rxdb'; 3 | import { Todo, TodosFilter } from '@shared'; 4 | 5 | @Pipe({ name: 'byStatus' }) 6 | export class TodosPipe implements PipeTransform { 7 | colConfig = inject(RXDB_CONFIG_COLLECTION); 8 | transform(value: Todo[], status: TodosFilter, force = false): Todo[] { 9 | if (!value || (this.colConfig.options.useQueryParams && !force)) { 10 | return value; 11 | } 12 | if (status === 'ALL') { 13 | return value; 14 | } 15 | return value.filter(todo => todo.completed === (status === 'COMPLETED')); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/rxdb_dataframe/frontend/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../dist/out-tsc", 5 | "types": [ 6 | "node", 7 | "@nx/react/typings/cssmodule.d.ts", 8 | "@nx/react/typings/image.d.ts", 9 | "vite/client", 10 | "vitest/importMeta" 11 | ] 12 | }, 13 | "exclude": [ 14 | "src/**/*.spec.ts", 15 | "src/**/*.test.ts", 16 | "src/**/*.spec.tsx", 17 | "src/**/*.test.tsx", 18 | "src/**/*.spec.js", 19 | "src/**/*.test.js", 20 | "src/**/*.spec.jsx", 21 | "src/**/*.test.jsx" 22 | ], 23 | "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"] 24 | } 25 | -------------------------------------------------------------------------------- /.compodocrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@compodoc/compodoc/src/config/schema.json", 3 | "name": "@ngx-odm documentation", 4 | "tsConfig": "tools/tsconfig.compodoc.json", 5 | "outputPath": "dist/demo/documentation", 6 | "theme": "readthedocs", 7 | "workspaceDocs": true, 8 | "assetsFolder": "dist/demo/assets", 9 | "??:unitTestCoverage": "coverage/packages/rxdb-coverage-summary.json", 10 | "navTabConfig": [], 11 | "toggleMenuItems": ["all"], 12 | "hideGenerator": true, 13 | "disablePrivate": false, 14 | "disableProtected": false, 15 | "disableInternal": true, 16 | "disableCoverage": true, 17 | "disableRoutesGraph": true, 18 | "disableStyleTab": true, 19 | "disableGraph": false, 20 | "silent": false 21 | } 22 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "search.showLineNumbers": true, 3 | "debug.allowBreakpointsEverywhere": true, 4 | "workbench.colorCustomizations": { 5 | "statusBar.background": "#8d2089", 6 | "statusBar.foreground": "#e7e7e7", 7 | "statusBarItem.hoverBackground": "#b729b1", 8 | "sash.hoverBorder": "#b729b1", 9 | "statusBarItem.remoteBackground": "#8d2089", 10 | "statusBarItem.remoteForeground": "#e7e7e7" 11 | }, 12 | "peacock.color": "#8d2089", 13 | "python.defaultInterpreterPath": "/home/voznik/.cache/pypoetry/virtualenvs/streamlit-rxdb-dataframe-zuiqvGqO-py3.10", 14 | "flake8.args": ["--max-line-length=100"], 15 | "flake8.importStrategy": "fromEnvironment", 16 | "black-formatter.args": ["--line-length=100"] 17 | } 18 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/rxdb_dataframe/frontend/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../../../dist/out-tsc", 5 | "types": [ 6 | "vitest/globals", 7 | "vitest/importMeta", 8 | "vite/client", 9 | "node", 10 | "vitest", 11 | "@nx/react/typings/cssmodule.d.ts", 12 | "@nx/react/typings/image.d.ts" 13 | ] 14 | }, 15 | "include": [ 16 | "vite.config.ts", 17 | "vitest.config.ts", 18 | "src/**/*.test.ts", 19 | "src/**/*.spec.ts", 20 | "src/**/*.test.tsx", 21 | "src/**/*.spec.tsx", 22 | "src/**/*.test.js", 23 | "src/**/*.spec.js", 24 | "src/**/*.test.jsx", 25 | "src/**/*.spec.jsx", 26 | "src/**/*.d.ts" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /examples/demo/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'nx16', 4 | preset: '../../jest.preset.js', 5 | setupFilesAfterEnv: ['/src/test-setup.ts'], 6 | coverageDirectory: '../../coverage/apps/nx16', 7 | transform: { 8 | '^.+\\.(ts|mjs|js|html)$': [ 9 | 'jest-preset-angular', 10 | { 11 | tsconfig: '/tsconfig.spec.json', 12 | stringifyContentPathRegex: '\\.(html|svg)$', 13 | }, 14 | ], 15 | }, 16 | transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], 17 | snapshotSerializers: [ 18 | 'jest-preset-angular/build/serializers/no-ng-attributes', 19 | 'jest-preset-angular/build/serializers/ng-snapshot', 20 | 'jest-preset-angular/build/serializers/html-comment', 21 | ], 22 | }; 23 | -------------------------------------------------------------------------------- /examples/standalone/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'standalone', 4 | preset: '../../jest.preset.js', 5 | setupFilesAfterEnv: ['/src/test-setup.ts'], 6 | coverageDirectory: '../../coverage/examples/standalone', 7 | transform: { 8 | '^.+\\.(ts|mjs|js|html)$': [ 9 | 'jest-preset-angular', 10 | { 11 | tsconfig: '/tsconfig.spec.json', 12 | stringifyContentPathRegex: '\\.(html|svg)$', 13 | }, 14 | ], 15 | }, 16 | transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], 17 | snapshotSerializers: [ 18 | 'jest-preset-angular/build/serializers/no-ng-attributes', 19 | 'jest-preset-angular/build/serializers/ng-snapshot', 20 | 'jest-preset-angular/build/serializers/html-comment', 21 | ], 22 | }; 23 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/rxdb_dataframe/frontend/src/lib/RxDBDataframeArgs.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | RxCollectionCreatorExtended, 3 | RxDatabaseCreatorExtended, 4 | } from '@ngx-odm/rxdb/config'; 5 | import type { Entity, EntityId } from '@ngx-odm/rxdb/utils'; 6 | import { MangoQuery } from 'rxdb'; 7 | import { ArrowTable } from 'streamlit-component-lib'; 8 | 9 | export type DataframeEditingState = { 10 | edited_rows: Record; 11 | added_rows: Entity[]; 12 | deleted_rows: number[]; 13 | }; 14 | 15 | export interface RxDBDataframeArgs { 16 | collection_config: RxCollectionCreatorExtended; 17 | query?: MangoQuery; 18 | with_rev?: boolean; 19 | db_config: RxDatabaseCreatorExtended; 20 | dataframe: ArrowTable; 21 | data: Entity[]; 22 | editing_state: DataframeEditingState; 23 | } 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /docs 6 | /documentation 7 | /public 8 | /tmp 9 | /out-tsc 10 | **/builds 11 | **/@ngx-odm* 12 | 13 | # dependencies 14 | /node_modules 15 | .angular 16 | 17 | # IDEs and editors 18 | /.idea 19 | .project 20 | .classpath 21 | .c9/ 22 | *.launch 23 | .settings/ 24 | *.sublime-workspace 25 | 26 | # IDE - VSCode 27 | .vscode/* 28 | !.vscode/settings.json 29 | !.vscode/tasks.json 30 | !.vscode/launch.json 31 | !.vscode/extensions.json 32 | 33 | # misc 34 | .cache 35 | /.sass-cache 36 | /connect.lock 37 | /coverage 38 | /libpeerconnection.log 39 | npm-debug.log 40 | yarn-error.log 41 | testem.log 42 | /typings 43 | *.bak 44 | .env 45 | junit.xml 46 | 47 | # System Files 48 | .DS_Store 49 | Thumbs.db 50 | 51 | .nx/cache -------------------------------------------------------------------------------- /examples/demo/src/assets/data/col.dump.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "todo", 3 | "schemaHash": "9b18d72e95209a29cdc5f4849e21dc3c7c399f7d0fa070f159820e80ec2dee29", 4 | "docs": [ 5 | { 6 | "id": "a4c6a479-7cca-4d3b-ab90-45d3eaa957f3", 7 | "title": "Check other examples", 8 | "completed": false, 9 | "createdAt": 1548979200000, 10 | "last_modified": 1548979200000 11 | }, 12 | { 13 | "id": "a4c6a479-7cca-4d3b-bc10-45d3eaa957r5", 14 | "title": "Use \"@ngx-odm/rxdb\" in your project", 15 | "completed": false, 16 | "createdAt": 1698404710931, 17 | "last_modified": 1698404710931 18 | }, 19 | { 20 | "id": "ac3ef2c6-c98b-43e1-9047-71d68b1f92f4", 21 | "title": "Open Todo list example", 22 | "completed": true, 23 | "createdAt": 1546300800000, 24 | "last_modified": 1546300800000 25 | } 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /examples/standalone/src/assets/data/col.dump.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "todo", 3 | "schemaHash": "9b18d72e95209a29cdc5f4849e21dc3c7c399f7d0fa070f159820e80ec2dee29", 4 | "docs": [ 5 | { 6 | "id": "a4c6a479-7cca-4d3b-ab90-45d3eaa957f3", 7 | "title": "Check other examples", 8 | "completed": false, 9 | "createdAt": 1548979200000, 10 | "last_modified": 1548979200000 11 | }, 12 | { 13 | "id": "a4c6a479-7cca-4d3b-bc10-45d3eaa957r5", 14 | "title": "Use \"@ngx-odm/rxdb\" in your project", 15 | "completed": false, 16 | "createdAt": 1698404710931, 17 | "last_modified": 1698404710931 18 | }, 19 | { 20 | "id": "ac3ef2c6-c98b-43e1-9047-71d68b1f92f4", 21 | "title": "Open Todo list example", 22 | "completed": true, 23 | "createdAt": 1546300800000, 24 | "last_modified": 1546300800000 25 | } 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /examples/demo/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts"], 7 | "extends": [ 8 | "plugin:@nx/angular", 9 | "plugin:@angular-eslint/template/process-inline-templates" 10 | ], 11 | "rules": { 12 | "@angular-eslint/directive-selector": [ 13 | "error", 14 | { 15 | "type": "attribute", 16 | "style": "camelCase" 17 | } 18 | ], 19 | "@angular-eslint/component-selector": [ 20 | "error", 21 | { 22 | "type": "element", 23 | "style": "kebab-case" 24 | } 25 | ], 26 | "import/no-unresolved": 0 27 | } 28 | }, 29 | { 30 | "files": ["*.html"], 31 | "extends": ["plugin:@nx/angular-template"], 32 | "rules": {} 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /packages/rxdb/testing/src/lib/stubs.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | /// 3 | 4 | /** See https://github.com/angular/angular/issues/25837 */ 5 | export function setupNavigationWarnStub() { 6 | const warn = console.warn; 7 | const error = console.error; 8 | jest.spyOn(console, 'warn').mockImplementation((...args: any[]) => { 9 | const [firstArg] = args; 10 | if ( 11 | typeof firstArg === 'string' && 12 | firstArg.startsWith('Navigation triggered outside Angular zone') 13 | ) { 14 | return; 15 | } 16 | return warn.apply(console, args); 17 | }); 18 | jest.spyOn(console, 'error').mockImplementation((...args: any[]) => { 19 | const [firstArg] = args; 20 | if (typeof firstArg === 'string' && firstArg.startsWith('Attempted to log "[DEBUG')) { 21 | return; 22 | } 23 | return error.apply(console, args); 24 | }); 25 | } 26 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/rxdb_dataframe/frontend/build/assets/data/col.dump.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "todo", 3 | "schemaHash": "9b18d72e95209a29cdc5f4849e21dc3c7c399f7d0fa070f159820e80ec2dee29", 4 | "docs": [ 5 | { 6 | "id": "a4c6a479-7cca-4d3b-ab90-45d3eaa957f3", 7 | "title": "Check other examples", 8 | "completed": false, 9 | "createdAt": 1548979200000, 10 | "last_modified": 1548979200000 11 | }, 12 | { 13 | "id": "a4c6a479-7cca-4d3b-bc10-45d3eaa957r5", 14 | "title": "Use \"@ngx-odm/rxdb\" in your project", 15 | "completed": false, 16 | "createdAt": 1698404710931, 17 | "last_modified": 1698404710931 18 | }, 19 | { 20 | "id": "ac3ef2c6-c98b-43e1-9047-71d68b1f92f4", 21 | "title": "Open Todo list example", 22 | "completed": true, 23 | "createdAt": 1546300800000, 24 | "last_modified": 1546300800000 25 | } 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /packages/rxdb/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | (globalThis as any).ngJest = { 3 | testEnvironmentOptions: { 4 | errorOnUnknownElements: true, 5 | errorOnUnknownProperties: true, 6 | }, 7 | }; 8 | (globalThis as any).structuredClone = (val: any) => JSON.parse(JSON.stringify(val)); 9 | 10 | import 'setimmediate'; 11 | import 'jest-preset-angular/setup-jest'; 12 | 13 | if (process.env['CI']) { 14 | const consoleMethods: string[] = [ 15 | 'error', 16 | 'trace', 17 | 'debug', 18 | 'warn', 19 | 'log', 20 | 'group', 21 | 'groupCollapsed', 22 | ]; 23 | 24 | consoleMethods.forEach((methodName: string) => { 25 | jest.spyOn(global.console, methodName as any).mockImplementation((...args: any[]) => { 26 | if (methodName === 'error' && !args[0].includes('RxError')) { 27 | console.error(...args); 28 | } 29 | jest.fn(); 30 | }); 31 | }); 32 | } 33 | -------------------------------------------------------------------------------- /examples/demo/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'demo-root', 5 | template: ` 6 |
7 | 8 |
9 | `, 10 | styles: [ 11 | ` 12 | /* */ 13 | :host { 14 | display: block; 15 | font: 16 | 14px 'Helvetica Neue', 17 | Helvetica, 18 | Arial, 19 | sans-serif; 20 | line-height: 1.4em; 21 | background: #f5f5f5; 22 | color: #4d4d4d; 23 | min-width: 230px; 24 | max-width: 550px; 25 | margin: 0 auto; 26 | -webkit-font-smoothing: antialiased; 27 | -moz-osx-font-smoothing: grayscale; 28 | font-weight: 300; 29 | } 30 | 31 | .flex { 32 | display: flex; 33 | align-items: center; 34 | justify-content: center; 35 | } 36 | `, 37 | ], 38 | }) 39 | export class AppComponent {} 40 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/rxdb_dataframe/frontend/public/assets/data/col.dump.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "todo", 3 | "schemaHash": "9b18d72e95209a29cdc5f4849e21dc3c7c399f7d0fa070f159820e80ec2dee29", 4 | "docs": [ 5 | { 6 | "id": "a4c6a479-7cca-4d3b-ab90-45d3eaa957f3", 7 | "title": "Check other examples", 8 | "completed": false, 9 | "createdAt": "2019-02-01T00:00:00.000Z", 10 | "last_modified": 1548979200000 11 | }, 12 | { 13 | "id": "a4c6a479-7cca-4d3b-bc10-45d3eaa957r5", 14 | "title": "Use \"@ngx-odm/rxdb\" in your project", 15 | "completed": false, 16 | "createdAt": "2023-10-27T11:05:10.931Z", 17 | "last_modified": 1698404710931 18 | }, 19 | { 20 | "id": "ac3ef2c6-c98b-43e1-9047-71d68b1f92f4", 21 | "title": "Open Todo list example", 22 | "completed": true, 23 | "createdAt": "2019-02-01T00:01:00.000Z", 24 | "last_modified": 1546300800000 25 | } 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /examples/shared/todos.schema.ts: -------------------------------------------------------------------------------- 1 | export const TODO_SCHEMA = { 2 | definitions: {}, 3 | type: 'object', 4 | title: 'Todo', 5 | description: 'Todo Schema', 6 | required: ['id', 'title', 'createdAt'], 7 | version: 3, 8 | properties: { 9 | id: { 10 | type: 'string', 11 | title: 'Id', 12 | pattern: '^(.*)$', 13 | maxLength: 36, 14 | readOnly: true, 15 | }, 16 | title: { 17 | type: 'string', 18 | title: 'Title', 19 | }, 20 | completed: { 21 | type: 'boolean', 22 | title: 'Done', 23 | }, 24 | createdAt: { 25 | type: 'string', 26 | title: 'Created Date', 27 | format: 'date-time', 28 | readOnly: true, 29 | }, 30 | last_modified: { 31 | type: 'number', 32 | title: 'Last Modified Date', 33 | multipleOf: 1, 34 | }, 35 | }, 36 | __indexes: ['createdAt'], 37 | primaryKey: 'id', 38 | attachments: { 39 | encrypted: false, 40 | }, 41 | }; 42 | -------------------------------------------------------------------------------- /examples/shared/todos.conflictHandler.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | RxConflictHandler, 3 | RxConflictHandlerInput, 4 | RxConflictHandlerOutput, 5 | } from 'rxdb'; 6 | import { deepEqual } from 'rxdb'; 7 | import { Todo } from './todos.model'; 8 | 9 | /** 10 | * The default conflict handler is a function that gets called when a conflict is detected. 11 | * In your custom conflict handler you likely want to merge properties of the realMasterState and the newDocumentState instead. 12 | * @param i 13 | * @see https://rxdb.info/replication.html#conflict-handling 14 | */ 15 | export const todosConflictHandler: RxConflictHandler = function ( 16 | i: RxConflictHandlerInput 17 | ): Promise> { 18 | if (deepEqual(i.newDocumentState, i.realMasterState)) { 19 | return Promise.resolve({ 20 | isEqual: true, 21 | }); 22 | } 23 | return Promise.resolve({ 24 | isEqual: false, 25 | documentData: i.realMasterState, 26 | }); 27 | }; 28 | -------------------------------------------------------------------------------- /.renovaterc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base", 4 | "group:all", 5 | "monorepo:angular", 6 | "schedule:monthly", 7 | ":maintainLockFilesMonthly" 8 | ], 9 | "ignoreDeps": [ 10 | "typescript", 11 | "semantic-release", 12 | "@semantic-release/git", 13 | "@semantic-release/changelog" 14 | ], 15 | "pinVersions": false, 16 | "separatePatchReleases": false, 17 | "ignoreUnstable": true, 18 | "automerge": true, 19 | "automergeType": "branch-push", 20 | "lockFileMaintenance": { 21 | "enabled": true 22 | }, 23 | "peerDependencies": { 24 | "versionStrategy": "widen" 25 | }, 26 | "packageRules": [ 27 | { 28 | "sourceUrlPrefixes": ["https://github.com/babel/babel"], 29 | "groupName": "babel monorepo" 30 | }, 31 | { 32 | "packagePatterns": ["^eslint"], 33 | "groupName": "eslint" 34 | }, 35 | { 36 | "packagePatterns": ["jest"], 37 | "groupName": "jest" 38 | } 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /docker-compose.kinto.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | db: 4 | image: postgres:14 5 | environment: 6 | POSTGRES_NAME: ${POSTGRES_NAME} 7 | POSTGRES_USER: ${POSTGRES_USER} 8 | POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} 9 | healthcheck: 10 | test: ['CMD', 'pg_isready', '-U', 'postgres'] 11 | interval: 5s 12 | timeout: 5s 13 | retries: 5 14 | ports: 15 | - '5432:5432' 16 | cache: 17 | image: memcached:1 18 | web: 19 | build: 20 | context: . 21 | dockerfile: Dockerfile 22 | image: kinto/kinto-server:latest 23 | depends_on: 24 | db: 25 | condition: service_healthy 26 | cache: 27 | condition: service_started 28 | ports: 29 | - '8888:8888' 30 | environment: 31 | KINTO_CACHE_BACKEND: ${KINTO_CACHE_BACKEND} 32 | KINTO_CACHE_HOSTS: ${KINTO_CACHE_HOSTS} 33 | KINTO_STORAGE_BACKEND: ${KINTO_STORAGE_BACKEND} 34 | KINTO_STORAGE_URL: ${KINTO_STORAGE_URL} 35 | -------------------------------------------------------------------------------- /examples/standalone/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, inject } from '@angular/core'; 2 | import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; 3 | import { NavigationEnd, Router, RouterModule } from '@angular/router'; 4 | import { RenderScheduler } from '@ngrx/component'; 5 | import { filter } from 'rxjs'; 6 | 7 | @Component({ 8 | standalone: true, 9 | imports: [RouterModule], 10 | selector: 'app-root', 11 | template: ` 12 | 13 | `, 14 | providers: [RenderScheduler], 15 | }) 16 | export class AppComponent { 17 | private router = inject(Router); 18 | private renderScheduler = inject(RenderScheduler); 19 | 20 | constructor() { 21 | this.zonelessCD(); 22 | } 23 | 24 | private zonelessCD(): void { 25 | this.router.events 26 | .pipe( 27 | filter(event => event instanceof NavigationEnd), 28 | takeUntilDestroyed() 29 | ) 30 | .subscribe(() => this.renderScheduler.schedule()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/standalone/src/assets/data/todo.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "definitions": {}, 3 | "$schema": "http://json-schema.org/draft-07/schema#", 4 | "type": "object", 5 | "title": "Todo", 6 | "description": "Todo Schema", 7 | "required": ["id", "title", "createdAt"], 8 | "version": 3, 9 | "properties": { 10 | "id": { 11 | "type": "string", 12 | "title": "Id", 13 | "pattern": "^(.*)$", 14 | "maxLength": 36, 15 | "readOnly": true 16 | }, 17 | "title": { 18 | "type": "string", 19 | "title": "Title" 20 | }, 21 | "completed": { 22 | "type": "boolean", 23 | "title": "Done" 24 | }, 25 | "createdAt": { 26 | "type": "string", 27 | "title": "Created Date", 28 | "format": "date-time", 29 | "readOnly": true 30 | }, 31 | "last_modified": { 32 | "type": "number", 33 | "title": "Last Modified Date", 34 | "multipleOf": 1 35 | } 36 | }, 37 | "__indexes": ["createdAt"], 38 | "primaryKey": "id" 39 | } 40 | -------------------------------------------------------------------------------- /examples/demo/src/assets/data/todo.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "definitions": {}, 3 | "$schema": "http://json-schema.org/draft-07/schema#", 4 | "type": "object", 5 | "title": "Todo", 6 | "description": "Todo Schema", 7 | "required": ["id", "title", "createdAt"], 8 | "version": 3, 9 | "properties": { 10 | "id": { 11 | "type": "string", 12 | "title": "Id", 13 | "pattern": "^(.*)$", 14 | "maxLength": 36, 15 | "readOnly": true 16 | }, 17 | "title": { 18 | "type": "string", 19 | "title": "Title" 20 | }, 21 | "completed": { 22 | "type": "boolean", 23 | "title": "Done" 24 | }, 25 | "createdAt": { 26 | "type": "string", 27 | "title": "Created Date", 28 | "format": "date-time", 29 | "readOnly": true 30 | }, 31 | "last_modified": { 32 | "type": "number", 33 | "title": "Last Modified Date", 34 | "multipleOf": 1 35 | } 36 | }, 37 | "__indexes": ["createdAt"], 38 | "primaryKey": "id", 39 | "attachments": { 40 | "encrypted": false 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/demo/src/assets/data/db.dump.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "instanceToken": "vhngmgjupw", 4 | "collections": [ 5 | { 6 | "name": "todo", 7 | "schemaHash": "9b18d72e95209a29cdc5f4849e21dc3c7c399f7d0fa070f159820e80ec2dee29", 8 | "docs": [ 9 | { 10 | "id": "a4c6a479-7cca-4d3b-ab90-45d3eaa957f3", 11 | "title": "Check other examples", 12 | "completed": false, 13 | "createdAt": 1548979200000, 14 | "last_modified": 1548979200000 15 | }, 16 | { 17 | "id": "a4c6a479-7cca-4d3b-bc10-45d3eaa957r5", 18 | "title": "Use \"@ngx-odm/rxdb\" in your project", 19 | "completed": false, 20 | "createdAt": 1698404710931, 21 | "last_modified": 1698404710931 22 | }, 23 | { 24 | "id": "ac3ef2c6-c98b-43e1-9047-71d68b1f92f4", 25 | "title": "Open Todo list example", 26 | "completed": true, 27 | "createdAt": 1546300800000, 28 | "last_modified": 1546300800000 29 | } 30 | ] 31 | } 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /examples/standalone/src/assets/data/db.dump.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "instanceToken": "vhngmgjupw", 4 | "collections": [ 5 | { 6 | "name": "todo", 7 | "schemaHash": "9b18d72e95209a29cdc5f4849e21dc3c7c399f7d0fa070f159820e80ec2dee29", 8 | "docs": [ 9 | { 10 | "id": "a4c6a479-7cca-4d3b-ab90-45d3eaa957f3", 11 | "title": "Check other examples", 12 | "completed": false, 13 | "createdAt": 1548979200000, 14 | "last_modified": 1548979200000 15 | }, 16 | { 17 | "id": "a4c6a479-7cca-4d3b-bc10-45d3eaa957r5", 18 | "title": "Use \"@ngx-odm/rxdb\" in your project", 19 | "completed": false, 20 | "createdAt": 1698404710931, 21 | "last_modified": 1698404710931 22 | }, 23 | { 24 | "id": "ac3ef2c6-c98b-43e1-9047-71d68b1f92f4", 25 | "title": "Open Todo list example", 26 | "completed": true, 27 | "createdAt": 1546300800000, 28 | "last_modified": 1546300800000 29 | } 30 | ] 31 | } 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /.github/workflows/nx-release.yaml: -------------------------------------------------------------------------------- 1 | # @see https://nx.dev/recipes/nx-release/publish-in-ci-cd 2 | name: Publish 3 | 4 | on: 5 | workflow_dispatch: 6 | 7 | jobs: 8 | test: 9 | name: Publish 10 | runs-on: ubuntu-latest 11 | permissions: 12 | contents: read 13 | id-token: write # needed for provenance data generation 14 | timeout-minutes: 10 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 0 20 | 21 | - name: Install Node 22 | uses: actions/setup-node@v4 23 | with: 24 | node-version: 20 25 | registry-url: https://registry.npmjs.org/ 26 | 27 | - name: Install dependencies 28 | run: npm install 29 | shell: bash 30 | 31 | - name: Print Environment Info 32 | run: npx nx report 33 | shell: bash 34 | 35 | - name: Publish packages 36 | run: npx nx release publish 37 | shell: bash 38 | env: 39 | NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }} 40 | NPM_CONFIG_PROVENANCE: true 41 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | setuptools.setup( 4 | name="streamlit-rxdb-dataframe", 5 | version="0.0.1", 6 | author="voznik", 7 | author_email="", 8 | author_url="github.com/voznik", 9 | description="Custom DataFrame connecting RxDB collection", 10 | long_description="Custom DataFrame connecting RxDB collection", 11 | long_description_content_type="text/plain", 12 | url="", 13 | packages=setuptools.find_packages(), 14 | include_package_data=True, 15 | classifiers=[], 16 | python_requires=">=3.7", 17 | install_requires=[ 18 | # By definition, a Custom Component depends on Streamlit. 19 | # If your component has other Python dependencies, list 20 | # them here. 21 | "streamlit >= 0.66", 22 | ], 23 | extras_require={ 24 | "devel": [ 25 | "wheel", 26 | "pytest==7.4.0", 27 | "playwright==1.39.0", 28 | "requests==2.31.0", 29 | "pytest-playwright-snapshot==1.0", 30 | "pytest-rerunfailures==12.0", 31 | ] 32 | } 33 | ) 34 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/rxdb_dataframe/frontend/build/assets/data/db.dump.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "instanceToken": "vhngmgjupw", 4 | "collections": [ 5 | { 6 | "name": "todo", 7 | "schemaHash": "9b18d72e95209a29cdc5f4849e21dc3c7c399f7d0fa070f159820e80ec2dee29", 8 | "docs": [ 9 | { 10 | "id": "a4c6a479-7cca-4d3b-ab90-45d3eaa957f3", 11 | "title": "Check other examples", 12 | "completed": false, 13 | "createdAt": 1548979200000, 14 | "last_modified": 1548979200000 15 | }, 16 | { 17 | "id": "a4c6a479-7cca-4d3b-bc10-45d3eaa957r5", 18 | "title": "Use \"@ngx-odm/rxdb\" in your project", 19 | "completed": false, 20 | "createdAt": 1698404710931, 21 | "last_modified": 1698404710931 22 | }, 23 | { 24 | "id": "ac3ef2c6-c98b-43e1-9047-71d68b1f92f4", 25 | "title": "Open Todo list example", 26 | "completed": true, 27 | "createdAt": 1546300800000, 28 | "last_modified": 1546300800000 29 | } 30 | ] 31 | } 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/rxdb_dataframe/frontend/public/assets/data/db.dump.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "instanceToken": "vhngmgjupw", 4 | "collections": [ 5 | { 6 | "name": "todo", 7 | "schemaHash": "9b18d72e95209a29cdc5f4849e21dc3c7c399f7d0fa070f159820e80ec2dee29", 8 | "docs": [ 9 | { 10 | "id": "a4c6a479-7cca-4d3b-ab90-45d3eaa957f3", 11 | "title": "Check other examples", 12 | "completed": false, 13 | "createdAt": 1548979200000, 14 | "last_modified": 1548979200000 15 | }, 16 | { 17 | "id": "a4c6a479-7cca-4d3b-bc10-45d3eaa957r5", 18 | "title": "Use \"@ngx-odm/rxdb\" in your project", 19 | "completed": false, 20 | "createdAt": 1698404710931, 21 | "last_modified": 1698404710931 22 | }, 23 | { 24 | "id": "ac3ef2c6-c98b-43e1-9047-71d68b1f92f4", 25 | "title": "Open Todo list example", 26 | "completed": true, 27 | "createdAt": 1546300800000, 28 | "last_modified": 1546300800000 29 | } 30 | ] 31 | } 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018-2021 Streamlit Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2020 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/rxdb_dataframe/frontend/build/assets/data/todo.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "definitions": {}, 3 | "$schema": "http://json-schema.org/draft-07/schema#", 4 | "type": "object", 5 | "title": "Todo", 6 | "description": "Todo Schema", 7 | "required": ["id", "title", "createdAt"], 8 | "version": 0, 9 | "properties": { 10 | "id": { 11 | "type": "string", 12 | "format": "uuid", 13 | "title": "Id", 14 | "pattern": "^(.*)$", 15 | "maxLength": 36, 16 | "readOnly": true 17 | }, 18 | "title": { 19 | "type": "string", 20 | "title": "Title", 21 | "minLength": 3 22 | }, 23 | "completed": { 24 | "type": "boolean", 25 | "title": "Done" 26 | }, 27 | "createdAt": { 28 | "type": "string", 29 | "title": "Created Date", 30 | "format": "date-time", 31 | "readOnly": true 32 | }, 33 | "last_modified": { 34 | "type": "integer", 35 | "format": "time", 36 | "title": "Last Modified Date" 37 | } 38 | }, 39 | "__indexes": ["createdAt"], 40 | "primaryKey": "id", 41 | "attachments": { 42 | "encrypted": false 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /examples/shared/todos.model.ts: -------------------------------------------------------------------------------- 1 | export interface Todo { 2 | id: string; 3 | title: string; 4 | completed: boolean; 5 | createdAt: string; 6 | last_modified: number; 7 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 8 | _attachments?: Record; 9 | } 10 | 11 | export type TodosFilter = 'ALL' | 'COMPLETED' | 'ACTIVE'; 12 | 13 | export interface TodosLocalState { 14 | filter: TodosFilter; 15 | } 16 | 17 | export const TODOS_INITIAL_ITEMS = [ 18 | { 19 | id: 'ac3ef2c6-c98b-43e1-9047-71d68b1f92f4', 20 | title: 'Open Todo list example', 21 | completed: true, 22 | createdAt: new Date(1546300800000).toISOString(), 23 | last_modified: 1546300800000, 24 | }, 25 | { 26 | id: 'a4c6a479-7cca-4d3b-ab90-45d3eaa957f3', 27 | title: 'Check other examples', 28 | completed: false, 29 | createdAt: new Date(1548979200000).toISOString(), 30 | last_modified: 1548979200000, 31 | }, 32 | { 33 | id: 'a4c6a479-7cca-4d3b-bc10-45d3eaa957r5', 34 | title: 'Use "@ngx-odm/rxdb" in your project', 35 | completed: false, 36 | createdAt: new Date().toISOString(), 37 | last_modified: Date.now(), 38 | }, 39 | ]; 40 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/rxdb_dataframe/frontend/public/assets/data/todo.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "definitions": {}, 3 | "$schema": "http://json-schema.org/draft-07/schema#", 4 | "type": "object", 5 | "title": "Todo", 6 | "description": "Todo Schema", 7 | "required": ["id", "title", "createdAt"], 8 | "version": 0, 9 | "properties": { 10 | "id": { 11 | "type": "string", 12 | "format": "uuid", 13 | "title": "Id", 14 | "pattern": "^(.*)$", 15 | "maxLength": 36, 16 | "readOnly": true 17 | }, 18 | "title": { 19 | "type": "string", 20 | "title": "Title", 21 | "minLength": 3 22 | }, 23 | "completed": { 24 | "type": "boolean", 25 | "title": "Done" 26 | }, 27 | "createdAt": { 28 | "type": "string", 29 | "title": "Created Date", 30 | "format": "date-time", 31 | "readOnly": true 32 | }, 33 | "last_modified": { 34 | "type": "integer", 35 | "format": "time", 36 | "title": "Last Modified Date" 37 | } 38 | }, 39 | "__indexes": ["createdAt"], 40 | "primaryKey": "id", 41 | "attachments": { 42 | "encrypted": false 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/rxdb/src/lib/rxdb.module.puml: -------------------------------------------------------------------------------- 1 | @startuml NgxRxdbModule Initialization 2 | 3 | actor User 4 | participant ApplicationInitStatus 5 | participant NgxRxdbModule 6 | participant NgxRxdbService 7 | participant RXDB_COLLECTION 8 | participant RXDB_CONFIG 9 | 10 | User -> ApplicationInitStatus: Start Application 11 | User -> NgxRxdbModule: Import NgxRxdbModule.forRoot(config) 12 | NgxRxdbModule -> RXDB_CONFIG: Provide RXDB_CONFIG 13 | NgxRxdbModule -> NgxRxdbService: Provide NgxRxdbService 14 | NgxRxdbModule -> ApplicationInitStatus: APP_INITIALIZER 15 | 16 | activate NgxRxdbService 17 | NgxRxdbService -> NgxRxdbModule: Initialize NgxRxdbService 18 | NgxRxdbModule -> RXDB_CONFIG: Initialize with RXDB_CONFIG 19 | NgxRxdbService -> RXDB_CONFIG: Use RXDB_CONFIG 20 | NgxRxdbService -> NgxRxdbModule: NgxRxdbService Initialized 21 | NgxRxdbService -> ApplicationInitStatus: Done with Initialization 22 | 23 | deactivate NgxRxdbService 24 | 25 | User -> RXDB_COLLECTION: Use RXDB_COLLECTION 26 | RXDB_COLLECTION -> NgxRxdbService: Use NgxRxdbService 27 | NgxRxdbService --> RXDB_COLLECTION: Provide NgxRxdbService 28 | RXDB_COLLECTION -> RXDB_CONFIG: Use RXDB_CONFIG 29 | NgxRxdbService --> RXDB_CONFIG: Provide RXDB_CONFIG 30 | 31 | @enduml 32 | -------------------------------------------------------------------------------- /tools/scripts/publish-dev-builds.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires, @typescript-eslint/no-non-null-assertion */ 2 | import { parse, SemVer } from 'semver'; 3 | import { setMetadata } from './set-metadata'; 4 | import { execute, publishAllPackagesToNpm } from './utils'; 5 | 6 | export async function main() { 7 | const json = require('../../package.json'); 8 | 9 | // determine commit from either circle ci or last git commit 10 | let commit = process.env.CIRCLE_SHA1; 11 | if (!commit) { 12 | const lastCommit = await execute('git rev-parse HEAD'); 13 | commit = lastCommit.toString().trim(); 14 | } 15 | 16 | // shorten commit 17 | commit = commit!.slice(0, 7); 18 | 19 | // construct new version from base version 2.0.0 to become 2.0.0+dev.shortsha 20 | const version: SemVer = parse(json.version)!; 21 | const newVersion = `${version.major}.${version.minor}.${version.patch}-dev`; // .master-${commit}`; 22 | 23 | console.log('setting metada for all packages'); 24 | 25 | setMetadata(true); 26 | 27 | console.log('publishing new version', newVersion); 28 | 29 | // run through all our packages and push them to npm 30 | await publishAllPackagesToNpm(newVersion, 'dev'); 31 | } 32 | 33 | main(); 34 | -------------------------------------------------------------------------------- /examples/demo/src/app/todos/todos.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { Inject, NgModule } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { RouterModule } from '@angular/router'; 5 | import { LetDirective, PushPipe } from '@ngrx/component'; 6 | import { NgxRxdbModule, RXDB_COLLECTION } from '@ngx-odm/rxdb'; 7 | import { RxDBCollectionService } from '@ngx-odm/rxdb/collection'; 8 | import { TODOS_COLLECTION_CONFIG, Todo } from '@shared'; 9 | import { TodosComponent } from './todos.component'; 10 | import { TodosPipe } from './todos.pipe'; 11 | import { TodosService } from './todos.service'; 12 | 13 | @NgModule({ 14 | imports: [ 15 | RouterModule.forChild([{ path: '', component: TodosComponent }]), 16 | CommonModule, 17 | FormsModule, 18 | LetDirective, 19 | PushPipe, 20 | NgxRxdbModule.forFeature(TODOS_COLLECTION_CONFIG), // creates RxDB collection from config 21 | ], 22 | declarations: [TodosComponent, TodosPipe], 23 | providers: [TodosService], 24 | }) 25 | export class TodosModule { 26 | constructor( 27 | @Inject(RXDB_COLLECTION) private collectionService: RxDBCollectionService 28 | ) { 29 | this.collectionService.sync(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/e2e/test_rxdb_dataframe.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | import pytest 4 | 5 | from playwright.sync_api import Page, expect 6 | 7 | from e2e_utils import StreamlitRunner 8 | 9 | ROOT_DIRECTORY = Path(__file__).parent.parent.absolute() 10 | BASIC_EXAMPLE_FILE = ROOT_DIRECTORY / "rxdb_dataframe" / "example.py" 11 | 12 | @pytest.fixture(autouse=True, scope="module") 13 | def streamlit_app(): 14 | with StreamlitRunner(BASIC_EXAMPLE_FILE) as runner: 15 | yield runner 16 | 17 | 18 | @pytest.fixture(autouse=True, scope="function") 19 | def go_to_app(page: Page, streamlit_app: StreamlitRunner): 20 | page.goto(streamlit_app.server_url) 21 | # Wait for app to load 22 | page.get_by_role("img", name="Running...").is_hidden() 23 | 24 | 25 | def test_should_render_dataframe(page: Page): 26 | frame = page.frame_locator( 27 | 'iframe[title="rxdb_dataframe\\.rxdb_dataframe"]' 28 | ) 29 | cell_in_frame = frame.get_by_role("cell", name="Jason") 30 | expect(cell_in_frame).to_be_visible() 31 | 32 | st_table = page.get_by_test_id('stTable') 33 | 34 | frame.get_by_role("button", name="Return dataframe").click() 35 | cell_generated = st_table.get_by_role("cell", name="Jason") 36 | expect(cell_generated).to_be_visible() 37 | -------------------------------------------------------------------------------- /examples/demo/src/app/todos/todos.component.css: -------------------------------------------------------------------------------- 1 | /* @import "https://unpkg.com/open-props"; */ 2 | 3 | .clear-completed:disabled { 4 | color: #999; 5 | cursor: not-allowed; 6 | text-decoration: none; 7 | } 8 | 9 | .todo-list li label + .last-modified { 10 | position: absolute; 11 | bottom: 4px; 12 | right: 24px; 13 | display: none; 14 | font-size: small; 15 | color: #999; 16 | text-decoration: none !important; 17 | } 18 | 19 | .todo-list li:hover label:not(.editing) + .last-modified { 20 | display: block; 21 | } 22 | 23 | dialog { 24 | position: fixed; 25 | top: 50%; 26 | left: 50%; 27 | transform: translate(-50%, -50%); 28 | z-index: 1000; 29 | width: 80%; 30 | max-width: 500px; 31 | padding: 20px; 32 | border: 1px solid #ccc; 33 | box-shadow: 34 | 0 2px 4px 0 rgba(0, 0, 0, 0.2), 35 | 0 25px 50px 0 rgba(0, 0, 0, 0.1); 36 | background: white; 37 | color: #111111; 38 | font-family: unset; 39 | } 40 | 41 | dialog > form { 42 | padding-top: 1em; 43 | border-top: 1px solid #ccc; 44 | width: 100%; 45 | display: flex; 46 | justify-content: space-between; 47 | } 48 | dialog > form > button { 49 | display: block; 50 | } 51 | 52 | dialog::backdrop { 53 | /* make the backdrop a semi-transparent black */ 54 | background-color: rgba(0, 0, 0, 0.4); 55 | } 56 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## PR Checklist 2 | 3 | Please check if your PR fulfills the following requirements: 4 | 5 | - [ ] The commit message follows our guidelines: https://github.com/voznik/ngx-odm/blob/master/CONTRIBUTING.md#commit 6 | - [ ] Tests for the changes have been added (for bug fixes / features) 7 | - [ ] Docs have been added / updated (for bug fixes / features) 8 | 9 | ## PR Type 10 | 11 | What kind of change does this PR introduce? 12 | 13 | 14 | 15 | ``` 16 | [ ] Bugfix 17 | [ ] Feature 18 | [ ] Code style update (formatting, local variables) 19 | [ ] Refactoring (no functional changes, no api changes) 20 | [ ] Build related changes 21 | [ ] CI related changes 22 | [ ] Documentation content changes 23 | [ ] Other... Please describe: 24 | ``` 25 | 26 | ## What is the current behavior? 27 | 28 | 29 | 30 | Issue Number: N/A 31 | 32 | ## What is the new behavior? 33 | 34 | ## Does this PR introduce a breaking change? 35 | 36 | ``` 37 | [ ] Yes 38 | [ ] No 39 | ``` 40 | 41 | 42 | 43 | ## Other information 44 | -------------------------------------------------------------------------------- /tools/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tools", 3 | "$schema": "../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "tools", 5 | "projectType": "library", 6 | "targets": { 7 | "compodoc": { 8 | "executor": "@twittwer/compodoc:compodoc", 9 | "options": { 10 | "name": "@ngx-odm documentation", 11 | "tsConfig": "tools/tsconfig.compodoc.json", 12 | "outputPath": "dist/demo/documentation", 13 | "theme": "readthedocs", 14 | "workspaceDocs": true, 15 | "assetsFolder": "dist/demo/assets", 16 | "unitTestCoverage": "coverage/packages/rxdb-coverage-summary.json", 17 | "navTabConfig": [], 18 | "toggleMenuItems": ["all"], 19 | "hideGenerator": true, 20 | "disablePrivate": false, 21 | "disableProtected": false, 22 | "disableInternal": true, 23 | "disableCoverage": true, 24 | "disableRoutesGraph": true, 25 | "disableStyleTab": true, 26 | "disableGraph": false, 27 | "silent": false 28 | }, 29 | "configurations": { 30 | "json": { 31 | "exportFormat": "json" 32 | }, 33 | "watch": { 34 | "serve": true, 35 | "watch": true, 36 | "silent": false 37 | } 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tools/scripts/semantic-release.js: -------------------------------------------------------------------------------- 1 | const parser = require('git-log-parser'); // eslint-disable-line 2 | 3 | // this is hack which allows to use semantic-release for monorepo 4 | // https://github.com/semantic-release/semantic-release/issues/193#issuecomment-578436666 5 | parser.parse = (parse => (config, options) => { 6 | if (Array.isArray(config._)) { 7 | config._.push(options.cwd); 8 | } else if (config._) { 9 | config._ = [config._, options.cwd]; 10 | } else { 11 | config._ = options.cwd; 12 | } 13 | return parse(config, options); 14 | })(parser.parse); 15 | 16 | module.exports = { 17 | tagFormat: `${process.env.npm_package_name}@\${version}`, 18 | branches: ['master', { name: 'next', channel: 'next', prerelease: true }], 19 | verifyConditions: [ 20 | '@semantic-release/changelog', 21 | '@semantic-release/npm', 22 | '@semantic-release/git', 23 | '@semantic-release/github', 24 | ], 25 | prepare: [ 26 | { 27 | path: '@semantic-release/changelog', 28 | changelogTitle: 29 | '# Change Log\n\nAll notable changes to this project will be documented in this file.', 30 | }, 31 | '@semantic-release/npm', 32 | { 33 | path: '@semantic-release/git', 34 | message: `chore(release): ${process.env.npm_package_name}@\${nextRelease.version} [skip ci]`, 35 | }, 36 | ], 37 | success: [], 38 | }; 39 | -------------------------------------------------------------------------------- /packages/rxdb/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/package", 3 | "private": false, 4 | "name": "@ngx-odm/rxdb", 5 | "version": "6.0.1", 6 | "description": "Angular 14+ wrapper (module or standalone) for RxDB - A realtime Database for the Web", 7 | "keywords": [ 8 | "angular", 9 | "ngrx", 10 | "rxjs", 11 | "rxdb", 12 | "nosql", 13 | "indexeddb", 14 | "pouchdb", 15 | "typescript", 16 | "kinto", 17 | "replication" 18 | ], 19 | "homepage": "https://github.com/voznik/ngx-odm#readme", 20 | "bugs": { 21 | "url": "https://github.com/voznik/ngx-odm/issues" 22 | }, 23 | "repository": { 24 | "type": "git", 25 | "url": "git+https://github.com/voznik/ngx-odm.git" 26 | }, 27 | "license": "MIT", 28 | "author": { 29 | "name": "voznik", 30 | "url": "https://github.com/voznik" 31 | }, 32 | "contributors": [ 33 | { 34 | "name": "voznik", 35 | "url": "https://github.com/voznik" 36 | } 37 | ], 38 | "sideEffects": false, 39 | "engines": { 40 | "node": ">=14.16", 41 | "npm": ">=8.x" 42 | }, 43 | "peerDependencies": { 44 | "@angular/common": ">=v14", 45 | "@angular/core": ">=v14", 46 | "rxjs": "^6.6.7 || ^7.6.0", 47 | "query-string": "^8.1.0" 48 | }, 49 | "dependencies": { 50 | "rxdb": "^15.9.1", 51 | "tslib": "2.0.3" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/rxdb_dataframe/frontend/src/lib/useNullableRenderData.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react'; 2 | import { Subscription } from 'rxjs'; 3 | import { Streamlit, RenderData } from 'streamlit-component-lib'; 4 | import { RxDBDataframeArgs } from './RxDBDataframeArgs'; 5 | 6 | /** 7 | * Returns `RenderData` received from Streamlit after the first render event received. 8 | * @param sub Subscriptions holder 9 | */ 10 | export const useNullableRenderData = ( 11 | sub: Subscription 12 | ): RenderData | undefined => { 13 | const [renderData, setRenderData] = useState>(); 14 | 15 | useEffect(() => { 16 | const onRenderEvent = (event: Event): void => { 17 | const renderEvent = event as CustomEvent; 18 | setRenderData(renderEvent.detail); 19 | }; 20 | 21 | // Set up event listeners, and signal to Streamlit that we're ready. 22 | // We won't render the component until we receive the first RENDER_EVENT. 23 | Streamlit.events.addEventListener(Streamlit.RENDER_EVENT, onRenderEvent); 24 | Streamlit.setComponentReady(); 25 | 26 | const cleanup = () => { 27 | Streamlit.events.removeEventListener(Streamlit.RENDER_EVENT, onRenderEvent); 28 | sub.unsubscribe(); 29 | }; 30 | return cleanup; 31 | }, []); 32 | 33 | return renderData; 34 | }; 35 | -------------------------------------------------------------------------------- /packages/rxdb/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-default-export */ 2 | import { workspaceRoot } from '@nrwl/tao/src/utils/app-root'; 3 | import type { Config } from 'jest'; 4 | 5 | const ignoredModules = [ 6 | 'query-string', 7 | 'decode-uri-component', 8 | 'split-on-first', 9 | 'filter-obj', 10 | ]; 11 | 12 | const config: Config = { 13 | displayName: '@ngx-odm/rxdb', 14 | preset: '../../jest.preset.js', 15 | setupFilesAfterEnv: ['/src/test-setup.ts', 'jest-localstorage-mock'], 16 | // A set of global variables that need to be available in all test environments 17 | globals: { 18 | __DEV__: true, 19 | VERSION: 'x.x.x', 20 | }, 21 | transform: { 22 | '^.+\\.(ts|mjs|js|html)$': [ 23 | 'jest-preset-angular', 24 | { 25 | tsconfig: '/tsconfig.spec.json', 26 | stringifyContentPathRegex: '\\.(html|svg)$', 27 | }, 28 | ], 29 | }, 30 | transformIgnorePatterns: [ 31 | // 32 | `node_modules/(?!.*\\.mjs$|${ignoredModules.join('|')})`, 33 | ], 34 | collectCoverage: process.env.CI ? true : false, 35 | coverageDirectory: `${workspaceRoot}/coverage/packages`, 36 | collectCoverageFrom: [ 37 | '**/*.{ts,tsx}', 38 | '!**/**/index.ts', 39 | '!**/node_modules/**', 40 | '!utils/**/*.{ts,tsx}', 41 | '!testing/**/*.{ts,tsx}', 42 | '!jest.config.ts', 43 | ], 44 | }; 45 | 46 | export default config; 47 | -------------------------------------------------------------------------------- /examples/demo/src/app/todos/todos.component.ts: -------------------------------------------------------------------------------- 1 | import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; 2 | import { Title } from '@angular/platform-browser'; 3 | import { Todo, todosListAnimation } from '@shared'; 4 | import { Observable, tap } from 'rxjs'; 5 | import { TodosService } from './todos.service'; 6 | 7 | @Component({ 8 | selector: 'demo-todos', 9 | templateUrl: './todos.component.html', 10 | styleUrls: ['./todos.component.css'], 11 | changeDetection: ChangeDetectionStrategy.OnPush, 12 | animations: [todosListAnimation], 13 | }) 14 | export class TodosComponent { 15 | private title = inject(Title); 16 | readonly todosService = inject(TodosService); 17 | 18 | filter$ = this.todosService.filter$; 19 | todos$: Observable = this.todosService.todos$.pipe( 20 | tap(docs => { 21 | const total = docs.length; 22 | const remaining = docs.filter(doc => !doc.completed).length; 23 | this.title.setTitle(`(${total - remaining}/${total}) Todos done`); 24 | }) 25 | ); 26 | count$ = this.todosService.count$; 27 | 28 | isDialogOpen = false; 29 | selectedTodo: Todo = undefined; 30 | 31 | trackByFn = (index: number, item: Todo) => { 32 | return item.last_modified; 33 | }; 34 | 35 | showContextMenu(event: Event, todo: Todo) { 36 | event.preventDefault(); 37 | this.selectedTodo = todo; 38 | this.isDialogOpen = true; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/rxdb/utils/src/lib/utils.spec.ts: -------------------------------------------------------------------------------- 1 | import { of } from 'rxjs'; 2 | import { mapFindResultToJsonArray } from './utils'; 3 | 4 | describe('NgxRxdb Utils', () => { 5 | describe('mapFindResultToJsonArray', () => { 6 | it('should map find result to JSON array without rev and attachments', () => { 7 | const input = [ 8 | { _id: '1', _rev: 'rev1', _attachments: {}, _deleted: false, _meta: {} }, 9 | { _id: '2', _rev: 'rev2', _attachments: {}, _deleted: false, _meta: {} }, 10 | ]; 11 | const expectedOutput = [{ _id: '1' }, { _id: '2' }]; 12 | 13 | of(input) 14 | .pipe(mapFindResultToJsonArray()) 15 | .subscribe(output => { 16 | expect(output).toEqual(expectedOutput); 17 | }); 18 | }); 19 | 20 | it('should map find result to JSON array with rev and attachments', () => { 21 | const input = [ 22 | { _id: '1', _rev: 'rev1', _attachments: {}, _deleted: false, _meta: {} }, 23 | { _id: '2', _rev: 'rev2', _attachments: {}, _deleted: false, _meta: {} }, 24 | ]; 25 | const expectedOutput = [ 26 | { _id: '1', _rev: 'rev1', _attachments: {}, _deleted: false, _meta: {} }, 27 | { _id: '2', _rev: 'rev2', _attachments: {}, _deleted: false, _meta: {} }, 28 | ]; 29 | 30 | of(input) 31 | .pipe(mapFindResultToJsonArray(true)) 32 | .subscribe(output => { 33 | expect(output).toEqual(expectedOutput); 34 | }); 35 | }); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /examples/shared/todos.config.ts: -------------------------------------------------------------------------------- 1 | import type { RxCollectionCreatorExtended } from '@ngx-odm/rxdb/config'; 2 | import type { RxCollection } from 'rxdb'; 3 | import { todosConflictHandler } from './todos.conflictHandler'; 4 | import { todosMigrations } from './todos.migration'; 5 | import { TODOS_INITIAL_ITEMS } from './todos.model'; 6 | import { todosReplicationStateFactory } from './todos.replication'; 7 | 8 | export async function percentageCompletedFn() { 9 | const allDocs = await (this as RxCollection).find().exec(); 10 | return allDocs.filter(doc => !!doc.completed).length / allDocs.length; 11 | } 12 | const collectionMethods = { 13 | percentageCompleted: percentageCompletedFn, 14 | }; 15 | 16 | export const TODOS_COLLECTION_CONFIG: RxCollectionCreatorExtended = { 17 | name: 'todo', 18 | localDocuments: true, 19 | schema: undefined, // to load schema from remote url pass `undefined` here 20 | options: { 21 | schemaUrl: 'assets/data/todo.schema.json', // load schema from remote url 22 | initialDocs: TODOS_INITIAL_ITEMS, // populate collection with initial data, 23 | useQueryParams: localStorage['_ngx_rxdb_queryparams'] === 'true', // bind collection filtering/sorting to URL query params, 24 | replicationStateFactory: todosReplicationStateFactory, // create replication state for collection 25 | }, 26 | statics: collectionMethods, 27 | // in this example we have 3 migrations, since the beginning of development 28 | migrationStrategies: todosMigrations, 29 | conflictHandler: todosConflictHandler, // don't need custom for CouchDb example 30 | }; 31 | -------------------------------------------------------------------------------- /packages/rxdb/core/src/lib/plugin.loader.ts: -------------------------------------------------------------------------------- 1 | import { RxDBPreparePlugin } from '@ngx-odm/rxdb/prepare'; 2 | import { RxDBPUseQueryParamsPlugin } from '@ngx-odm/rxdb/query-params'; 3 | import { NgxRxdbUtils } from '@ngx-odm/rxdb/utils'; 4 | import { RxPlugin, addRxPlugin } from 'rxdb'; 5 | import { RxDBCleanupPlugin } from 'rxdb/plugins/cleanup'; 6 | import { RxDBJsonDumpPlugin } from 'rxdb/plugins/json-dump'; 7 | import { RxDBLocalDocumentsPlugin } from 'rxdb/plugins/local-documents'; 8 | import { RxDBMigrationPlugin } from 'rxdb/plugins/migration-schema'; 9 | import { RxDBUpdatePlugin } from 'rxdb/plugins/update'; 10 | 11 | const { logger } = NgxRxdbUtils; 12 | 13 | /** 14 | * Loads all the necessary and additional RxDB plugins for the application to work. 15 | * @param plugins 16 | * @returns A Promise that resolves when all the plugins have been loaded. 17 | * @throws If there was an error loading the plugins. 18 | */ 19 | export async function loadRxDBPlugins(plugins: RxPlugin[] = []): Promise { 20 | try { 21 | // vendor 22 | addRxPlugin(RxDBLocalDocumentsPlugin); 23 | addRxPlugin(RxDBJsonDumpPlugin); 24 | addRxPlugin(RxDBMigrationPlugin); 25 | addRxPlugin(RxDBUpdatePlugin); 26 | addRxPlugin(RxDBCleanupPlugin); 27 | // custom 28 | addRxPlugin(RxDBPreparePlugin); 29 | addRxPlugin(RxDBPUseQueryParamsPlugin); 30 | // additional plugins 31 | for (const plugin of plugins) { 32 | addRxPlugin(plugin); 33 | } 34 | logger.log('rxdb plugins loaded'); 35 | } catch (error) { 36 | throw new Error(error.message ?? error); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/rxdb_dataframe/frontend/vite.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-default-export */ 2 | /// 3 | import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin'; 4 | import react from '@vitejs/plugin-react-swc'; 5 | import { defineConfig } from 'vite'; 6 | // import json from 'vite-plugin-json'; 7 | // import staticFiles from 'vite-plugin-static'; 8 | // import jsonServer from 'vite-plugin-json-server'; 9 | 10 | export default defineConfig({ 11 | logLevel: 'info', 12 | root: __dirname, 13 | cacheDir: '../../../../node_modules/.vite/packages/streamlit-rxdb-dataframe/frontend', 14 | 15 | server: { 16 | port: 4201, 17 | host: 'localhost', 18 | }, 19 | 20 | preview: { 21 | port: 4301, 22 | host: 'localhost', 23 | }, 24 | 25 | plugins: [ 26 | // json(), 27 | react({ tsDecorators: true, devTarget: 'es2022' }), 28 | nxViteTsPaths(), 29 | ], 30 | 31 | // Uncomment this if you are using workers. 32 | // worker: { 33 | // plugins: [ nxViteTsPaths() ], 34 | // }, 35 | base: './', // This is needed to make compiled app work in Streamlit. 36 | build: { 37 | outDir: './build', 38 | emptyOutDir: true, 39 | reportCompressedSize: true, 40 | terserOptions: { 41 | mangle: false, 42 | }, 43 | sourcemap: true, 44 | commonjsOptions: { 45 | transformMixedEsModules: true, 46 | }, 47 | rollupOptions: { 48 | output: { 49 | entryFileNames: `[name].js`, // disable hash in file name 50 | chunkFileNames: `[name].js`, // disable hash in chunk file name 51 | }, 52 | }, 53 | }, 54 | }); 55 | -------------------------------------------------------------------------------- /tools/scripts/set-metadata.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-default-export, @typescript-eslint/no-var-requires */ 2 | import { writeFile } from 'fs'; 3 | import { getPackages } from './utils'; 4 | 5 | export async function setMetadata(dev = false) { 6 | const rootJson = require('../../package.json'); 7 | const keysToCopy = [ 8 | 'version', 9 | 'repository', 10 | 'keywords', 11 | 'author', 12 | 'contributors', 13 | 'license', 14 | 'bugs', 15 | 'homepage', 16 | // 'funding', 17 | ]; 18 | 19 | const packages = getPackages(); 20 | for (const pack of packages) { 21 | const packPath = `${pack.buildPath}/package.json`; 22 | const packPackage = require(packPath); 23 | 24 | // copy all meta data from the root package.json into all packages 25 | for (const key of keysToCopy) { 26 | packPackage[key] = rootJson[key]; 27 | } 28 | 29 | if (dev) { 30 | packPackage.version = `${rootJson.version}-dev`; 31 | } 32 | 33 | // set all the packages peerDependencies to be the same as root package.json version 34 | for (const packageInfo of packages) { 35 | if (packPackage.peerDependencies[packageInfo.packageName]) { 36 | packPackage.peerDependencies[ 37 | packageInfo.packageName 38 | ] = `^${rootJson.version} || ^${rootJson.version}-dev`; 39 | } 40 | } 41 | 42 | // save the package file after we have updated the keys and peerDependencies 43 | await writeFile(packPath, JSON.stringify(packPackage, null, 2), err => { 44 | if (err) { 45 | console.error('Write failed!'); 46 | } 47 | }); 48 | } 49 | 50 | console.log(`package version set to ${rootJson.version}`); 51 | } 52 | -------------------------------------------------------------------------------- /examples/demo/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 4 | import { RouterModule, Routes } from '@angular/router'; 5 | import { NgxRxdbModule } from '@ngx-odm/rxdb'; 6 | import { getRxDatabaseCreator } from '@ngx-odm/rxdb/config'; 7 | import { RxDBAttachmentsPlugin } from 'rxdb/plugins/attachments'; 8 | import { RxDBDevModePlugin } from 'rxdb/plugins/dev-mode'; 9 | import { RxDBLeaderElectionPlugin } from 'rxdb/plugins/leader-election'; 10 | import { AppComponent } from './app.component'; 11 | 12 | const routes: Routes = [ 13 | { 14 | path: 'todos', 15 | loadChildren: () => import('./todos/todos.module').then(mod => mod.TodosModule), 16 | }, 17 | { 18 | path: '', 19 | redirectTo: 'todos', 20 | pathMatch: 'full', 21 | }, 22 | ]; 23 | 24 | @NgModule({ 25 | declarations: [AppComponent], 26 | imports: [ 27 | BrowserModule, 28 | BrowserAnimationsModule, 29 | RouterModule.forRoot(routes), 30 | NgxRxdbModule.forRoot( 31 | getRxDatabaseCreator({ 32 | name: 'demo', 33 | localDocuments: false, 34 | multiInstance: true, 35 | ignoreDuplicate: false, 36 | options: { 37 | plugins: [ 38 | // will be loaded by together with core plugins 39 | RxDBDevModePlugin, 40 | RxDBAttachmentsPlugin, 41 | RxDBLeaderElectionPlugin, 42 | ], 43 | storageType: localStorage['_ngx_rxdb_storage'] ?? 'dexie', 44 | dumpPath: 'assets/data/db.dump.json', 45 | }, 46 | }) 47 | ), 48 | ], 49 | providers: [], 50 | bootstrap: [AppComponent], 51 | }) 52 | export class AppModule {} 53 | -------------------------------------------------------------------------------- /examples/standalone/src/app/app.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-unused-vars */ 2 | import { provideHttpClient } from '@angular/common/http'; 3 | import { ApplicationConfig, NgZone, ɵNoopNgZone } from '@angular/core'; 4 | import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; 5 | import { provideRouter, withRouterConfig } from '@angular/router'; 6 | import { provideRxDatabase } from '@ngx-odm/rxdb'; 7 | import { getRxDatabaseCreator } from '@ngx-odm/rxdb/config'; 8 | import { RxDBAttachmentsPlugin } from 'rxdb/plugins/attachments'; 9 | import { RxDBDevModePlugin } from 'rxdb/plugins/dev-mode'; 10 | import { RxDBLeaderElectionPlugin } from 'rxdb/plugins/leader-election'; 11 | import { appRoutes } from './app.routes'; 12 | 13 | export const appConfig: ApplicationConfig = { 14 | providers: [ 15 | { provide: NgZone, useClass: ɵNoopNgZone }, 16 | provideRouter(appRoutes, withRouterConfig({ onSameUrlNavigation: 'reload' })), 17 | provideAnimationsAsync(), 18 | provideHttpClient(), 19 | provideRxDatabase( 20 | getRxDatabaseCreator({ 21 | name: 'demo', 22 | localDocuments: true, 23 | multiInstance: true, 24 | ignoreDuplicate: false, 25 | allowSlowCount: true, 26 | // storage: getRxStorageDexie(), // INFO: can be ommited, will be provide by `storageType` string 27 | options: { 28 | plugins: [ 29 | // will be loaded by together with core plugins 30 | RxDBDevModePlugin, 31 | RxDBAttachmentsPlugin, 32 | RxDBLeaderElectionPlugin, 33 | ], 34 | storageType: localStorage['_ngx_rxdb_storage'] ?? 'dexie', 35 | dumpPath: 'assets/data/db.dump.json', 36 | }, 37 | }) 38 | ), 39 | ], 40 | }; 41 | -------------------------------------------------------------------------------- /examples/standalone/src/app/todos/todos.component.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { ChangeDetectionStrategy, Component, effect, inject } from '@angular/core'; 3 | import { Title } from '@angular/platform-browser'; 4 | import { RenderScheduler } from '@ngrx/component'; 5 | import { provideRxCollection } from '@ngx-odm/rxdb'; 6 | import { Todo, TODOS_COLLECTION_CONFIG, todosListAnimation } from '@shared'; 7 | import { TodoStore } from './todos.store'; 8 | 9 | @Component({ 10 | standalone: true, 11 | selector: 'demo-todos', 12 | templateUrl: './todos.component.html', 13 | styleUrls: ['./todos.component.css'], 14 | changeDetection: ChangeDetectionStrategy.OnPush, 15 | animations: [todosListAnimation], 16 | imports: [CommonModule], 17 | providers: [ 18 | provideRxCollection(TODOS_COLLECTION_CONFIG), // Collection will be created via this injection 19 | TodoStore, 20 | RenderScheduler, 21 | ], 22 | }) 23 | export class TodosComponent { 24 | private renderScheduler = inject(RenderScheduler); 25 | private titleService = inject(Title); 26 | readonly todoStore = inject(TodoStore); 27 | todos: Todo[] = []; // Copy todos from store inside effect to properly trigger zoneless change detection 28 | 29 | trackByFn = (index: number, item: Todo) => { 30 | return item.id + item.last_modified; 31 | }; 32 | 33 | constructor() { 34 | effect(() => { 35 | const { filtered, title } = this.todoStore; 36 | this.todos = filtered(); // Copy todos from store inside effect to properly trigger zoneless change detection 37 | const titleString = title(); 38 | this.titleService.setTitle(titleString); 39 | 40 | // INFO: Angular 17 doesn't provide way to detect changes with `signals` ONLY and no zone 41 | this.renderScheduler.schedule(); 42 | }); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tools/scripts/build-packages.ts: -------------------------------------------------------------------------------- 1 | import { join } from 'path'; 2 | import { getPackages, ArgvType } from './utils'; 3 | 4 | type Options = { 5 | specificPackage?: string; 6 | watch?: boolean; 7 | }; 8 | 9 | type NgPackagr = { 10 | forProject(ngPackagrProjectPath: string): NgPackagr; 11 | withOptions(options: { watch: boolean }): NgPackagr; 12 | withTsConfig(tsConfigPath: string): NgPackagr; 13 | build(): Promise; 14 | }; 15 | 16 | export function getOptionsFromProcessArgs(): Options { 17 | const options: string[] = process.argv.slice(2, process.argv.length) || []; 18 | const packageFlag: number = options.indexOf(ArgvType.PACKAGE); 19 | const specificPackage: string = packageFlag > -1 ? options[packageFlag + 1] : ''; 20 | const watch: boolean = options.includes(ArgvType.WATCH); 21 | return { specificPackage, watch }; 22 | } 23 | 24 | export async function buildPackages(options: Options, ngPackagr: () => NgPackagr) { 25 | const { specificPackage = null, watch = false } = options || {}; 26 | // get all packages 27 | let packages = getPackages(); 28 | 29 | // build a specific package that is passed via the command line 30 | // `yarn build:packages --package router-plugin` 31 | if (specificPackage) { 32 | console.log(`Specific: ${specificPackage}`); 33 | packages = packages.filter(p => p.name === specificPackage); 34 | } 35 | 36 | // run through all our packages and build and link them 37 | for (const pack of packages) { 38 | // build package 39 | try { 40 | await ngPackagr() 41 | .forProject(pack.ngPackagrProjectPath) 42 | .withOptions({ watch }) 43 | .withTsConfig(join(__dirname, '../tsconfig.build.json')) 44 | .build(); 45 | } catch (err) { 46 | console.error('ngPackagr build failed', err); 47 | throw err; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /packages/rxdb/collection/src/lib/helpers.spec.ts: -------------------------------------------------------------------------------- 1 | import { ReplaySubject, of } from 'rxjs'; 2 | import { ensureCollection, ensureCollection$ } from './helpers'; 3 | 4 | describe('ensureCollection', () => { 5 | let initialized: ReplaySubject; 6 | let testInstance: TestClass; 7 | 8 | class TestClass { 9 | get initialized$() { 10 | return initialized.asObservable(); 11 | } 12 | 13 | get config() { 14 | return { name: 'testCollection' }; 15 | } 16 | 17 | @ensureCollection() 18 | async asyncMethod() { 19 | return true; 20 | } 21 | 22 | @ensureCollection$() 23 | rxMethod() { 24 | return of(true); 25 | } 26 | } 27 | 28 | beforeEach(() => { 29 | initialized = new ReplaySubject(); 30 | testInstance = new TestClass(); 31 | }); 32 | 33 | it('should throw an error if the collection is not initialized', async () => { 34 | const errorMessage = `Collection "testCollection" was not initialized. Please check RxDB errors.`; 35 | initialized.complete(); 36 | await expect(testInstance.asyncMethod()).rejects.toThrowError(errorMessage); 37 | }); 38 | 39 | it('should call async method after the collection was initialized', async () => { 40 | const originalMethod = jest.spyOn(testInstance, 'asyncMethod'); 41 | initialized.next(true); 42 | initialized.complete(); 43 | 44 | const result = await testInstance.asyncMethod(); 45 | expect(originalMethod).toHaveBeenCalled(); 46 | expect(result).toBeTruthy(); 47 | }); 48 | 49 | it('should call rxjs method after the collection was initialized', done => { 50 | const originalMethod = jest.spyOn(testInstance, 'rxMethod'); 51 | initialized.next(true); 52 | initialized.complete(); 53 | 54 | testInstance.rxMethod().subscribe(result => { 55 | expect(originalMethod).toHaveBeenCalled(); 56 | expect(result).toBeTruthy(); 57 | done(); 58 | }); 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /packages/rxdb/src/lib/rxdb.providers.spec.ts: -------------------------------------------------------------------------------- 1 | import { Location } from '@angular/common'; 2 | import { SpyLocation } from '@angular/common/testing'; 3 | import { TestBed } from '@angular/core/testing'; 4 | import { Router } from '@angular/router'; 5 | import type { MangoQueryParams } from '@ngx-odm/rxdb/config'; 6 | import { Observable, take } from 'rxjs'; 7 | import { CURRENT_URL, updateQueryParams } from './rxdb.providers'; 8 | 9 | describe('query-params injection tokens', () => { 10 | describe('CURRENT_URL should emit stream', () => { 11 | let location: Location; 12 | let currentUrl$: Observable; 13 | 14 | beforeEach(() => { 15 | TestBed.configureTestingModule({ 16 | providers: [{ provide: Location, useClass: SpyLocation }], 17 | }); 18 | location = TestBed.inject(Location); 19 | currentUrl$ = TestBed.inject(CURRENT_URL); 20 | }); 21 | 22 | it('should emit current URL when it changes', async () => { 23 | const nextUrl = 'http://localhost:4200/todos?limit=1&skip=1'; 24 | location.go(nextUrl); 25 | 26 | const currentUrl = await currentUrl$.pipe(take(1)).toPromise(); 27 | expect(currentUrl).toMatch(nextUrl); 28 | }); 29 | }); 30 | 31 | describe('should update queryParams via router.navigate', () => { 32 | let router: Router; 33 | let spy: jest.SpyInstance; 34 | 35 | beforeEach(() => { 36 | TestBed.configureTestingModule({ 37 | providers: [Router], 38 | }); 39 | router = TestBed.inject(Router); 40 | spy = jest.spyOn(router, 'navigate'); 41 | }); 42 | 43 | it('should navigate with updated query parameters', async () => { 44 | const queryParams: MangoQueryParams = { 45 | skip: 1, 46 | }; 47 | const updateQueryParamsFn = TestBed.inject(updateQueryParams); 48 | await updateQueryParamsFn(queryParams); 49 | expect(spy).toHaveBeenCalledWith([], { 50 | queryParams, 51 | queryParamsHandling: 'merge', 52 | }); 53 | }); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "streamlit-rxdb-dataframe" 3 | version = "0.1.0" 4 | description = "Custom streamlit component connecting local browser indexedDB database as RxDB collection as dataframe" 5 | authors = ["voznik "] 6 | readme = "README.md" 7 | license = "MIT" 8 | homepage = "https://github.com/voznik/ngx-odm" 9 | repository = "https://github.com/voznik/ngx-odm" 10 | keywords = ["streamlit", "indexedDB", "RxDB", "browser", "connection", "dataframe"] 11 | packages = [{ include = "rxdb_dataframe" }] 12 | 13 | [tool.poetry.dependencies] 14 | python = "^3.10" 15 | pytest-playwright = "^0.4.4" 16 | streamlit = "^1.31.0" 17 | playwright = "^1.41.2" 18 | pandas = "^2.2.1" 19 | jsonschema = "^4.21.1" 20 | 21 | 22 | [build-system] 23 | requires = ["poetry-core"] 24 | build-backend = "poetry.core.masonry.api" 25 | 26 | [tool.poetry.group.dev.dependencies] 27 | pytest = "^7.1.3" 28 | black = "^23.1.0" 29 | isort = "^5.12.0" 30 | mypy = "^1.0.0" 31 | flake8 = "^7.0.0" 32 | flake8-annotations-complexity = "^0.0.8" 33 | 34 | [tool.isort] 35 | profile = "black" 36 | line_length = 100 37 | skip = ["./.venv", "./direnv", ".env"] 38 | 39 | [tool.black] 40 | exclude = ''' 41 | ( 42 | /( 43 | \.vscode 44 | | \.git 45 | | \.pytest_cache 46 | | \.mypy_cache 47 | | \.venv 48 | | \.env 49 | | \.direnv 50 | )/ 51 | ) 52 | ''' 53 | include = '\.pyi?$' 54 | line-length = 100 55 | 56 | [tool.flake8] 57 | max-line-length = 100 58 | ignore = ["E501"] 59 | 60 | [tool.mypy] 61 | files = ["**/*.py"] 62 | follow_imports = "silent" 63 | ignore_missing_imports = true 64 | scripts_are_modules = true 65 | python_version = "3.9" 66 | 67 | 68 | [tool.ruff] 69 | exclude = [ 70 | ".git", 71 | ".vscode", 72 | ".pytest_cache", 73 | ".mypy_cache", 74 | ".venv", 75 | ".env", 76 | ".direnv", 77 | "streamlit_patches.py", 78 | ] 79 | target-version = "py310" 80 | ignore = ["E501"] 81 | line-length = 100 82 | select = ["B", "E", "F", "W", "I"] 83 | 84 | [tool.ruff.per-file-ignores] 85 | -------------------------------------------------------------------------------- /packages/rxdb/sequence.puml: -------------------------------------------------------------------------------- 1 | @startuml NgxRxdbService Sequence 2 | 3 | 4 | !pragma teoz true 5 | 6 | participant Consumer 7 | participant NgxRxdbService 8 | box "Internal Service" 9 | participant NgxRxdbStore 10 | participant RxDB 11 | control createConnection 12 | collections socket 13 | end box 14 | 15 | == Initialization == 16 | Consumer -> NgxRxdbService : createHub(hubName, hubUrl) 17 | NgxRxdbService -> NgxRxdbStore: createHub 18 | activate NgxRxdbStore 19 | NgxRxdbStore -> NgxRxdbStore: _createHub 20 | create RxDB 21 | NgxRxdbStore --> RxDB: new 22 | NgxRxdbStore -> NgxRxdbService : instance of hub 23 | deactivate NgxRxdbStore 24 | NgxRxdbService -> NgxRxdbService: init() 25 | NgxRxdbService -> RxDB: start() 26 | activate RxDB 27 | RxDB --> RxDB: get connection 28 | create control createConnection 29 | activate createConnection 30 | RxDB -> createConnection **: new SignalR\nHubConnection 31 | alt testing 32 | createConnection -> RxDB: HubConnectionMock 33 | else SignalR HubConnection 34 | createConnection -> RxDB: HubConnection 35 | end 36 | deactivate createConnection 37 | RxDB -> RxDB: start() 38 | RxDB -> NgxRxdbService: Observable connection state 39 | deactivate RxDB 40 | == Hub Created == 41 | {start} Consumer -> NgxRxdbService : getStreamByServiceId$(streamingRequestParams, keepAlive?) 42 | ' alt connected 43 | NgxRxdbService -> RxDB: on(`OnMessageReceive`) 44 | activate RxDB 45 | RxDB --> RxDB: register handler as Subject 46 | create control socket 47 | activate socket 48 | NgxRxdbService -> RxDB: send(`SubscribeStreamAsync`) 49 | socket <- RxDB: invoke(`SubscribeStreamAsync`) 50 | socket -> RxDB: async socket messages 51 | RxDB -> NgxRxdbService: messages as Observable 52 | deactivate socket 53 | deactivate RxDB 54 | {end} NgxRxdbService -> Consumer: messages as Observable 55 | ' else 56 | ' end 57 | {start} <-> {end} : some time 58 | == Connection Stop == 59 | Consumer -> NgxRxdbService : connectionStop$ 60 | NgxRxdbService -> RxDB: stop$ 61 | RxDB -> RxDB: stop() 62 | alt hasConnections 63 | RxDB -> RxDB: purgeSubscriptions() 64 | end 65 | @enduml 66 | -------------------------------------------------------------------------------- /packages/rxdb/config/src/lib/config.spec.ts: -------------------------------------------------------------------------------- 1 | import { RxStorage } from 'rxdb'; 2 | import { getRxDatabaseCreator } from './config'; 3 | 4 | jest.mock('rxdb/plugins/storage-dexie', () => ({ 5 | getRxStorageDexie: jest.fn(() => { 6 | const storage = { 7 | createStorageInstance: jest.fn(), 8 | }; 9 | return storage; 10 | }), 11 | })); 12 | jest.mock('rxdb/plugins/storage-memory', () => ({ 13 | getRxStorageMemory: jest.fn(() => { 14 | const storage = { 15 | createStorageInstance: jest.fn(), 16 | }; 17 | return storage; 18 | }), 19 | })); 20 | 21 | describe('getRxDatabaseCreator', () => { 22 | it('should return a valid RxDatabaseCreator object with default storage type', () => { 23 | const config = { 24 | name: 'test-db', 25 | options: { 26 | storageType: 'unknown', 27 | storageOptions: {}, 28 | }, 29 | otherConfig: 'otherConfig', 30 | }; 31 | const result = getRxDatabaseCreator(config as any); 32 | expect(result.storage).toMatchObject>>({ 33 | createStorageInstance: expect.any(Function), 34 | }); 35 | }); 36 | 37 | it('should return a valid RxDatabaseCreator object with dexie storage type', () => { 38 | const config = { 39 | name: 'test-db', 40 | options: { 41 | storageType: 'dexie', 42 | storageOptions: {}, 43 | }, 44 | otherConfig: 'otherConfig', 45 | }; 46 | const result = getRxDatabaseCreator(config as any); 47 | expect(result.storage).toMatchObject>>({ 48 | createStorageInstance: expect.any(Function), 49 | }); 50 | }); 51 | 52 | it('should return a valid RxDatabaseCreator object with memory storage type', () => { 53 | const config = { 54 | name: 'test-db', 55 | options: { 56 | storageType: 'memory', 57 | storageOptions: {}, 58 | }, 59 | otherConfig: 'otherConfig', 60 | }; 61 | const result = getRxDatabaseCreator(config as any); 62 | expect(result.storage).toMatchObject>>({ 63 | createStorageInstance: expect.any(Function), 64 | }); 65 | }); 66 | }); 67 | -------------------------------------------------------------------------------- /examples/shared/todos.replication.ts: -------------------------------------------------------------------------------- 1 | import { replicateKintoDB } from '@ngx-odm/rxdb/replication-kinto'; 2 | import { getDefaultFetchWithHeaders } from '@ngx-odm/rxdb/utils'; 3 | import { b64EncodeUnicode } from 'rxdb'; 4 | import { RxReplicationState } from 'rxdb/plugins/replication'; 5 | import { replicateCouchDB } from 'rxdb/plugins/replication-couchdb'; 6 | import { environment } from './environment'; 7 | import { Todo } from './todos.model'; 8 | 9 | export const todosReplicationStateFactory = collection => { 10 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 11 | let replicationState: RxReplicationState | null = null; 12 | 13 | switch (localStorage['_ngx_rxdb_replication']) { 14 | case 'kinto': { 15 | replicationState = replicateKintoDB({ 16 | replicationIdentifier: 'demo-kinto-replication:todo', 17 | collection, 18 | kintoSyncOptions: { 19 | remote: environment.kintoServer, 20 | bucket: environment.bucket, 21 | collection: environment.collection, 22 | }, 23 | fetch: getDefaultFetchWithHeaders({ 24 | Authorization: 'Basic ' + b64EncodeUnicode('admin:adminadmin'), 25 | }), 26 | retryTime: 15000, 27 | live: true, 28 | autoStart: true, 29 | pull: { 30 | batchSize: 60, 31 | modifier: d => d, 32 | heartbeat: 60000, 33 | }, 34 | push: { 35 | modifier: d => d, 36 | }, 37 | }); 38 | break; 39 | } 40 | case 'couchdb': { 41 | replicationState = replicateCouchDB({ 42 | replicationIdentifier: 'demo-couchdb-replication', 43 | collection, 44 | fetch: getDefaultFetchWithHeaders({ 45 | Authorization: 'Basic ' + b64EncodeUnicode('admin:adminadmin'), 46 | }), 47 | url: 'http://localhost:5984/demo/', 48 | retryTime: 15000, 49 | live: true, 50 | pull: { 51 | batchSize: 60, 52 | modifier: d => d, 53 | heartbeat: 60000, 54 | }, 55 | push: { 56 | modifier: d => d, 57 | }, 58 | }); 59 | break; 60 | } 61 | default: { 62 | break; 63 | } 64 | } 65 | 66 | return replicationState; 67 | }; 68 | -------------------------------------------------------------------------------- /packages/rxdb/replication-kinto/src/replication-kinto.spec.ts: -------------------------------------------------------------------------------- 1 | import { getMockRxCollection } from '@ngx-odm/rxdb/testing'; 2 | import type { RxCollection } from 'rxdb'; 3 | import { RxReplicationState } from 'rxdb/plugins/replication'; 4 | import { replicateKintoDB } from './replication-kinto'; 5 | import { KintoCollectionSyncOptions } from './types'; 6 | 7 | describe('replication:kinto', () => { 8 | let collection: RxCollection; 9 | let kintoSyncOptions: KintoCollectionSyncOptions; 10 | const mockFetch = jest.fn(() => Promise.resolve({} as ReturnType)); 11 | const createFetchSpy = (data: any, ok = true) => 12 | mockFetch.mockResolvedValueOnce({ 13 | ok, 14 | json: jest.fn().mockResolvedValueOnce({ data }), 15 | headers: new Map([ 16 | ['Next-Page', ''], 17 | ['ETag', '"1698404710931"'], 18 | ]), 19 | } as any); 20 | 21 | beforeAll(async () => { 22 | collection = await getMockRxCollection(); 23 | kintoSyncOptions = { 24 | remote: 'https://kinto.dev.mozaws.net/v1', 25 | bucket: 'test', 26 | collection: 'test', 27 | }; 28 | }); 29 | 30 | beforeEach(() => { 31 | mockFetch.mockClear(); 32 | }); 33 | 34 | it('should create replicationState with default options', async () => { 35 | const replicationState = replicateKintoDB({ 36 | replicationIdentifier: 'test', 37 | collection, 38 | kintoSyncOptions, 39 | fetch: mockFetch, 40 | live: false, 41 | autoStart: false, 42 | }); 43 | expect(replicationState).toBeInstanceOf(RxReplicationState); 44 | expect(replicationState.start).toBeInstanceOf(Function); 45 | expect(replicationState.isStopped()).toBeFalsy(); 46 | }); 47 | 48 | it('should start pull replication', async () => { 49 | const replicationState = replicateKintoDB({ 50 | replicationIdentifier: 'test', 51 | kintoSyncOptions, 52 | collection, 53 | pull: { 54 | batchSize: 100, 55 | modifier: doc => doc, 56 | }, 57 | retryTime: 5000, 58 | live: false, 59 | autoStart: false, 60 | waitForLeadership: true, 61 | }); 62 | expect(replicationState).toBeDefined(); 63 | const spy = createFetchSpy([]); 64 | await replicationState.start(); 65 | const expectedUrl = 66 | 'https://kinto.dev.mozaws.net/v1/buckets/test/collections/test/records?_limit=100&_sort=-last_modified'; 67 | const [[url]] = spy.mock.calls as any[][]; 68 | expect(url).toEqual(expectedUrl); 69 | }); 70 | }); 71 | -------------------------------------------------------------------------------- /tools/scripts/utils.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires, @typescript-eslint/no-explicit-any */ 2 | import { exec, ExecOptions } from 'child_process'; 3 | import { resolve } from 'path'; 4 | 5 | export enum ArgvType { 6 | WATCH = '--watch', 7 | PACKAGE = '--package', 8 | } 9 | 10 | interface Package { 11 | name: string; 12 | packageName: string; 13 | buildPath: string; 14 | ngPackagrProjectPath: string; 15 | } 16 | 17 | export function getPackages(): Package[] { 18 | const rootDIr = resolve(__dirname, '../../'); 19 | const json = require('../../package.json'); 20 | const packages: string[] = json.packages; 21 | 22 | return packages.map(pack => { 23 | const path = pack.split('/'); 24 | const name = path[path.length - 1]; 25 | const packageName = `${json.packageScope}/${name}`; 26 | const buildPath = resolve(rootDIr, 'dist', 'packages', name); 27 | const ngPackagrProjectPath = resolve(rootDIr, 'packages', name, 'package.json'); 28 | return { 29 | name, 30 | packageName, 31 | buildPath, 32 | ngPackagrProjectPath, 33 | }; 34 | }); 35 | } 36 | 37 | export function execute(script: string, options: ExecOptions = {}): Promise { 38 | return new Promise((resolvePromise, rejectPromise) => { 39 | exec(script, options, (error, stdout, stderr) => { 40 | if (error) { 41 | rejectPromise({ error, stderr }); 42 | } else { 43 | resolvePromise(stdout); 44 | } 45 | }); 46 | }); 47 | } 48 | 49 | export async function publishAllPackagesToNpm(version: any, tag: string) { 50 | const packages = getPackages(); 51 | for (const pack of packages) { 52 | try { 53 | await execute('npm pack', { cwd: pack.buildPath }); 54 | await publishPackage(pack, version, tag); 55 | } catch (error) { 56 | // One retry 57 | await publishPackage(pack, version, tag); 58 | } 59 | } 60 | } 61 | async function publishPackage(pack: Package, version: any, tag: string) { 62 | const packageDescription = `${pack.buildPath} ${version} @${tag}`; 63 | try { 64 | // eslint-disable-next-line max-len 65 | const script = `npm publish --access public --non-interactive --no-git-tag-version --tag ${tag}`; 66 | const output = await execute(script, { cwd: pack.buildPath }); 67 | console.log(`Published ${packageDescription} /r/n -> ${output}`); 68 | } catch ({ error, stdErr }) { 69 | console.log(`Error Publishing ${packageDescription} /r/n -> ${error}`); 70 | throw error; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | ## I'm submitting a... 8 | 9 | 10 |

11 | [ ] Regression (a behavior that used to work and stopped working in a new release)
12 | [ ] Bug report  
13 | [ ] Performance issue
14 | [ ] Feature request
15 | [ ] Documentation issue or request
16 | [ ] Support request => https://github.com/voznik/ngx-odm/blob/master/CONTRIBUTING.md
17 | [ ] Other... Please describe:
18 | 
19 | 20 | ## Current behavior 21 | 22 | 23 | 24 | ## Expected behavior 25 | 26 | 27 | 28 | ## Minimal reproduction of the problem with instructions 29 | 30 | 39 | 40 | **Note:** Our policy is that issues reported without a reproduction will be closed immediately and then reopened once a reproduction has been provided. Please respect the developers of this project by doing this. We give of our personal time to work on this project and would rather be spending our time fixing or enhancing the library than chasing down badly described or unreproducable issues. 41 | Please delete this note once you have read it. 42 | 43 | ## What is the motivation / use case for changing the behavior? 44 | 45 | 46 | 47 | ## Environment 48 | 49 |

50 | Libs:
51 | - @angular/core version: X.Y.Z
52 | - @ngx-odm/rxdb version: X.Y.Z
53 | 
54 | 
55 | Browser:
56 | - [ ] Chrome (desktop) version XX
57 | - [ ] Chrome (Android) version XX
58 | - [ ] Chrome (iOS) version XX
59 | - [ ] Firefox version XX
60 | - [ ] Safari (desktop) version XX
61 | - [ ] Safari (iOS) version XX
62 | - [ ] IE version XX
63 | - [ ] Edge version XX
64 | 
65 | For Tooling issues:
66 | - Node version: XX  
67 | - Platform:  
68 | 
69 | Others:
70 | 
71 | 
72 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/rxdb_dataframe/test___init__.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import pytest 3 | 4 | from rxdb_dataframe import get_dataframe_by_schema 5 | 6 | 7 | def test_get_dataframe_by_schema(): 8 | # Test case 1: Empty schema 9 | schema = {} 10 | expected_df = pd.DataFrame() 11 | assert get_dataframe_by_schema(schema).equals(expected_df) 12 | 13 | # Test case 2: Schema with string properties 14 | schema = { 15 | "properties": { 16 | "name": {"type": "string"}, 17 | "age": {"type": "string"}, 18 | "city": {"type": "string"}, 19 | } 20 | } 21 | expected_df = pd.DataFrame( 22 | { 23 | "name": pd.Series(dtype="object"), 24 | "age": pd.Series(dtype="object"), 25 | "city": pd.Series(dtype="object"), 26 | } 27 | ) 28 | assert get_dataframe_by_schema(schema).equals(expected_df) 29 | 30 | # Test case 3: Schema with boolean properties 31 | schema = { 32 | "properties": {"is_active": {"type": "boolean"}, "has_permission": {"type": "boolean"}} 33 | } 34 | expected_df = pd.DataFrame( 35 | {"is_active": pd.Series(dtype="bool"), "has_permission": pd.Series(dtype="bool")} 36 | ) 37 | assert get_dataframe_by_schema(schema).equals(expected_df) 38 | 39 | 40 | def test_get_dataframe_by_schema(): 41 | # Test case 1: Empty schema 42 | schema = {} 43 | expected_df = pd.DataFrame() 44 | assert get_dataframe_by_schema(schema).equals(expected_df) 45 | 46 | # Test case 2: Schema with string properties 47 | schema = { 48 | "properties": { 49 | "name": {"type": "string"}, 50 | "age": {"type": "string"}, 51 | "city": {"type": "string"}, 52 | } 53 | } 54 | expected_df = pd.DataFrame( 55 | { 56 | "name": pd.Series(dtype="object"), 57 | "age": pd.Series(dtype="object"), 58 | "city": pd.Series(dtype="object"), 59 | } 60 | ) 61 | assert get_dataframe_by_schema(schema).equals(expected_df) 62 | 63 | # Test case 3: Schema with boolean properties 64 | schema = { 65 | "properties": {"is_active": {"type": "boolean"}, "has_permission": {"type": "boolean"}} 66 | } 67 | expected_df = pd.DataFrame( 68 | {"is_active": pd.Series(dtype="bool"), "has_permission": pd.Series(dtype="bool")} 69 | ) 70 | assert get_dataframe_by_schema(schema).equals(expected_df) 71 | 72 | 73 | if __name__ == "__main__": 74 | pytest.main([__file__]) 75 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": ".", 6 | "outDir": "./dist/out-tsc", 7 | "rootDir": ".", 8 | "sourceMap": true, 9 | "declaration": false, 10 | "allowSyntheticDefaultImports": true, 11 | "useUnknownInCatchVariables": false, 12 | "emitDecoratorMetadata": true, 13 | "esModuleInterop": true, 14 | "experimentalDecorators": true, 15 | "importHelpers": true, 16 | "lib": ["es2022", "dom"], 17 | "module": "ESNext", 18 | "moduleResolution": "Node", 19 | "resolveJsonModule": true, 20 | "skipDefaultLibCheck": true, 21 | "skipLibCheck": true, 22 | "ignoreDeprecations": "5.0", 23 | "suppressImplicitAnyIndexErrors": true, 24 | "target": "es2022", 25 | "typeRoots": ["node_modules/@types"], 26 | "types": ["node"], 27 | "paths": { 28 | "@ngx-odm/react": ["packages/react/src/index.ts"], 29 | "@ngx-odm/rxdb": ["dist/packages/rxdb", "packages/rxdb/src/index.ts"], 30 | "@ngx-odm/rxdb/collection": [ 31 | "dist/packages/rxdb/collection", 32 | "packages/rxdb/collection/src/index.ts" 33 | ], 34 | "@ngx-odm/rxdb/config": [ 35 | "dist/packages/rxdb/config", 36 | "packages/rxdb/config/src/index.ts" 37 | ], 38 | "@ngx-odm/rxdb/core": ["dist/packages/rxdb/core", "packages/rxdb/core/src/index.ts"], 39 | "@ngx-odm/rxdb/prepare": [ 40 | "dist/packages/rxdb/prepare", 41 | "packages/rxdb/prepare/src/index.ts" 42 | ], 43 | "@ngx-odm/rxdb/query-params": [ 44 | "dist/packages/rxdb/query-params", 45 | "packages/rxdb/query-params/src/index.ts" 46 | ], 47 | "@ngx-odm/rxdb/replication-kinto": [ 48 | "dist/packages/rxdb/replication-kinto", 49 | "packages/rxdb/replication-kinto/src/index.ts" 50 | ], 51 | "@ngx-odm/rxdb/signals": [ 52 | "dist/packages/rxdb/signals", 53 | "packages/rxdb/signals/src/index.ts" 54 | ], 55 | "@ngx-odm/rxdb/sreamlit": ["packages/streamlit-rxdb-dataframe-frontend/src/index.ts"], 56 | "@ngx-odm/rxdb/testing": [ 57 | "dist/packages/rxdb/testing", 58 | "packages/rxdb/testing/src/index.ts" 59 | ], 60 | "@ngx-odm/rxdb/utils": [ 61 | "dist/packages/rxdb/utils", 62 | "packages/rxdb/utils/src/index.ts" 63 | ], 64 | "@package": ["packages/rxdb/package.json"], 65 | "@shared": ["examples/shared/index.ts"] 66 | } 67 | }, 68 | "exclude": ["node_modules", "tmp"] 69 | } 70 | -------------------------------------------------------------------------------- /packages/rxdb/query-params/src/utils.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/ban-types, @typescript-eslint/no-explicit-any */ 2 | import { NgxRxdbUtils } from '@ngx-odm/rxdb/utils'; 3 | import { includeKeys } from 'filter-obj'; 4 | import queryString from 'query-string'; 5 | import type { MangoQuery, MangoQuerySelector, MangoQuerySortPart, RxSchema } from 'rxdb'; 6 | 7 | const { keys, isEmpty, isNullOrUndefined } = NgxRxdbUtils; 8 | 9 | /** 10 | * Ensure that all top level fields are included in the schema. 11 | * Ensure that sort only runs on known fields 12 | * @param schema 13 | */ 14 | export const normalizeMangoQuery = ( 15 | { selector, sort, limit, skip }: MangoQuery, 16 | schema: RxSchema 17 | ): MangoQuery => { 18 | const schemaTopLevelFields = keys(schema.jsonSchema.properties); 19 | if (!isEmpty(selector)) { 20 | selector = includeKeys(selector as Record, key => { 21 | return ( 22 | !key.startsWith('$') && // do not check operators 23 | !key.includes('.') && // skip this check on non-top-level 24 | schemaTopLevelFields.includes(key) // included in the schema 25 | ); 26 | }); 27 | } 28 | if (!isEmpty(sort)) { 29 | sort = sort?.filter(sortPart => schemaTopLevelFields.includes(keys(sortPart)[0])); 30 | } 31 | 32 | if (isNullOrUndefined(limit) || isNaN(limit as number)) { 33 | limit = undefined; 34 | } 35 | if (isNullOrUndefined(skip) || isNaN(skip as number)) { 36 | skip = undefined; 37 | } 38 | 39 | return { selector, sort, limit, skip }; 40 | }; 41 | 42 | export const parseUrlToMangoQuery = (url: string, schema: RxSchema): MangoQuery => { 43 | url = queryString.extract(url); 44 | const urlPart = queryString.pick(url, ['selector', 'sort', 'limit', 'skip']); 45 | const parsed: any = queryString.parse(urlPart, { 46 | parseNumbers: true, 47 | parseBooleans: true, 48 | }); 49 | const { selector: _selector, sort: _sort, limit, skip } = parsed; 50 | const selector = _selector ? JSON.parse(_selector as string) : undefined; 51 | const sort = _sort ? JSON.parse(_sort as string) : undefined; 52 | /** Ensure that all top level fields are included in the schema. */ 53 | const queryObj: MangoQuery = normalizeMangoQuery( 54 | { 55 | selector, 56 | sort, 57 | limit, 58 | skip, 59 | }, 60 | schema 61 | ); 62 | return queryObj; 63 | }; 64 | 65 | export const stringifyParam = ( 66 | param: MangoQuerySelector | MangoQuerySortPart[] | undefined 67 | ): string => { 68 | if (isNullOrUndefined(param)) return ''; 69 | return JSON.stringify(param); 70 | }; 71 | -------------------------------------------------------------------------------- /packages/rxdb/query-params/src/utils.spec.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/ban-ts-comment */ 2 | import { TEST_SCHEMA, TestDocType } from '@ngx-odm/rxdb/testing'; 3 | import { RxSchema, MangoQuery } from 'rxdb'; 4 | import { normalizeMangoQuery, parseUrlToMangoQuery } from './utils'; 5 | 6 | describe('query params utils', () => { 7 | const schema = new RxSchema(TEST_SCHEMA, () => Promise.resolve('')); 8 | 9 | describe('normalizeQuery', () => { 10 | it('should remove fields from selector that are not in the schema', () => { 11 | const query: MangoQuery = { 12 | selector: { 13 | completed: { 14 | $eq: true, 15 | }, 16 | // @ts-expect-error 17 | unknownField: 'value', 18 | }, 19 | sort: [], 20 | limit: 10, 21 | skip: 0, 22 | }; 23 | 24 | const result = normalizeMangoQuery(query, schema); 25 | 26 | expect(result.selector).toEqual({ 27 | completed: { 28 | $eq: true, 29 | }, 30 | }); 31 | }); 32 | 33 | it('should remove sort parts that are not in the schema', () => { 34 | const query: MangoQuery = { 35 | selector: {}, 36 | sort: [{ createdAt: 'asc' }, { unknownField: 'desc' }], 37 | limit: 10, 38 | skip: 0, 39 | }; 40 | 41 | const result = normalizeMangoQuery(query, schema); 42 | 43 | expect(result.sort).toEqual([{ createdAt: 'asc' }]); 44 | }); 45 | 46 | it('should set limit and skip to undefined if they are not valid numbers', () => { 47 | const query: MangoQuery = { 48 | selector: {}, 49 | sort: [], 50 | limit: 'invalid', 51 | skip: 'invalid', 52 | } as any; 53 | 54 | const result = normalizeMangoQuery(query, schema); 55 | 56 | expect(result.limit).toBeUndefined(); 57 | expect(result.skip).toBeUndefined(); 58 | }); 59 | 60 | // Add more test cases as needed 61 | }); 62 | 63 | describe('parseUrlToMangoQuery', () => { 64 | it('should parse the URL and return the corresponding MangoQuery', () => { 65 | const url = 66 | 'http://localhost:4200/todos?filter=ACTIVE&limit=1&selector=%7B%22completed%22:%7B%22$eq%22:true%7D%7D&sort=%5B%7B%22createdAt%22:%22desc%22%7D%5D'; 67 | 68 | const result = parseUrlToMangoQuery(url, schema); 69 | 70 | expect(result).toEqual({ 71 | selector: { 72 | completed: { 73 | $eq: true, 74 | }, 75 | }, 76 | sort: [{ createdAt: 'desc' }], 77 | limit: 1, 78 | skip: undefined, 79 | }); 80 | }); 81 | 82 | // Add more test cases as needed 83 | }); 84 | }); 85 | -------------------------------------------------------------------------------- /examples/standalone/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "standalone", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "projectType": "application", 5 | "prefix": "app", 6 | "sourceRoot": "examples/standalone/src", 7 | "tags": [], 8 | "targets": { 9 | "build": { 10 | "executor": "@angular-devkit/build-angular:application", 11 | "outputs": ["{options.outputPath}"], 12 | "options": { 13 | "outputPath": "dist/standalone", 14 | "index": "examples/standalone/src/index.html", 15 | "browser": "examples/standalone/src/main.ts", 16 | "polyfills": [], 17 | "tsConfig": "examples/standalone/tsconfig.app.json", 18 | "assets": ["examples/standalone/src/favicon.ico", "examples/standalone/src/assets"], 19 | "styles": [ 20 | "node_modules/todomvc-common/base.css", 21 | "node_modules/todomvc-app-css/index.css" 22 | ], 23 | "scripts": [] 24 | }, 25 | "configurations": { 26 | "production": { 27 | "budgets": [ 28 | { 29 | "type": "initial", 30 | "maximumWarning": "500kb", 31 | "maximumError": "1mb" 32 | }, 33 | { 34 | "type": "anyComponentStyle", 35 | "maximumWarning": "2kb", 36 | "maximumError": "4kb" 37 | } 38 | ], 39 | "outputHashing": "all", 40 | "extractLicenses": false 41 | }, 42 | "development": { 43 | "outputHashing": "none", 44 | "optimization": false, 45 | "extractLicenses": false, 46 | "sourceMap": true, 47 | "namedChunks": true 48 | } 49 | }, 50 | "defaultConfiguration": "production" 51 | }, 52 | "serve": { 53 | "executor": "@angular-devkit/build-angular:dev-server", 54 | "configurations": { 55 | "production": { 56 | "buildTarget": "standalone:build:production" 57 | }, 58 | "development": { 59 | "buildTarget": "standalone:build:development" 60 | } 61 | }, 62 | "defaultConfiguration": "development" 63 | }, 64 | "extract-i18n": { 65 | "executor": "@angular-devkit/build-angular:extract-i18n", 66 | "options": { 67 | "buildTarget": "standalone:build" 68 | } 69 | }, 70 | "lint": { 71 | "executor": "@nx/eslint:lint", 72 | "outputs": ["{options.outputFile}"] 73 | }, 74 | "test": { 75 | "executor": "@nx/jest:jest", 76 | "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], 77 | "options": { 78 | "jestConfig": "examples/standalone/jest.config.ts" 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /packages/rxdb/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rxdb", 3 | "$schema": "../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "packages/rxdb/src", 5 | "tags": [], 6 | "projectType": "library", 7 | "targets": { 8 | "build": { 9 | "executor": "@nx/angular:package", 10 | "outputs": ["{workspaceRoot}/dist/{projectRoot}"], 11 | "options": { 12 | "project": "packages/rxdb/ng-package.json" 13 | }, 14 | "configurations": { 15 | "production": { 16 | "tsConfig": "packages/rxdb/tsconfig.lib.prod.json" 17 | }, 18 | "development": { 19 | "tsConfig": "packages/rxdb/tsconfig.lib.json" 20 | } 21 | }, 22 | "defaultConfiguration": "production" 23 | }, 24 | "test": { 25 | "executor": "@nx/jest:jest", 26 | "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], 27 | "options": { 28 | "jestConfig": "packages/rxdb/jest.config.ts" 29 | } 30 | }, 31 | "lint": { 32 | "executor": "@nx/eslint:lint", 33 | "outputs": ["{options.outputFile}"] 34 | }, 35 | "version": { 36 | "executor": "@jscutlery/semver:version", 37 | "options": { 38 | "preset": "angular", 39 | "tagPrefix": "v", 40 | "noVerify": true, 41 | "baseBranch": "master", 42 | "push": true, 43 | "syncVersions": false, 44 | "commitMessageFormat": "release(ngx-odm/rxdb): new version ${version}", 45 | "skipCommitTypes": ["docs", "ci"], 46 | "postTargets": ["rxdb:github"], 47 | "types": [ 48 | { 49 | "type": "feat", 50 | "section": "Features" 51 | }, 52 | { 53 | "type": "fix", 54 | "section": "Bug Fixes" 55 | }, 56 | { 57 | "type": "chore", 58 | "hidden": false 59 | }, 60 | { 61 | "type": "docs", 62 | "hidden": false 63 | }, 64 | { 65 | "type": "style", 66 | "hidden": false 67 | }, 68 | { 69 | "type": "refactor", 70 | "section": "Features", 71 | "hidden": false 72 | }, 73 | { 74 | "type": "perf", 75 | "section": "Features", 76 | "hidden": false 77 | }, 78 | { 79 | "type": "test", 80 | "hidden": true 81 | }, 82 | { 83 | "type": "build", 84 | "hidden": true 85 | } 86 | ] 87 | } 88 | }, 89 | "github": { 90 | "executor": "@jscutlery/semver:github", 91 | "options": { 92 | "tag": "{tag}", 93 | "notes": "{notes}" 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/tests/test_rxdb_dataframe.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from rxdb_dataframe import get_column_config, get_dataframe_by_schema 3 | 4 | 5 | def test_get_column_config(): 6 | schema = { 7 | "properties": { 8 | "name": {"type": "string", "maxLength": 50}, 9 | "age": {"type": "integer", "min": 0, "max": 100}, 10 | "is_active": {"type": "boolean"}, 11 | "gender": {"type": "string", "enum": ["Male", "Female", "Other"]}, 12 | "birth_date": {"type": "string", "format": "date-time"}, 13 | }, 14 | "required": ["name", "age"], 15 | } 16 | 17 | column_config = get_column_config(schema) 18 | 19 | assert "name" in column_config 20 | assert column_config["name"]["type_config"]["type"] == "text" 21 | assert column_config["name"]["type_config"]["max_chars"] == 50 22 | 23 | assert "age" in column_config 24 | assert column_config["age"]["type_config"]["type"] == "number" 25 | assert column_config["age"]["type_config"]["min_value"] == 0 26 | assert column_config["age"]["type_config"]["max_value"] == 100 27 | 28 | assert "is_active" in column_config 29 | assert column_config["is_active"]["type_config"]["type"] == "checkbox" 30 | 31 | assert "gender" in column_config 32 | assert column_config["gender"]["type_config"]["type"] == "selectbox" 33 | assert column_config["gender"]["type_config"]["options"] == ["Male", "Female", "Other"] 34 | 35 | assert "birth_date" in column_config 36 | assert column_config["birth_date"]["type_config"]["type"] == "datetime" 37 | assert column_config["birth_date"]["type_config"]["format"] == "YYYY-MM-DD HH:mm" 38 | 39 | 40 | def test_get_dataframe_by_schema(): 41 | # Test case 1: Empty schema 42 | schema = {} 43 | expected_df = pd.DataFrame() 44 | assert get_dataframe_by_schema(schema).equals(expected_df) 45 | 46 | # Test case 2: Schema with string properties 47 | schema = { 48 | "properties": { 49 | "name": {"type": "string"}, 50 | "age": {"type": "string"}, 51 | "city": {"type": "string"}, 52 | } 53 | } 54 | expected_df = pd.DataFrame( 55 | { 56 | "name": pd.Series(dtype="object"), 57 | "age": pd.Series(dtype="object"), 58 | "city": pd.Series(dtype="object"), 59 | } 60 | ) 61 | assert get_dataframe_by_schema(schema).equals(expected_df) 62 | 63 | # Test case 3: Schema with boolean properties 64 | schema = { 65 | "properties": {"is_active": {"type": "boolean"}, "has_permission": {"type": "boolean"}} 66 | } 67 | expected_df = pd.DataFrame( 68 | {"is_active": pd.Series(dtype="bool"), "has_permission": pd.Series(dtype="bool")} 69 | ) 70 | assert get_dataframe_by_schema(schema).equals(expected_df) 71 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/rxdb_dataframe/frontend/src/lib/useEditingState.ts: -------------------------------------------------------------------------------- 1 | import { RxDBCollectionService } from '@ngx-odm/rxdb/collection'; 2 | import { NgxRxdbUtils, type Entity } from '@ngx-odm/rxdb/utils'; 3 | import equal from 'fast-deep-equal'; 4 | import { useEffect, useRef, useState } from 'react'; 5 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 6 | // @ts-expect-error 7 | import { v4 as uuid } from 'uuid'; 8 | import { DataframeEditingState } from './RxDBDataframeArgs'; 9 | 10 | const { logger, isEmpty } = NgxRxdbUtils; 11 | 12 | /** 13 | * Custom hook that manages the editing state of a Dataframe. 14 | * @param editingState - The editing state of the Dataframe. 15 | * @param collectionService - The service used to interact with the RxDB collection. 16 | * @returns A tuple containing the entities and a function to set the entities. 17 | */ 18 | export const useEditedState = ( 19 | editingState: DataframeEditingState, 20 | collectionService: RxDBCollectionService 21 | ): [Entity[] | undefined, React.Dispatch>] => { 22 | const [entities, setEntities] = useState(); 23 | const editingStateRef = useRef(editingState); 24 | 25 | useEffect(() => { 26 | if ( 27 | !entities || 28 | isEmpty(editingState) || 29 | equal(editingState, editingStateRef.current) 30 | ) { 31 | return; 32 | } 33 | editingStateRef.current = editingState; 34 | 35 | const { added_rows: added, edited_rows: edited, deleted_rows: deleted } = editingState; 36 | 37 | if (!isEmpty(added)) { 38 | const docs = added.map(item => ({ 39 | ...item, 40 | id: uuid(), 41 | createdAt: new Date().toISOString(), 42 | last_modified: Date.now(), 43 | })); 44 | if (!docs.length) return; 45 | collectionService.upsertBulk(docs).catch(error => logger.log('upsertBulk', error)); 46 | } 47 | 48 | if (!isEmpty(deleted)) { 49 | const ids: string[] = []; 50 | deleted.forEach(rowIndex => { 51 | const entity = entities.at(rowIndex); 52 | if (entity) { 53 | ids.push(entity.id); 54 | } 55 | }); 56 | if (!ids.length) return; 57 | collectionService.removeBulk(ids).catch(error => logger.log('removeBulk', error)); 58 | } 59 | 60 | if (!isEmpty(edited)) { 61 | const docs = Object.entries(edited).map(([rowIndex, change]) => { 62 | const entity = entities.at(+rowIndex); 63 | return { 64 | ...entity, 65 | ...change, 66 | last_modified: Date.now(), 67 | }; 68 | }); 69 | if (!docs.length) return; 70 | collectionService.upsertBulk(docs).catch(error => logger.log('upsertBulk', error)); 71 | } 72 | }, [editingState, entities, collectionService]); 73 | 74 | return [entities, setEntities]; 75 | }; 76 | -------------------------------------------------------------------------------- /decorate-angular-cli.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file decorates the Angular CLI with the Nx CLI to enable features such as computation caching 3 | * and faster execution of tasks. 4 | * 5 | * It does this by: 6 | * 7 | * - Patching the Angular CLI to warn you in case you accidentally use the undecorated ng command. 8 | * - Symlinking the ng to nx command, so all commands run through the Nx CLI 9 | * - Updating the package.json postinstall script to give you control over this script 10 | * 11 | * The Nx CLI decorates the Angular CLI, so the Nx CLI is fully compatible with it. 12 | * Every command you run should work the same when using the Nx CLI, except faster. 13 | * 14 | * Because of symlinking you can still type `ng build/test/lint` in the terminal. The ng command, in this case, 15 | * will point to nx, which will perform optimizations before invoking ng. So the Angular CLI is always invoked. 16 | * The Nx CLI simply does some optimizations before invoking the Angular CLI. 17 | * 18 | * To opt out of this patch: 19 | * - Replace occurrences of nx with ng in your package.json 20 | * - Remove the script from your postinstall script in your package.json 21 | * - Delete and reinstall your node_modules 22 | */ 23 | 24 | const fs = require('fs'); 25 | const os = require('os'); 26 | const cp = require('child_process'); 27 | const isWindows = os.platform() === 'win32'; 28 | let output; 29 | try { 30 | output = require('@nrwl/workspace').output; 31 | } catch (e) { 32 | console.warn( 33 | 'Angular CLI could not be decorated to enable computation caching. Please ensure @nrwl/workspace is installed.' 34 | ); 35 | process.exit(0); 36 | } 37 | 38 | /** 39 | * Symlink of ng to nx, so you can keep using `ng build/test/lint` and still 40 | * invoke the Nx CLI and get the benefits of computation caching. 41 | */ 42 | function symlinkNgCLItoNxCLI() { 43 | try { 44 | const ngPath = './node_modules/.bin/ng'; 45 | const nxPath = './node_modules/.bin/nx'; 46 | if (isWindows) { 47 | /** 48 | * This is the most reliable way to create symlink-like behavior on Windows. 49 | * Such that it works in all shells and works with npx. 50 | */ 51 | ['', '.cmd', '.ps1'].forEach(ext => { 52 | if (fs.existsSync(nxPath + ext)) 53 | fs.writeFileSync(ngPath + ext, fs.readFileSync(nxPath + ext)); 54 | }); 55 | } else { 56 | // If unix-based, symlink 57 | cp.execSync(`ln -sf ./nx ${ngPath}`); 58 | } 59 | } catch (e) { 60 | output.error({ 61 | title: 'Unable to create a symlink from the Angular CLI to the Nx CLI:' + e.message, 62 | }); 63 | throw e; 64 | } 65 | } 66 | 67 | try { 68 | symlinkNgCLItoNxCLI(); 69 | require('@nrwl/cli/lib/decorate-cli').decorateCli(); 70 | output.log({ 71 | title: 'Angular CLI has been decorated to enable computation caching.', 72 | }); 73 | } catch (e) { 74 | output.error({ 75 | title: 'Decoration of the Angular CLI did not complete successfully', 76 | }); 77 | } 78 | -------------------------------------------------------------------------------- /packages/rxdb/core/src/lib/service.ts: -------------------------------------------------------------------------------- 1 | import { 2 | RxCollectionExtended as RxCollection, 3 | RxCollectionCreatorExtended, 4 | } from '@ngx-odm/rxdb/config'; 5 | import { prepareCollections } from '@ngx-odm/rxdb/prepare'; 6 | import { NgxRxdbUtils } from '@ngx-odm/rxdb/utils'; 7 | import { 8 | CollectionsOfDatabase, 9 | RxDatabase, 10 | RxDatabaseCreator, 11 | createRxDatabase, 12 | } from 'rxdb'; 13 | import { loadRxDBPlugins } from './plugin.loader'; 14 | 15 | const { logger } = NgxRxdbUtils; 16 | 17 | /** 18 | * Service for managing a RxDB database instance. 19 | */ 20 | export class RxDBService { 21 | private dbInstance!: RxDatabase; 22 | private options!: RxDatabaseCreator; 23 | 24 | get db(): RxDatabase { 25 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 26 | return this.dbInstance!; 27 | } 28 | 29 | get dbOptions(): RxDatabaseCreator { 30 | return this.options; 31 | } 32 | 33 | get collections(): { [name: string]: RxCollection } { 34 | return this.db.collections as { [name: string]: RxCollection }; 35 | } 36 | 37 | async destroyDb() { 38 | try { 39 | await this.db.remove(); 40 | await this.db.destroy(); 41 | (this.dbInstance as unknown) = null; 42 | logger.log(`database destroy`); 43 | } catch { 44 | logger.log(`database destroy error`); 45 | } 46 | } 47 | 48 | /** 49 | * Runs via APP_INITIALIZER in app.module.ts 50 | * to ensure the database exists before the angular-app starts up 51 | * @param config 52 | */ 53 | async initDb(config: RxDatabaseCreator): Promise { 54 | if (this.dbInstance) { 55 | return; 56 | } 57 | try { 58 | await loadRxDBPlugins(config.options?.plugins); 59 | this.dbInstance = await createRxDatabase(config); 60 | this.options = config; 61 | logger.log( 62 | `created database "${this.db.name}" with config "${JSON.stringify(config)}"` 63 | ); 64 | 65 | // optional: can create collections from root config 66 | if (config?.options?.schemas) { 67 | const bulk = await this.initCollections(config.options.schemas); 68 | logger.log( 69 | `created ${Object.keys(bulk).length} collections bulk: ${Object.keys(bulk)}` 70 | ); 71 | } 72 | } catch (error) { 73 | logger.log('Error initializing the database:', error); 74 | throw error; 75 | } 76 | } 77 | 78 | /** 79 | * uses bulk `addCollections` method at the end of array 80 | * @param colConfigs 81 | */ 82 | async initCollections(colConfigs: { 83 | [name: string]: RxCollectionCreatorExtended; 84 | }): Promise { 85 | // eslint-disable-next-line no-useless-catch 86 | try { 87 | const colCreators = await prepareCollections(colConfigs); 88 | return await this.db.addCollections(colCreators); 89 | } catch (error) { 90 | logger.log('Error initializing collection(s)', error); 91 | throw error; 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /packages/rxdb/prepare/src/lib/prepare.plugin.spec.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/ban-ts-comment, @typescript-eslint/no-non-null-assertion */ 2 | import { getMockRxCollection } from '@ngx-odm/rxdb/testing'; 3 | import { RxCollection, RxCollectionCreator, RxQuery } from 'rxdb'; 4 | import { RxDBPreparePlugin } from './prepare.plugin'; 5 | 6 | describe('RxDBPreparePlugin', () => { 7 | describe('test hook "createRxCollection:after"', () => { 8 | let collection: RxCollection; 9 | let creator: RxCollectionCreator; 10 | let collectionCount: RxQuery; 11 | let createRxCollectionAfter: any; // RxPluginHooks['after'] 12 | 13 | beforeEach(async () => { 14 | collection = await getMockRxCollection(); 15 | collectionCount = collection.count(); 16 | creator = { options: {} } as RxCollectionCreator; 17 | createRxCollectionAfter = RxDBPreparePlugin.hooks!.createRxCollection!.after!; 18 | }); 19 | 20 | it('should not import initial docs if collection is not empty', async () => { 21 | jest.spyOn(collectionCount, 'exec').mockResolvedValue(1); 22 | await createRxCollectionAfter({ collection, creator }); 23 | expect(collection.importJSON).not.toHaveBeenCalled(); 24 | }); 25 | 26 | it('should not import initial docs if initialDocs is empty', async () => { 27 | creator.options.initialDocs = []; 28 | await createRxCollectionAfter({ collection, creator }); 29 | expect(collection.importJSON).not.toHaveBeenCalled(); 30 | }); 31 | 32 | it('should not import initial docs if collection has already been imported', async () => { 33 | jest.spyOn(collection as any, 'getMetadata').mockResolvedValueOnce({ 34 | isNewDb: false, 35 | }); 36 | await createRxCollectionAfter({ collection, creator }); 37 | expect(collection.importJSON).not.toHaveBeenCalled(); 38 | }); 39 | 40 | it('should import initial docs if collection is empty and initialDocs is not empty', async () => { 41 | creator.options.recreate = true; 42 | creator.options.initialDocs = [{ foo: 'bar' }]; 43 | await createRxCollectionAfter({ collection, creator }); 44 | expect(collection.importJSON).toHaveBeenCalledWith({ 45 | name: collection.name, 46 | schemaHash: expect.any(String), 47 | docs: creator.options.initialDocs, 48 | }); 49 | }); 50 | 51 | it('should not throw if count fails', async () => { 52 | const error = new Error('count failed'); 53 | jest.spyOn(collectionCount, 'exec').mockRejectedValue(error); 54 | expect( 55 | async () => await createRxCollectionAfter({ collection, creator }) 56 | ).not.toThrow(); 57 | }); 58 | 59 | it('should not throw if importJSON fails', async () => { 60 | const error = new Error('importJSON failed'); 61 | jest.spyOn(collection, 'importJSON').mockRejectedValue(error); 62 | expect( 63 | async () => await createRxCollectionAfter({ collection, creator }) 64 | ).not.toThrow(); 65 | }); 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /examples/demo/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE11 requires the following for NgClass support on SVG elements */ 22 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 23 | 24 | /** 25 | * Web Animations `@angular/platform-browser/animations` 26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 28 | */ 29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 30 | 31 | /** 32 | * By default, zone.js will patch all possible macroTask and DomEvents 33 | * user can disable parts of macroTask/DomEvents patch by setting following flags 34 | * because those flags need to be set before `zone.js` being loaded, and webpack 35 | * will put import in the top of bundle, so user need to create a separate file 36 | * in this directory (for example: zone-flags.ts), and put the following flags 37 | * into that file, and then add the following code before importing zone.js. 38 | * import './zone-flags'; 39 | * 40 | * The flags allowed in zone-flags.ts are listed here. 41 | * 42 | * The following flags will work for all browsers. 43 | * 44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 46 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 47 | * 48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 50 | * 51 | * (window as any).__Zone_enable_cross_context_check = true; 52 | * 53 | */ 54 | 55 | /*************************************************************************************************** 56 | * Zone JS is required by default for Angular itself. 57 | */ 58 | import 'zone.js'; // Included with Angular CLI. 59 | 60 | /*************************************************************************************************** 61 | * APPLICATION IMPORTS 62 | */ 63 | -------------------------------------------------------------------------------- /packages/rxdb/collection/src/lib/helpers.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | import type { RxCollectionCreatorExtended } from '@ngx-odm/rxdb/config'; 3 | import { NgxRxdbUtils } from '@ngx-odm/rxdb/utils'; 4 | import { Observable, OperatorFunction, defer, lastValueFrom, switchMap } from 'rxjs'; 5 | 6 | const { debug, isEmptyObject, isFunction } = NgxRxdbUtils; 7 | 8 | type CollectionLike = { 9 | readonly initialized$: Observable; 10 | readonly config: RxCollectionCreatorExtended; 11 | }; 12 | 13 | export type ZoneLike = { 14 | run(fn: (...args: any[]) => T, applyThis?: any, applyArgs?: any[]): T; 15 | }; 16 | 17 | function isZone(obj: any): obj is ZoneLike { 18 | return !isEmptyObject(obj) && isFunction(obj.run); 19 | } 20 | 21 | /* eslint-disable prettier/prettier */ 22 | /** 23 | * Moves observable execution in and out of Angular zone. 24 | * @param zone 25 | */ 26 | export function runInZone(zone: ZoneLike): OperatorFunction { // NOSONAR 27 | if (!isZone(zone)) return source => source; 28 | 29 | return source => { // NOSONAR 30 | return new Observable(subscriber => { // NOSONAR 31 | return source.subscribe( 32 | (value: T) => zone.run(() => subscriber.next(value)), 33 | (e: any) => zone.run(() => subscriber.error(e)), 34 | () => zone.run(() => subscriber.complete()) // NOSONAR 35 | ); 36 | }); 37 | }; 38 | } 39 | /* eslint-enable prettier/prettier */ 40 | 41 | /** 42 | * Collection method decorator for Observable return type 43 | * 44 | * Ensure the collection is created before the method is called by piping riginal method 45 | * through class init$ observable property which emits when collection is created 46 | */ 47 | export function ensureCollection$() { 48 | return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { 49 | const originalMethod = descriptor.value; 50 | descriptor.value = function (this: CollectionLike, ...args: any[]) { 51 | return defer(() => { 52 | return this.initialized$.pipe( 53 | switchMap(() => originalMethod.apply(this, args)), // NOSONAR 54 | debug(`collection.${propertyKey}`) 55 | ); 56 | }); 57 | }; 58 | return descriptor; 59 | }; 60 | } 61 | 62 | /** 63 | * Collection method decorator for Promise return type 64 | * 65 | * Ensure the collection is created before the method is called by piping riginal method 66 | * through class init$ observable property which emits when collection is created 67 | */ 68 | export function ensureCollection() { 69 | return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { 70 | const originalMethod = descriptor.value; 71 | descriptor.value = async function (this: CollectionLike, ...args: any[]) { 72 | await lastValueFrom(this.initialized$).catch(() => { 73 | // eslint-disable-next-line prettier/prettier 74 | throw new Error(`Collection "${this.config.name}" was not initialized. Please check RxDB errors.`); 75 | }); 76 | 77 | return originalMethod.apply(this, args); 78 | }; 79 | return descriptor; 80 | }; 81 | } 82 | -------------------------------------------------------------------------------- /nx.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/nx/schemas/nx-schema.json", 3 | "workspaceLayout": { 4 | "appsDir": "examples", 5 | "libsDir": "packages", 6 | "projectNameAndRootFormat": "as-provided" 7 | }, 8 | "affected": { 9 | "defaultBase": "origin/master" 10 | }, 11 | "release": { 12 | "projects": ["packages/*"], 13 | "projectChangelogs": { 14 | "createRelease": "github" 15 | }, 16 | "version": { 17 | "generatorOptions": { 18 | "preid": "dev" 19 | } 20 | } 21 | }, 22 | "targetDefaults": { 23 | "build": { 24 | "dependsOn": ["^build"], 25 | "inputs": ["production", "^production"], 26 | "cache": true 27 | }, 28 | "lint": { 29 | "inputs": [ 30 | "default", 31 | "{workspaceRoot}/.eslintrc.json", 32 | "{workspaceRoot}/.eslintignore", 33 | "{workspaceRoot}/eslint.config.js" 34 | ], 35 | "cache": true 36 | }, 37 | "@nx/jest:jest": { 38 | "inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"], 39 | "cache": true, 40 | "options": { 41 | "passWithNoTests": true 42 | }, 43 | "configurations": { 44 | "ci": { 45 | "ci": true, 46 | "codeCoverage": true 47 | } 48 | } 49 | } 50 | }, 51 | "namedInputs": { 52 | "default": ["{projectRoot}/**/*", "sharedGlobals"], 53 | "production": [ 54 | "default", 55 | "!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)", 56 | "!{projectRoot}/tsconfig.spec.json", 57 | "!{projectRoot}/jest.config.[jt]s", 58 | "!{projectRoot}/src/test-setup.[jt]s", 59 | "!{projectRoot}/test-setup.[jt]s", 60 | "!{projectRoot}/.eslintrc.json", 61 | "!{projectRoot}/eslint.config.js" 62 | ], 63 | "sharedGlobals": [] 64 | }, 65 | "generators": { 66 | "@nx/angular:application": { 67 | "style": "css", 68 | "linter": "eslint", 69 | "unitTestRunner": "jest", 70 | "e2eTestRunner": "none" 71 | }, 72 | "@nx/angular:library": { 73 | "linter": "eslint", 74 | "unitTestRunner": "jest" 75 | }, 76 | "@nx/angular:component": { 77 | "style": "css" 78 | }, 79 | "@nx/react": { 80 | "library": { 81 | "style": "css", 82 | "linter": "eslint", 83 | "unitTestRunner": "jest" 84 | }, 85 | "application": { 86 | "babel": true, 87 | "style": "css", 88 | "linter": "eslint", 89 | "bundler": "vite" 90 | }, 91 | "component": { 92 | "style": "css" 93 | } 94 | } 95 | }, 96 | "plugins": [ 97 | { 98 | "plugin": "@nx/eslint/plugin", 99 | "options": { 100 | "targetName": "lint" 101 | } 102 | }, 103 | { 104 | "plugin": "@nx/vite/plugin", 105 | "options": { 106 | "buildTargetName": "build", 107 | "previewTargetName": "preview", 108 | "testTargetName": "test", 109 | "serveTargetName": "serve", 110 | "serveStaticTargetName": "serve-static" 111 | } 112 | } 113 | ] 114 | } 115 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | - Using welcoming and inclusive language 12 | - Being respectful of differing viewpoints and experiences 13 | - Gracefully accepting constructive criticism 14 | - Focusing on what is best for the community 15 | - Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | - The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | - Trolling, insulting/derogatory comments, and personal or political attacks 21 | - Public or private harassment 22 | - Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | - Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at worrydontcom@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /packages/rxdb/query-params/src/query-params.plugin.spec.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-unused-vars */ 2 | /* @typescript-eslint/no-non-null-assertion */ 3 | import { RxCollectionExtended as RxCollection } from '@ngx-odm/rxdb/config'; 4 | import { 5 | TEST_FEATURE_CONFIG_1, 6 | TestDocType, 7 | getMockRxCollection, 8 | } from '@ngx-odm/rxdb/testing'; 9 | import type { MangoQuery, RxCollectionCreator, RxPlugin, RxQuery } from 'rxdb'; 10 | import { Observable, Subject, take } from 'rxjs'; 11 | import { RxDBPUseQueryParamsPlugin } from './query-params.plugin'; 12 | 13 | describe('RxDBPUseQueryParamsPlugin', () => { 14 | describe('test proto extension', () => { 15 | let collection: RxCollection; 16 | let creator: RxCollectionCreator; 17 | let plugin: RxPlugin; 18 | const mockUrlStream$ = new Subject(); 19 | 20 | beforeEach(async () => { 21 | const colConfig = TEST_FEATURE_CONFIG_1; 22 | colConfig.options.useQueryParams = true; 23 | plugin = RxDBPUseQueryParamsPlugin; 24 | collection = (await getMockRxCollection(colConfig)) as RxCollection; 25 | }); 26 | 27 | it('should add properties & methods for query-params', async () => { 28 | expect(collection.queryParamsInit).toBeDefined(); 29 | expect(collection.queryParams!.$).toBeInstanceOf(Observable); 30 | expect(collection.queryParams!.set).toBeDefined(); 31 | expect(collection.queryParams!.patch).toBeDefined(); 32 | }); 33 | 34 | it('should properly intialize usage of query-params', async () => { 35 | const startUrl = 36 | 'http://localhost:4200/todos?limit=1&selector=%7B%22completed%22:%7B%22$eq%22:true%7D%7D&sort=%5B%7B%22createdAt%22:%22desc%22%7D%5D'; 37 | collection.queryParamsInit!(mockUrlStream$, jest.fn()); 38 | mockUrlStream$.next(startUrl); 39 | const expectedQueryParams = { 40 | selector: { 41 | completed: { 42 | $eq: true, 43 | }, 44 | }, 45 | sort: [{ createdAt: 'desc' }], 46 | limit: 1, 47 | skip: undefined, 48 | }; 49 | const queryParamsValue = await collection.queryParams!.$.pipe(take(1)).toPromise(); 50 | expect(queryParamsValue).toEqual(expectedQueryParams); 51 | }); 52 | it('should properly set query-params', async () => { 53 | const nextUrl = 54 | 'http://localhost:4200/todos?limit=2&sort=%5B%7B%22createdAt%22:%22asc%22%7D%5D&skip=0'; 55 | 56 | collection.queryParamsInit!(mockUrlStream$, jest.fn()); 57 | const newQueryParams: MangoQuery = { 58 | selector: undefined, 59 | sort: [{ createdAt: 'asc' }], 60 | limit: 2, 61 | skip: 0, 62 | }; 63 | collection.queryParams!.set(newQueryParams); 64 | mockUrlStream$.next(nextUrl); 65 | const queryParamsValue = await collection.queryParams!.$.pipe(take(1)).toPromise(); 66 | expect(queryParamsValue).toEqual(newQueryParams); 67 | }); 68 | it('should properly patch query-params', async () => { 69 | const startUrl = 'http://localhost:4200/todos?limit=0'; 70 | const nextUrl = 'http://localhost:4200/todos?limit=1&skip=1'; 71 | mockUrlStream$.next(startUrl); 72 | collection.queryParamsInit!(mockUrlStream$, jest.fn()); 73 | const newQueryParams: MangoQuery = { 74 | limit: 1, 75 | skip: 1, 76 | }; 77 | collection.queryParams!.patch(newQueryParams); 78 | mockUrlStream$.next(nextUrl); 79 | const queryParamsValue = await collection.queryParams!.$.pipe(take(1)).toPromise(); 80 | expect(queryParamsValue).toMatchObject(newQueryParams); 81 | }); 82 | }); 83 | }); 84 | -------------------------------------------------------------------------------- /examples/demo/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "projectType": "application", 5 | "prefix": "demo", 6 | "sourceRoot": "examples/demo/src", 7 | "tags": [], 8 | "targets": { 9 | "build": { 10 | "executor": "@angular-devkit/build-angular:browser", 11 | "outputs": ["{options.outputPath}"], 12 | "options": { 13 | "outputPath": "dist/demo", 14 | "index": "examples/demo/src/index.html", 15 | "main": "examples/demo/src/main.ts", 16 | "polyfills": ["zone.js"], 17 | "tsConfig": "examples/demo/tsconfig.app.json", 18 | "assets": ["examples/demo/src/favicon.ico", "examples/demo/src/assets"], 19 | "styles": [ 20 | "node_modules/todomvc-common/base.css", 21 | "node_modules/todomvc-app-css/index.css" 22 | ], 23 | "scripts": [] 24 | }, 25 | "configurations": { 26 | "production": { 27 | "fileReplacements": [ 28 | { 29 | "replace": "examples/shared/environment.ts", 30 | "with": "examples/shared/environment.prod.ts" 31 | } 32 | ], 33 | "budgets": [ 34 | { 35 | "type": "initial", 36 | "maximumWarning": "500kb", 37 | "maximumError": "1mb" 38 | }, 39 | { 40 | "type": "anyComponentStyle", 41 | "maximumWarning": "2kb", 42 | "maximumError": "4kb" 43 | } 44 | ], 45 | "outputHashing": "all", 46 | "vendorChunk": true 47 | }, 48 | "development": { 49 | "buildOptimizer": false, 50 | "optimization": false, 51 | "vendorChunk": true, 52 | "extractLicenses": false, 53 | "sourceMap": true, 54 | "namedChunks": true 55 | } 56 | }, 57 | "defaultConfiguration": "production" 58 | }, 59 | "serve": { 60 | "executor": "@angular-devkit/build-angular:dev-server", 61 | "configurations": { 62 | "production": { 63 | "buildTarget": "demo:build:production" 64 | }, 65 | "development": { 66 | "buildTarget": "demo:build:development", 67 | "proxyConfig": "examples/demo/proxy.conf.js", 68 | "verbose": true 69 | } 70 | }, 71 | "defaultConfiguration": "development" 72 | }, 73 | "extract-i18n": { 74 | "executor": "@angular-devkit/build-angular:extract-i18n", 75 | "options": { 76 | "buildTarget": "demo:build" 77 | } 78 | }, 79 | "lint": { 80 | "executor": "@nx/eslint:lint", 81 | "outputs": ["{options.outputFile}"] 82 | }, 83 | "test": { 84 | "executor": "@nx/jest:jest", 85 | "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], 86 | "options": { 87 | "jestConfig": "examples/demo/jest.config.ts", 88 | "passWithNoTests": true 89 | }, 90 | "configurations": { 91 | "ci": { 92 | "ci": true, 93 | "codeCoverage": true 94 | } 95 | } 96 | }, 97 | "file-server": { 98 | "executor": "@nrwl/web:file-server", 99 | "options": { 100 | "buildTarget": "demo:build:production", 101 | "port": 4201, 102 | "host": "0.0.0.0", 103 | "proxyUrl": "http://localhost:4201?", 104 | "watch": true 105 | } 106 | }, 107 | "version": { 108 | "executor": "@jscutlery/semver:version", 109 | "options": { 110 | "preset": "conventional" 111 | } 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /packages/streamlit-rxdb-dataframe/example.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | from typing import Dict, List 4 | import streamlit as st 5 | from streamlit.runtime.caching import cache_data 6 | from rxdb_dataframe import ( 7 | RXDB_COLLECTION_EDITOR_KEY, 8 | RxCollectionCreator, 9 | RxDBSessionState, 10 | rxdb_dataframe, 11 | ) 12 | 13 | # from pandas.api.types import ( is_bool_dtype, is_categorical_dtype, is_datetime64_any_dtype, is_numeric_dtype, is_object_dtype, ) # noqa: E501 14 | 15 | current_dir = os.path.dirname(os.path.abspath(__file__)) 16 | data_dir = os.path.join(current_dir, "rxdb_dataframe/frontend/public/assets/data") 17 | 18 | collection_name = "todo" 19 | todoSchema: Dict = json.load(open(os.path.join(data_dir, "todo.schema.json"))) 20 | initial_docs: List = json.load(open(os.path.join(data_dir, "col.dump.json")))["docs"] 21 | collection_config: RxCollectionCreator = { 22 | "name": collection_name, 23 | "schema": todoSchema, # to auto load schema from remote url pass None 24 | "localDocuments": True, 25 | "options": { 26 | # 'schemaUrl': 'assets/data/todo.schema.json', 27 | "initialDocs": initial_docs, 28 | "recreate": False, 29 | }, 30 | } 31 | 32 | 33 | state = RxDBSessionState() 34 | column_config = state.column_config 35 | query = state.query 36 | 37 | 38 | def on_change_dataframe(rxdb_state: RxDBSessionState): 39 | print("RxDBDataframe component on_change call") 40 | print("collection.info()", rxdb_state.info) 41 | 42 | 43 | @cache_data 44 | def apply_row_style(row): 45 | return ( 46 | ["color:green"] * len(row) if row.completed else ["color:grey"] * len(row) # default color 47 | ) # noqa: E501 48 | 49 | 50 | display = st.radio( 51 | "Display RxDB collection as:", 52 | options=["dataframe", "data_editor", "table"], 53 | horizontal=True, 54 | ) 55 | filter = st.radio( 56 | label="Filter data using RxDB **RxQuery**", 57 | help="MangoQuery syntax", 58 | label_visibility="visible", 59 | options=["all", "active", "completed"], 60 | horizontal=True, 61 | ) 62 | 63 | if filter == "active": 64 | query = {"selector": {"completed": {"$eq": False}}} 65 | elif filter == "completed": 66 | query = {"selector": {"completed": {"$eq": True}}} 67 | else: 68 | query = {"selector": {}} 69 | 70 | df = rxdb_dataframe( 71 | collection_config, 72 | query=query, 73 | with_rev=False, 74 | on_change=on_change_dataframe, 75 | ) 76 | 77 | if display == "data_editor": 78 | try: 79 | st.data_editor( 80 | df.copy().style.apply(apply_row_style, axis=1), 81 | use_container_width=True, 82 | hide_index=True, 83 | column_config=column_config, 84 | column_order=["title", "completed", "createdAt"], 85 | num_rows="dynamic", 86 | key=RXDB_COLLECTION_EDITOR_KEY, 87 | ) 88 | except Exception as e: 89 | st.error(f"An error occurred: {str(e)}") 90 | elif display == "dataframe": 91 | try: 92 | st.dataframe( 93 | df.style.apply(apply_row_style, axis=1), 94 | use_container_width=True, 95 | hide_index=True, 96 | column_config=column_config, 97 | column_order=["title", "completed", "createdAt"], 98 | ) 99 | except Exception as e: 100 | st.error(f"An error occurred: {str(e)}") 101 | else: 102 | try: 103 | st.table( 104 | df.style.apply(apply_row_style, axis=1), 105 | ) 106 | except Exception as e: 107 | st.error(f"An error occurred: {str(e)}") 108 | 109 | 110 | with st.sidebar: 111 | st.write("RxDB Collection Config") 112 | st.json(collection_config, expanded=False) 113 | 114 | st.write("RsDB Session State:") 115 | st.json(st.session_state, expanded=False) 116 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to @ngx-odm 2 | 3 | :+1::tada: First off, thanks for taking the time to contribute! :tada::+1: 4 | 5 | The following is a set of guidelines for contributing to @ngx-odm and its packages. 6 | 7 | #### Table Of Contents 8 | 9 | [I don't want to read this whole thing, I just have a question!!!](#i-dont-want-to-read-this-whole-thing-i-just-have-a-question) 10 | 11 | [How can I help?](#how-can-I-help?) 12 | 13 | [Developing](#developing) 14 | 15 | [Building](#building) 16 | 17 | - [Linking local version](#linking) 18 | 19 | [Publish new version](#publishing-new-version) 20 | 21 | - [Dev builds](#dev-builds) 22 | - [Beta builds](#beta-builds) 23 | - [Release builds](#release-builds) 24 | 25 | [Commit Message Guidelines](#commit) 26 | 27 | ## I don't want to read this whole thing I just have a question!!! 28 | 29 | > **Note:** Please don't file an issue to ask a question. 30 | 31 | - Read Rxdb [docs](https://rxdb.info) 32 | - Ask a question on [stackoverflow](https://stackoverflow.com/questions/tagged/rxdb). 33 | 34 | # How can I help? 35 | 36 | Check the [issues](https://github.com/voznik/ngx-odm/issues) where we have labels for help wanted. 37 | 38 | # Developing 39 | 40 | Start by installing all dependencies 41 | ... 42 | 43 | 44 | 45 | # Commit Message Guidelines 46 | 47 | We have very precise rules over how our git commit messages can be formatted. This leads to **more 48 | readable messages** that are easy to follow when looking through the **project history**. But also, 49 | we use the git commit messages to **generate the Angular change log**. 50 | 51 | ### Commit Message Format 52 | 53 | Each commit message consists of a **header**, a **body** and a **footer**. The header has a special 54 | format that includes a **type**, a **scope** and a **subject**: 55 | 56 | ``` 57 | (): 58 | 59 | 60 | 61 |