From e5ad8b8161835bce36164cfa6ebe275fa38b0775 Mon Sep 17 00:00:00 2001 From: Lawrence Khadka <6295956+lawrencek0@users.noreply.github.com> Date: Thu, 28 Jun 2018 00:56:27 -0500 Subject: [PATCH] Add PouchDB base service (#1355) --- docker/planet/Dockerfile | 3 ++ package.json | 4 ++ src/app/app.module.ts | 2 + src/app/shared/database/index.ts | 4 ++ src/app/shared/database/pouch.service.ts | 68 ++++++++++++++++++++++++ src/polyfills.ts | 4 ++ tsconfig.json | 1 + 7 files changed, 86 insertions(+) create mode 100644 src/app/shared/database/index.ts create mode 100644 src/app/shared/database/pouch.service.ts diff --git a/docker/planet/Dockerfile b/docker/planet/Dockerfile index d19ef3757b..a4c237a4a0 100644 --- a/docker/planet/Dockerfile +++ b/docker/planet/Dockerfile @@ -10,6 +10,9 @@ COPY package.json ./ COPY docker/planet/scripts/ ./ COPY . . +RUN apk add --update \ + python \ + build-base RUN npm i --silent RUN ./compile_planet.sh diff --git a/package.json b/package.json index 7d21bd76c5..b05d1a34c2 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,8 @@ "material-icons": "^0.1.0", "mime": "^2.3.1", "ngx-img": "^10.15.0", + "pouchdb": "^7.0.0", + "pouchdb-find": "^7.0.0", "rxjs": "^6.2.0", "zone.js": "~0.8.26" }, @@ -53,6 +55,8 @@ "@types/jasmine": "~2.5.53", "@types/jasminewd2": "~2.0.2", "@types/node": "~6.0.60", + "@types/pouchdb": "^6.3.2", + "@types/pouchdb-find": "^6.3.3", "codelyzer": "~3.2.0", "htmlhint-ng2": "0.0.13", "jasmine-core": "~2.6.2", diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 1766c016dd..83d94e4857 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -22,6 +22,7 @@ import { FeedbackService } from './feedback/feedback.service'; import { ResourcesService } from './resources/resources.service'; import { SubmissionsService } from './submissions/submissions.service'; import { CoursesService } from './courses/courses.service'; +import { SHARED_SERVICES } from './shared/database'; import { SyncService } from './shared/sync.service'; import { PlanetDialogsModule } from './shared/dialogs/planet-dialogs.module'; import { PlanetLanguageModule } from './shared/planet-language.module'; @@ -54,6 +55,7 @@ import { PlanetLanguageModule } from './shared/planet-language.module'; ResourcesService, SubmissionsService, CoursesService, + ...SHARED_SERVICES, SyncService ], bootstrap: [ AppComponent ] diff --git a/src/app/shared/database/index.ts b/src/app/shared/database/index.ts new file mode 100644 index 0000000000..d34ab6c114 --- /dev/null +++ b/src/app/shared/database/index.ts @@ -0,0 +1,4 @@ +import { PouchService } from './pouch.service'; + +export { PouchService } from './pouch.service'; +export const SHARED_SERVICES = [ PouchService ]; diff --git a/src/app/shared/database/pouch.service.ts b/src/app/shared/database/pouch.service.ts new file mode 100644 index 0000000000..b728b43d88 --- /dev/null +++ b/src/app/shared/database/pouch.service.ts @@ -0,0 +1,68 @@ +import { Injectable } from '@angular/core'; +import PouchDB from 'pouchdb'; +import PouchDBFind from 'pouchdb-find'; +import { throwError, from } from 'rxjs'; +import { catchError } from 'rxjs/operators'; +import { environment } from '../../../environments/environment'; + +PouchDB.plugin(PouchDBFind); + +@Injectable() +export class PouchService { + private baseUrl = environment.couchAddress; + private localDBs; + private databases = []; + + constructor() { + this.databases.forEach(db => { + const pouchDB = new PouchDB(`local-${db}`); + + // indexes the field for faster lookup + pouchDB.createIndex({ + index: { + fields: [ 'kind', 'createdAt' ] + } + }); + this.localDBs[db] = pouchDB; + }); + } + + // @TODO: handle edge cases like offline, duplicate, duplications + // handle repliction errors or make use of navigator online? + replicateFromRemoteDBs() { + this.databases.forEach(db => { + this.localDBs[db].replicate.from(this.baseUrl + db); + }); + } + + replicateToRemoteDBs() { + this.databases.forEach(db => { + this.localDBs[db].replicate.to(this.baseUrl + db, { + filter(doc) { + return doc.pouchIndex === db; + } + }); + }); + } + + replicateFromRemoteDB(db) { + return this.replicate(this.localDBs[db].replicate.from(this.baseUrl + db)); + } + + replicateToRemoteDB(db) { + return this.replicate(this.localDBs[db].replicate.to(this.baseUrl + db)); + } + + replicate(replicateFn) { + return from(replicateFn).pipe(catchError(this.handleError)); + } + + getLocalPouchDB(db) { + return this.localDBs[db]; + } + + private handleError(err) { + console.error('An error occurred in PouchDB', err); + return throwError(err.message || err); + } +} diff --git a/src/polyfills.ts b/src/polyfills.ts index 7831e97b79..827d3f9cd6 100644 --- a/src/polyfills.ts +++ b/src/polyfills.ts @@ -70,3 +70,7 @@ import 'zone.js/dist/zone'; // Included with Angular CLI. * Need to import at least one locale-data with intl. */ // import 'intl/locale-data/jsonp/en'; + +(window as any).global = window; +(window as any).process = {}; +(window as any).process.nextTick = setTimeout; diff --git a/tsconfig.json b/tsconfig.json index fcf1a1f90e..0c00a75d0a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,6 +7,7 @@ "moduleResolution": "node", "emitDecoratorMetadata": true, "experimentalDecorators": true, + "allowSyntheticDefaultImports": true, "target": "es5", "typeRoots": [ "node_modules/@types"