fhir_db 0.12.0 copy "fhir_db: ^0.12.0" to clipboard
fhir_db: ^0.12.0 copied to clipboard

A wrapper for Sembast and SQFlite to enable easy, local and secure storage of fhir resources

example/main.dart

// ignore_for_file: avoid_print

import 'dart:io';

import 'package:collection/collection.dart';
import 'package:fhir/r4.dart';
import 'package:fhir_bulk/r4.dart';
import 'package:fhir_db/r4.dart';
import 'package:hive/hive.dart';
import 'package:test/test.dart';

import '../test/test_resources.dart';

Future<void> main() async {
  const String directory = 'db';
  if (await Directory(directory).exists()) {
    await Directory(directory).delete(recursive: true);
  }

  /// Initialize Hive & Clear Current Hive DB
  final FhirDb fhirDb = FhirDb();
  const String password1 = 'password1';
  const String password2 = 'password2';
  await fhirDb.init(path: directory, pw: password1);
  const Patient patient1 = Patient(fhirId: '1');
  final Resource saved1 = await fhirDb.save(resource: patient1, pw: password1);
  group('', () {
    test('Saved A Patient, Found A Patient', () async {
      final List<Resource> search1 = await fhirDb.find(
          resourceType: R4ResourceType.Patient, id: '1', pw: password1);
      expect(saved1, search1[0]);
    });

    test('Found Patient With New Password Because Box Was Already Opened',
        () async {
      final List<Resource> search2 = await fhirDb.find(
          resourceType: R4ResourceType.Patient, id: '1', pw: password1);
      expect(saved1, search2[0]);
    });

    test('Password Changed', () async {
      await fhirDb.updatePw(oldPw: password1, newPw: password2);
      // final List<Resource> search3 = await fhirDb.find(password1,
      //     resourceType: R4ResourceType.Patient, id: '1');
      // expect(true, search3.isEmpty);
      // await fhirDb.closeAllBoxes();
      final List<Resource> search4 = await fhirDb.find(
          resourceType: R4ResourceType.Patient, id: '1', pw: password2);
      expect(saved1, search4[0]);
      await fhirDb.updatePw(oldPw: password2);
    });
  });

  const String id = '12345';
  group('Saving Things:', () {
    test('Save Patient', () async {
      const HumanName humanName =
          HumanName(family: 'Atreides', given: <String>['Duke']);
      const Patient patient = Patient(fhirId: id, name: <HumanName>[humanName]);
      final Resource saved = await fhirDb.save(resource: patient);

      expect(saved.fhirId, id);
      expect((saved as Patient).name?[0], humanName);
    });

    test('Save Organization', () async {
      const Organization organization =
          Organization(fhirId: id, name: 'FhirFli');
      final Resource saved = await fhirDb.save(resource: organization);

      expect(saved.fhirId, id);

      expect((saved as Organization).name, 'FhirFli');
    });

    test('Save Observation1', () async {
      final Observation observation1 = Observation(
        fhirId: 'obs1',
        code: const CodeableConcept(text: 'Observation #1'),
        effectiveDateTime: FhirDateTime(DateTime(1981, 09, 18)),
      );
      final Resource saved = await fhirDb.save(resource: observation1);

      expect(saved.fhirId, 'obs1');

      expect((saved as Observation).code.text, 'Observation #1');
    });

    test('Save Observation1 Again', () async {
      const Observation observation1 = Observation(
          fhirId: 'obs1',
          code: CodeableConcept(text: 'Observation #1 - Updated'));
      final Resource saved = await fhirDb.save(resource: observation1);

      expect(saved.fhirId, 'obs1');

      expect((saved as Observation).code.text, 'Observation #1 - Updated');

      expect(saved.meta?.versionId, FhirId('2'));
    });

    test('Save Observation2', () async {
      final Observation observation2 = Observation(
        fhirId: 'obs2',
        code: const CodeableConcept(text: 'Observation #2'),
        effectiveDateTime: FhirDateTime(DateTime(1981, 09, 18)),
      );
      final Resource saved = await fhirDb.save(resource: observation2);

      expect(saved.fhirId, 'obs2');

      expect((saved as Observation).code.text, 'Observation #2');
    });

    test('Save Observation3', () async {
      final Observation observation3 = Observation(
        fhirId: 'obs3',
        code: const CodeableConcept(text: 'Observation #3'),
        effectiveDateTime: FhirDateTime(DateTime(1981, 09, 18)),
      );
      final Resource saved = await fhirDb.save(resource: observation3);

      expect(saved.fhirId, 'obs3');

      expect((saved as Observation).code.text, 'Observation #3');
    });
  });

  group('Finding Things:', () {
    test('Find 1st Patient', () async {
      final List<Resource> search =
          await fhirDb.find(resourceType: R4ResourceType.Patient, id: id);
      const HumanName humanName =
          HumanName(family: 'Atreides', given: <String>['Duke']);

      expect(search.length, 1);

      expect((search[0] as Patient).name?[0], humanName);
    });

    test('Find 3rd Observation', () async {
      final List<Resource> search = await fhirDb.find(
          resourceType: R4ResourceType.Observation, id: 'obs3');

      expect(search.length, 1);

      expect(search[0].fhirId, 'obs3');

      expect((search[0] as Observation).code.text, 'Observation #3');
    });

    test('Find All Observations', () async {
      final List<Resource> search = await fhirDb.getActiveResourcesOfType(
        resourceTypes: <R4ResourceType>[R4ResourceType.Observation],
      );

      expect(search.length, 3);

      final List<String> idList = <String>[];
      for (final Resource obs in search) {
        idList.add(obs.fhirId.toString());
      }

      expect(idList.contains('obs1'), true);

      expect(idList.contains('obs2'), true);

      expect(idList.contains('obs3'), true);
    });

    test('Find All (non-historical) Resources', () async {
      final List<Resource> search = await fhirDb.getAllActiveResources();

      expect(search.length, 6);
      final List<Resource> patList = search.toList();
      final List<Resource> orgList = search.toList();
      final List<Resource> obsList = search.toList();
      patList.retainWhere((Resource resource) =>
          resource.resourceType == R4ResourceType.Patient);
      orgList.retainWhere((Resource resource) =>
          resource.resourceType == R4ResourceType.Organization);
      obsList.retainWhere((Resource resource) =>
          resource.resourceType == R4ResourceType.Observation);

      expect(patList.length, 2);

      expect(orgList.length, 1);

      expect(obsList.length, 3);
    });
  });

  group('Deleting Things:', () {
    test('Delete 2nd Observation', () async {
      await fhirDb.delete(
        resourceType: R4ResourceType.Observation,
        id: 'obs2',
      );

      final List<Resource> search = await fhirDb.getActiveResourcesOfType(
        resourceTypes: <R4ResourceType>[R4ResourceType.Observation],
      );

      expect(search.length, 2);

      final List<String> idList = <String>[];
      for (final Resource obs in search) {
        idList.add(obs.fhirId.toString());
      }

      expect(idList.contains('obs1'), true);

      expect(idList.contains('obs2'), false);

      expect(idList.contains('obs3'), true);
    });

    test('Delete All Observations', () async {
      await fhirDb.deleteSingleType(resourceType: R4ResourceType.Observation);

      final List<Resource> search = await fhirDb.getAllActiveResources();

      expect(search.length, 3);

      final List<Resource> patList = search.toList();
      final List<Resource> orgList = search.toList();
      patList.retainWhere((Resource resource) =>
          resource.resourceType == R4ResourceType.Patient);
      orgList.retainWhere((Resource resource) =>
          resource.resourceType == R4ResourceType.Organization);

      expect(patList.length, 2);
    });

    test('Delete All Resources', () async {
      await fhirDb.deleteAllResources();

      final List<Resource> search = await fhirDb.getAllActiveResources();

      expect(search.length, 0);
    });
  });

  group('Password - Saving Things:', () {
    test('Save Patient', () async {
      await fhirDb.updatePw(newPw: password2);
      const HumanName humanName =
          HumanName(family: 'Atreides', given: <String>['Duke']);
      const Patient patient = Patient(fhirId: id, name: <HumanName>[humanName]);
      final Resource saved =
          await fhirDb.save(resource: patient, pw: password2);

      expect(saved.fhirId, id);

      expect((saved as Patient).name?[0], humanName);
    });

    test('Save Organization', () async {
      const Organization organization =
          Organization(fhirId: id, name: 'FhirFli');
      final Resource saved =
          await fhirDb.save(resource: organization, pw: password2);

      expect(saved.fhirId, id);

      expect((saved as Organization).name, 'FhirFli');
    });

    test('Save Observation1', () async {
      final Observation observation1 = Observation(
        fhirId: 'obs1',
        code: const CodeableConcept(text: 'Observation #1'),
        effectiveDateTime: FhirDateTime(DateTime(1981, 09, 18)),
      );
      final Resource saved =
          await fhirDb.save(resource: observation1, pw: password2);

      expect(saved.fhirId, 'obs1');

      expect((saved as Observation).code.text, 'Observation #1');
    });

    test('Save Observation1 Again', () async {
      const Observation observation1 = Observation(
          fhirId: 'obs1',
          code: CodeableConcept(text: 'Observation #1 - Updated'));
      final Resource saved =
          await fhirDb.save(resource: observation1, pw: password2);

      expect(saved.fhirId, 'obs1');

      expect((saved as Observation).code.text, 'Observation #1 - Updated');

      expect(saved.meta?.versionId, FhirId('2'));
    });

    test('Save Observation2', () async {
      final Observation observation2 = Observation(
        fhirId: 'obs2',
        code: const CodeableConcept(text: 'Observation #2'),
        effectiveDateTime: FhirDateTime(DateTime(1981, 09, 18)),
      );
      final Resource saved =
          await fhirDb.save(resource: observation2, pw: password2);

      expect(saved.fhirId, 'obs2');

      expect((saved as Observation).code.text, 'Observation #2');
    });

    test('Save Observation3', () async {
      final Observation observation3 = Observation(
        fhirId: 'obs3',
        code: const CodeableConcept(text: 'Observation #3'),
        effectiveDateTime: FhirDateTime(DateTime(1981, 09, 18)),
      );
      final Resource saved =
          await fhirDb.save(resource: observation3, pw: password2);

      expect(saved.fhirId, 'obs3');

      expect((saved as Observation).code.text, 'Observation #3');
    });
  });

  group('Password - Finding Things:', () {
    test('Find 1st Patient', () async {
      final List<Resource> search = await fhirDb.find(
          resourceType: R4ResourceType.Patient, id: id, pw: password2);
      const HumanName humanName =
          HumanName(family: 'Atreides', given: <String>['Duke']);

      expect(search.length, 1);

      expect((search[0] as Patient).name?[0], humanName);
    });

    test('Find 3rd Observation', () async {
      final List<Resource> search = await fhirDb.find(
          resourceType: R4ResourceType.Observation, id: 'obs3', pw: password2);

      expect(search.length, 1);

      expect(search[0].fhirId, 'obs3');

      expect((search[0] as Observation).code.text, 'Observation #3');
    });

    test('Find All Observations', () async {
      final List<Resource> search = await fhirDb.getActiveResourcesOfType(
          resourceTypes: <R4ResourceType>[R4ResourceType.Observation],
          pw: password2);

      expect(search.length, 3);

      final List<String> idList = <String>[];
      for (final Resource obs in search) {
        idList.add(obs.fhirId.toString());
      }

      expect(idList.contains('obs1'), true);

      expect(idList.contains('obs2'), true);

      expect(idList.contains('obs3'), true);
    });

    test('Find All (non-historical) Resources', () async {
      final List<Resource> search =
          await fhirDb.getAllActiveResources(pw: password2);

      expect(search.length, 5);
      final List<Resource> patList = search.toList();
      final List<Resource> orgList = search.toList();
      final List<Resource> obsList = search.toList();
      patList.retainWhere((Resource resource) =>
          resource.resourceType == R4ResourceType.Patient);
      orgList.retainWhere((Resource resource) =>
          resource.resourceType == R4ResourceType.Organization);
      obsList.retainWhere((Resource resource) =>
          resource.resourceType == R4ResourceType.Observation);

      expect(patList.length, 1);

      expect(orgList.length, 1);

      expect(obsList.length, 3);
    });
  });

  group('Password - Deleting Things:', () {
    test('Delete 2nd Observation', () async {
      await fhirDb.delete(resourceType: R4ResourceType.Observation, id: 'obs2');

      final List<Resource> search = await fhirDb.getActiveResourcesOfType(
          resourceTypes: <R4ResourceType>[R4ResourceType.Observation],
          pw: password2);

      expect(search.length, 2);

      final List<String> idList = <String>[];
      for (final Resource obs in search) {
        idList.add(obs.fhirId.toString());
      }

      expect(idList.contains('obs1'), true);

      expect(idList.contains('obs2'), false);

      expect(idList.contains('obs3'), true);
    });

    test('Delete All Observations', () async {
      await fhirDb.deleteSingleType(resourceType: R4ResourceType.Observation);

      final List<Resource> search =
          await fhirDb.getAllActiveResources(pw: password2);

      expect(search.length, 2);

      final List<Resource> patList = search.toList();
      final List<Resource> orgList = search.toList();
      patList.retainWhere((Resource resource) =>
          resource.resourceType == R4ResourceType.Patient);
      orgList.retainWhere((Resource resource) =>
          resource.resourceType == R4ResourceType.Organization);

      expect(patList.length, 1);

      expect(patList.length, 1);
    });

    test('Delete All Resources', () async {
      await fhirDb.deleteAllResources(pw: password2);

      final List<Resource> search =
          await fhirDb.getAllActiveResources(pw: password2);

      expect(search.length, 0);

      await fhirDb.updatePw(newPw: password2);
    });
  });

  group('More Complicated Searching', () {
    test('(& Resources)', () async {
      String output = '';
      final Directory dir = Directory('assets');
      final List<String> fileList =
          await dir.list().map((FileSystemEntity event) => event.path).toList();
      int total = 0;
      const int numberOfTimes = 1;
      for (int i = 0; i < numberOfTimes; i++) {
        final DateTime startTime = DateTime.now();
        for (final String file in fileList) {
          // print(file);
          int i = 0;
          final List<Resource> resources = await FhirBulk.fromFile(file);
          for (final Resource? resource in resources) {
            if (resource != null) {
              i++;
              await fhirDb.save(resource: resource);
            }
          }
          total += i;
        }
        final DateTime endTime = DateTime.now();
        final Duration duration = endTime.difference(startTime);
        output += 'Total Resources: $total\n';
        output += 'Total time: ${duration.inSeconds} seconds';
      }
      await fhirDb.save(resource: testPatient1);
      await fhirDb.save(resource: testPatient2);
      await fhirDb.save(resource: testObservation1);
      await fhirDb.save(resource: testObservation2);
      await fhirDb.save(resource: testObservation3);
      await fhirDb.save(resource: testObservation4);
      await fhirDb.save(resource: testObservation5);
      await fhirDb.save(resource: testObservation6);
      await fhirDb.save(resource: testConceptMap1);
      await fhirDb.save(resource: testCondition1);

      print(output);
      final DateTime testStartTime = DateTime.now();
      expect(true, await compareTwoResources(testPatient1, fhirDb, null));
      expect(true, await compareTwoResources(testPatient2, fhirDb, null));
      expect(true, await compareTwoResources(testObservation1, fhirDb, null));
      expect(true, await compareTwoResources(testObservation2, fhirDb, null));
      expect(true, await compareTwoResources(testObservation3, fhirDb, null));
      expect(true, await compareTwoResources(testObservation4, fhirDb, null));
      expect(true, await compareTwoResources(testObservation5, fhirDb, null));
      expect(true, await compareTwoResources(testObservation6, fhirDb, null));
      expect(true, await compareTwoResources(testConceptMap1, fhirDb, null));
      expect(true, await compareTwoResources(testCondition1, fhirDb, null));
      final DateTime testEndTime = DateTime.now();
      print(
          'Found 10 resources in total of ${testEndTime.difference(testStartTime).inMilliseconds} ms');
    }, timeout: const Timeout(Duration(minutes: 10)));
  });
  await Hive.close();
}

Future<bool> compareTwoResources(
    Resource originalResource, FhirDb fhirDb, String? pw) async {
  final Resource? dbResource = await fhirDb.get(
      pw: pw,
      resourceType: originalResource.resourceType!,
      id: originalResource.fhirId!);
  final Map<String, dynamic> resource1Json = originalResource.toJson();
  final Map<String, dynamic>? resource2json = dbResource?.toJson();
  resource1Json.remove('meta');
  resource2json?.remove('meta');
  if (!(const DeepCollectionEquality()).equals(resource1Json, resource2json)) {
    return false;
  }
  if (!(const DeepCollectionEquality()).equals(resource2json, resource1Json)) {
    return false;
  }
  return true;
}
14
likes
140
pub points
51%
popularity

Publisher

verified publisherfhirfli.dev

A wrapper for Sembast and SQFlite to enable easy, local and secure storage of fhir resources

Homepage
Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (LICENSE)

Dependencies

collection, fhir, fhir_bulk, hive, path

More

Packages that depend on fhir_db