{"id":27997429,"url":"https://github.com/mkeen/rxcouch","last_synced_at":"2025-05-08T21:58:49.625Z","repository":{"id":33152277,"uuid":"141527031","full_name":"mkeen/rxcouch","owner":"mkeen","description":"🛋 (Universal) CouchDB Client Powered by ReactiveX (RxJS)","archived":false,"fork":false,"pushed_at":"2023-03-04T02:45:11.000Z","size":1824,"stargazers_count":7,"open_issues_count":9,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-08T21:58:44.473Z","etag":null,"topics":["angular","angular6","couchdb","couchdb-client","javascript","javascript-library","npm-module","rxjs","rxjs6","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mkeen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-07-19T05:06:46.000Z","updated_at":"2024-08-28T15:48:43.000Z","dependencies_parsed_at":"2023-01-14T23:39:01.054Z","dependency_job_id":null,"html_url":"https://github.com/mkeen/rxcouch","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkeen%2Frxcouch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkeen%2Frxcouch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkeen%2Frxcouch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkeen%2Frxcouch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mkeen","download_url":"https://codeload.github.com/mkeen/rxcouch/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253154974,"owners_count":21862621,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","angular6","couchdb","couchdb-client","javascript","javascript-library","npm-module","rxjs","rxjs6","typescript"],"created_at":"2025-05-08T21:58:48.291Z","updated_at":"2025-05-08T21:58:49.618Z","avatar_url":"https://github.com/mkeen.png","language":"TypeScript","readme":"# RxCouch\n\n`📀 Universal`\n\nReal-time CouchDB client that runs in the browser or nodejs. The change feed is handled automatically. Everything's a `BehaviorSubject`, so you get two-way binding for free.\n\n## Prerequisites\n\nRxJS 6+  \nCouchDB 2.3+, CouchDB 3.0+\n\n## Installation\n\n**NPM:** `npm install @mkeen/rxcouch`  \n**Yarn:** `yarn install @mkeen/rxcouch`\n\n## Developer Documentation\n\n### Including RxCouch in Your Project\n\n```typescript\nimport { CouchDB } from '@mkeen/rxcouch';\n```\n\n### Initialize RxCouch for Connecting to a CouchDB Database\n\n```typescript\nconst couchDbConnection = new CouchDB(\n  {\n    dbName: 'people',\n  }\n);\n```\n\n### Basic Configuration Options\n\nCouchDB is initialized with: `(RxCouchConfig, AuthorizationBehavior?, Observable\u003cCouchDBCredentials\u003e?)`\n\nAn `RxCouchConfig` looks like this by default:\n\n{ `host`: 'localhost'  \n`port`: 5984  \n`ssl`: false  \n`trackChanges`: true,\n`dbName`: '_users' }\n\n### Configuring Authentication\n\nCouchDB supports [Basic Auth, Cookies, and JWT](https://docs.couchdb.org/en/stable/api/server/authn.html) authentication schemes. This library supports Cookies or JWT (bearer token). For development purposes only, this library also supports open installs of couchdb without security.\n\nLet's take a look at how to initialize RxCouch for connecting to a CouchDB database that has Cookie Authentication configured.\n\n```typescript\nimport { BehaviorSubject } from 'rxjs';\nimport { CouchDB,\n         CouchSession,\n         AuthorizationBehavior } from '@mkeen/rxcouch';\n\nconst couchSession: CouchSession = new CouchSession(\n  AuthorizationBehavior.cookie,\n  `${COUCH_SSL? 'https://' : 'http://'}${COUCH_HOST}:${COUCH_PORT}/_session`,\n  new BehaviorSubject({username: 'username', password: 'password'}}),\n);\n\nconst couchDbConnection = new CouchDB(\n  {\n    dbName: 'people',\n    host: 'localhost',\n    trackChanges: true,\n  },\n  couchSession\n);\n\n//...\n```\n\nThe big detail to note here is that the final argument passed to the CouchSession initializer is an `Observable`. In this example it's hardcoded. In a real-world implementation, you'll create an `Observable` that emits when a user submits a login form, or when a configuration value is read, and pass that `Observable` into the initializer.\n\nSince we're hardcoding the credentials `Observable` argument, the above example will result in an authentication attempt being made to the speficied CouchDB host (without using HTTPS) immediately.\n\n### Getting Info About the Current Session\n\nTo determine which user (if any) is currently logged into CouchDB, you can call the `session()` function. `session` returns an `Observable` that emits a `CouchDBSession`.\n\n```typescript\n//...\ncouchDbConnection.session().subscribe((session: CouchDBSession) =\u003e {\n  console.log('Currently session info: ', session);\n});\n```\n\nIf you're using CouchDB to authenticate users in your application, you could call `session` when your app is initialized in order to determine if a user is logged in, and if so, any other information stored in the `_users` document.\n\n### Dealing with Documents\n\nWhether authentication is used or not, a document is always returned to you by RxCouch in the form a `BehaviorSubject` which provides a real-time two-way data binding with the document.\n\n#### Subscribe to Any Document in Real Time\n\n```typescript\ninterface Person {\n  name: string;\n  email?: string;\n  phone?: string;\n}\n\nconst myDocument: BehaviorSubject\u003cPerson\u003e = couchDbConnection.doc('778...05b');\n\nmyDocument.subscribe((document: Person) =\u003e {\n  console.log('Most recent person: ', document);\n});\n\n//...\n```\n\n###### Result\n\n```typescript\nMost recent person: { _id: \"7782f0743bee05005a548ba8af00205b\", _rev: \"10-bcaab49ec87c678686984d1c4873cd3e\", name: 'Mike\" }\n```\n\n#### Update The Same Document in Real Time\n\n```typescript\n//...\nconst myCompletelyChangedDocument = {\n  name: 'some new name here',\n  email: 'mwk@mikekeen.com',\n  phone: '323-209-5336'\n}\n\nmyDocument.next(myCompletelyChangedDocument);\n```\n\n###### All Connected Clients Result:\n\n```typescript\nMost recent person: { _id: \"7782f0743bee05005a548ba8af00205b\", _rev: \"11-bf3003bb5f63b875db4284f319a0b918\", name: \"some new name here\", email:  \"mwk@mikekeen.com\", phone: \"323-209-5336\"}\n```\n\n### Creating And Modifying Documents\n\nIn the above example, a document was fetched by its `_id`. The `doc()` function alternatively accepts an object as an argument. If an object is passed in, one of two things will happen:\n\n1. If the object contains both an `_id` and `_rev` field, the rest of the fields in the object will be used to update the document that matches the `_id`.\n2. If the object does not contain both an `_id` and a `_rev` field, then a new document will be created based on the fields contained in the object passed.\n\nWhichever of the above happens, `doc` returns a `BehaviorSubject` that will reflect all future changes to the relevant document, and pass all changes upstream when `.next()` is called.\n\n#### Create a New Document and Subscribe to Future Changes\n\n```typescript\n//...\nconst newlyCreatedPerson = couchDbConnection.doc({\n  name: 'tracy',\n  email: 'tracy@company.com',\n  phone: '323-209-5336'\n}).subscribe((doc: Person) =\u003e {\n  console.log('Person Feed: ', doc);\n});\n```\n\n###### Result\n\n```typescript\nPerson Feed: {\"_id\": \"7782f0743bee05005a548ba8af00b4f5\", \"_rev\": \"1-2fee21d51258845545ea6506ab138919\", \"name\": \"tracy\", \"email\": \"tracy@company.com\", \"phone\": \"323-209-5336\"}\n```\n\n#### Modify an Existing Document and Subscribe to Future Changes\n\nThere are two ways to modify a document that already exists in CouchDB.\n\nOne way, is to simply pass a modified version of the existing document to `doc` like in the example below:\n\n```typescript\n//...\ncouchDbConnection.doc({\n  _id: '7782f0743bee05005a548ba8af00b4f5',\n  _rev: '1-2fee21d51258845545ea6506ab138919',\n  name: 'tracy',\n  email: 'tracy@company-modified.com',\n  phone: '323-209-5336'\n}).subscribe((doc) =\u003e {\n  console.log('Document Modified: ', doc);\n})\n```\n\n###### Result\n\n```typescript\nDocument Modified: { \"_id\": \"7782f0743bee05005a548ba8af00b4f5\", \"_rev\": \"2-e654adf15f28b99f26ae1f0dbe8e7c36\", \"name\": \"tracy\", \"email\": \"tracy@company-modified.com\", \"phone\": \"323-209-5336\" }\n\nPerson Feed: {\"_id\": \"7782f0743bee05005a548ba8af00b4f5\", \"_rev\": \"2-e654adf15f28b99f26ae1f0dbe8e7c36\", \"name\": \"tracy\", \"email\": \"tracy@company-modified.com\", \"phone\": \"323-209-5336\" }\n```\n\nAnother way to modify a document that already exists in CouchDB is to just call `next` on an already fetched document's `BehaviorSubject`.\n\n```typescript\n//..\nnewlyCreatedPerson.next({\n  name: 'tracy Modified!',\n  email: 'tracy@company-modified-again.com',\n  phone: '323-209-5336'\n});\n```\n\n###### Result\n\n```typescript\nPerson Feed: {\"_id\": \"7782f0743bee05005a548ba8af00b4f5\", \"_rev\": \"3-8da970f593132c80ccee83fc4708ce33\", \"name\": \"tracy Modified!\", \"email\": \"tracy@company-modified-again.com\", \"phone\": \"323-209-5336\" }\n```\n\n### Finding Documents With a Query\n\nRxCouch exposes `find` from `CouchDB` that uses [CouchDB Selector Syntax](https://docs.couchdb.org/en/2.2.0/api/database/find.html#selector-syntax) to make queries, and returns a list of matching documents. Warning: Documents returned are not `BehaviorSubject`s!\n\n### Get a List of Documents That Match a Query\n\nCall `find` with `(CouchDBFindQuery)`.\n\nAn `CouchDBFindQuery`, when passed into `find`, should conform to [CouchDB Selector Syntax](https://docs.couchdb.org/en/2.2.0/api/database/find.html#selector-syntax). It can have the following optional properties of the following types:\n\n`selector: CouchDBFindSelector`\n`limit: number`\n`skip: number`\n`sort: CouchDBFindSort[]`\n`fields: string[]`\n`use_index: string | []`\n`r: number`\n`bookmark: string`\n`update: boolean`\n`stable: boolean`\n`stale: string`\n`execution_stats: boolean`\n\nA call to `find` will return an `Observable` that will emit a list of documents that match the passed query.\n\n```typescript\n//...\ncouchDbConnection.find({\n  selector: {\n    name: 'tracy'\n  }\n  \n}).subscribe((matchingPeople: Person[]) =\u003e {\n  console.log('Matching people: ', matchingPeople);\n});\n```\n\n###### Result\n\n```typescript\nMatching people: [{ \"_id\": \"7782f0743bee05005a548ba8af00b4f5\", \"_rev\": \"3-8da970f593132c80ccee83fc4708ce33\", \"name\": \"tracy Modified!\", \"email\": \"tracy@company-modified-again.com\", \"phone\": \"323-209-5336\" }]\n```\n\n#### Get Real-Time Feeds for Found Documents\n\n```typescript\n//...\ncouchDbConnection.find({\n  selector: {\n    name: 'some new name here'\n  }\n  \n}).subscribe((matchingPeople: Person[]) =\u003e {\n  const documentFeeds = matchingPeople.map((person: Person) =\u003e {\n    return couchDbConnection.doc(matchingPeople)\n  });\n  \n  documentFeeds.forEach((feed) =\u003e {\n    feed.subscribe(\n      (document: Person) =\u003e console.log('Latest person: ', document)\n    );\n    \n  });\n  \n});\n```\n\n###### Result\n\n```typescript\nLatest person: { \"_id\": \"7782f0743bee05005a548ba8af00b4f5\", \"_rev\": \"3-8da970f593132c80ccee83fc4708ce33\", \"name\": \"tracy Modified!\", \"email\": \"tracy@company-modified-again.com\", \"phone\": \"323-209-5336\" }\n```\n\n## 🚂 Under the Hood\n\n#### Document Tracking\n\nDocuments are automatically cached and then tracked for changes. `CouchDBDocumentCollection` handles both caching and change tracking.\n\n##### Cache\n\nInstances of `CouchDB` have a method called `doc`. Any documents that flow through `doc` are cached in a `CouchDBDocumentCollection`. They can later be retrieved by _id in the form of a `BehaviorSubject` that supports two way binding. A hash of the document is indexed (by document id) for change tracking purposes.\n\n##### Change Tracking\n\nBefore document changes are propagated either to or from a `BehaviorSubject`, the potentially changed document is hashed and compared against a previously indexed  hash of the document. If the hashes don't match, the document has changed, and it will be passed into the `next` method of the relavent indexed `BehaviorSubject`. Finally, the indexed hash entry for the document will be updated.\n\n## Thank you for using RxCouch!\n\n🇺🇸\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmkeen%2Frxcouch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmkeen%2Frxcouch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmkeen%2Frxcouch/lists"}