adding database changes & models.

This commit is contained in:
Jason Kulatunga 2022-10-06 18:03:18 -07:00
parent 349b627845
commit 5442063c17
9 changed files with 120 additions and 33 deletions

View File

@ -1,6 +1,6 @@
# lib
This directory contains Typescript libraries/packages that are intended to be used in both Angular & WebWorkers.
This directory contains Typescript libraries/packages that are intended to be used in both Angular & WebWorkers (and potentially NodeJS).
That means they cannot contain any browser context/DOM specific code, as they will break in Web Workers.
## conduit

View File

@ -1,5 +1,7 @@
import {Source} from '../models/database/source';
import {ResourceFhir} from '../models/database/resource_fhir';
import {SourceSummary} from '../models/fasten/source-summary';
import {Summary} from '../models/fasten/summary';
// import {SourceSummary} from '../../app/models/fasten/source-summary';
export interface IDatabaseDocument {
@ -22,21 +24,20 @@ export interface IDatabaseRepository {
// GetUserByEmail(context.Context, string) (*models.User, error)
// GetCurrentUser(context.Context) *models.User
// GetSummary(ctx context.Context) (*models.Summary, error)
GetSummary(): Promise<Summary>
CreateSource(source: Source): Promise<string>
GetSource(source_id: string): Promise<Source>
DeleteSource(source_id: string): Promise<boolean>
GetSourceSummary(source_id: string): Promise<SourceSummary>
GetSources(): Promise<IDatabasePaginatedResponse>
// UpsertResource(context.Context, *models.ResourceFhir) error
// GetResourceBySourceType(context.Context, string, string) (*models.ResourceFhir, error)
// GetResourceBySourceId(context.Context, string, string) (*models.ResourceFhir, error)
// ListResources(context.Context, models.ListResourceQueryOptions) ([]models.ResourceFhir, error)
// GetPatientForSources(ctx context.Context) ([]models.ResourceFhir, error)
CreateSource(source: Source): Promise<string>
GetSource(source_id: string): Promise<Source>
DeleteSource(source_id: string): Promise<boolean>
// GetSourceSummary(source_id: string): Promise<SourceSummary>
GetSources(): Promise<IDatabasePaginatedResponse>
CreateResource(resource: ResourceFhir): Promise<string>
CreateResources(resources: ResourceFhir[]): Promise<string[]>
GetResource(resource_id: string): Promise<ResourceFhir>

View File

@ -1,6 +1,6 @@
import {IDatabaseRepository} from './interface';
import {NewRepositiory} from './pouchdb_repository';
import {SourceType} from '../models/database/types';
import {SourceType} from '../models/database/source_types';
import {Source} from '../models/database/source';
import {DocType} from './constants';

View File

@ -1,9 +1,13 @@
import {Source} from '../models/database/source';
import {IDatabasePaginatedResponse, IDatabaseDocument, IDatabaseRepository} from './interface';
import * as PouchDB from 'pouchdb/dist/pouchdb';
import PouchFind from 'pouchdb/dist/pouchdb.find';
// import * as PouchDB from 'pouchdb';
import {DocType} from './constants';
import {ResourceFhir} from '../models/database/resource_fhir';
import {ResourceTypeCounts, SourceSummary} from '../models/fasten/source-summary';
import {Base64} from '../utils/base64';
import {Summary} from '../models/fasten/summary';
export function NewRepositiory(databaseName: string = 'fasten'): IDatabaseRepository {
return new PouchdbRepository(databaseName)
@ -13,12 +17,71 @@ export class PouchdbRepository implements IDatabaseRepository {
localPouchDb: PouchDB.Database
constructor(public databaseName: string) {
//setup PouchDB Plugins
PouchDB.plugin(PouchFind); //https://pouchdb.com/guides/mango-queries.html
this.localPouchDb = new PouchDB(databaseName);
//create any necessary indexes
// this index allows us to group by source_resource_type
this.localPouchDb.createIndex({
index: {fields: [
//global
'doc_type',
//only relevant for resource_fhir documents
'source_resource_type',
]}
}, (msg) => {console.log("DB createIndex complete", msg)});
}
public Close(): void {
return
}
///////////////////////////////////////////////////////////////////////////////////////
// Summary
public async GetSummary(): Promise<Summary> {
const summary = new Summary()
summary.sources = await this.GetSources()
.then((paginatedResp) => paginatedResp.rows)
summary.patients = await this.GetDB().find({
selector: {
doc_type: DocType.ResourceFhir,
source_resource_type: "Patient",
}
})
summary.resource_type_counts = await this.findDocumentByPrefix(`${DocType.ResourceFhir}`, true)
.then((paginatedResp) => {
const lookup: {[name: string]: ResourceTypeCounts} = {}
paginatedResp?.rows.forEach((resource: ResourceFhir) => {
let currentResourceStats = lookup[resource.source_resource_type] || {
count: 0,
source_id: resource.source_id,
resource_type: resource.source_resource_type
}
currentResourceStats.count += 1
lookup[resource.source_resource_type] = currentResourceStats
})
const arr = []
for(let key in lookup){
arr.push(lookup[key])
}
return arr
})
return summary
}
///////////////////////////////////////////////////////////////////////////////////////
// Source
public async CreateSource(source: Source): Promise<string> {
return this.createDocument(source);
}
@ -41,10 +104,41 @@ export class PouchdbRepository implements IDatabaseRepository {
})
}
public async GetSourceSummary(source_id: string): Promise<SourceSummary> {
const sourceSummary = new SourceSummary()
sourceSummary.source = await this.GetSource(source_id)
sourceSummary.patient = await this.findDocumentByPrefix(`${DocType.ResourceFhir}:${Base64.Encode(source_id)}:Patient`, true)
.then((paginatedResp) => paginatedResp?.rows[0])
sourceSummary.resource_type_counts = await this.findDocumentByPrefix(`${DocType.ResourceFhir}:${Base64.Encode(source_id)}`, true)
.then((paginatedResp) => {
const lookup: {[name: string]: ResourceTypeCounts} = {}
paginatedResp?.rows.forEach((resource: ResourceFhir) => {
let currentResourceStats = lookup[resource.source_resource_type] || {
count: 0,
source_id: resource.source_id,
resource_type: resource.source_resource_type
}
currentResourceStats.count += 1
lookup[resource.source_resource_type] = currentResourceStats
})
const arr = []
for(let key in lookup){
arr.push(lookup[key])
}
return arr
})
return sourceSummary
}
public async DeleteSource(source_id: string): Promise<boolean> {
return this.deleteDocument(source_id)
}
///////////////////////////////////////////////////////////////////////////////////////
// Resource
public async CreateResource(resource: ResourceFhir): Promise<string> {
return this.createDocument(resource);
}
@ -114,12 +208,16 @@ export class PouchdbRepository implements IDatabaseRepository {
.get(id)
}
private findDocumentByDocType(docType: DocType, includeDocs: boolean = true): Promise<IDatabasePaginatedResponse> {
return this.findDocumentByPrefix(docType, includeDocs)
}
private findDocumentByPrefix(prefix: string, includeDocs: boolean = true): Promise<IDatabasePaginatedResponse> {
return this.GetDB()
.allDocs({
include_docs: includeDocs,
startkey: `${docType}:`,
endkey: `${docType}:\uffff`
startkey: `${prefix}:`,
endkey: `${prefix}:\uffff`
})
}

View File

@ -1,17 +0,0 @@
// export class RecordBase {
// _id: string
// entry_type: DatabaseRecordType
// source_id: string
// source_resource_type: string
// source_resource_id: string
//
// constructor(database_record_type: DatabaseRecordType, source_resource_type: string, source_id: string, source_resource_id: string ) {
// this.source_record_type = source_resource_type
// this.source_id = source_id
// this.source_resource_id = source_resource_id
// }
// }
// interface LabeledValue {
// label: string;
// }

View File

@ -1,5 +1,5 @@
import {LighthouseSourceMetadata} from '../lighthouse/lighthouse-source-metadata';
import {SourceType} from './types';
import {SourceType} from './source_types';
import {DocType} from '../../../lib/database/constants';
export class Source extends LighthouseSourceMetadata{

View File

@ -16,4 +16,5 @@ export class LighthouseSourceMetadata {
redirect_uri: string
confidential: boolean
cors_relay_required: boolean
}

View File

@ -1,8 +1,12 @@
export class Base64 {
public static Encode(data: string): string {
return btoa(data)
return `b64.${btoa(data)}`
}
public static Decode(data: string): string {
return atob(data)
const parts = data.split(".")
if(parts.length != 2){
throw new Error(`invalid base64 encoded string: ${data}`)
}
return atob(parts[1])
}
}