/**
  DBT
**/

CREATE SCHEMA {{ dbt_schema }};

/**
  PROJECT
**/

CREATE TABLE {{ dbt_schema }}.{{ dbt_meta_table }} AS SELECT '{{ project_id }}' AS project_id, '{{ project_url }}' as url, '{{ db_type}}' as db_type;

/**
  EXTENSIONS
**/

CREATE EXTENSION IF NOT EXISTS "uuid-ossp" SCHEMA {{ dbt_schema }};
CREATE EXTENSION IF NOT EXISTS "postgres_fdw" SCHEMA {{ dbt_schema }};
CREATE EXTENSION IF NOT EXISTS "oracle_fdw" SCHEMA {{ dbt_schema }};
CREATE EXTENSION IF NOT EXISTS "tds_fdw" SCHEMA {{ dbt_schema }};

/**
  TYPES
**/

CREATE TYPE {{ dbt_schema }}.fhir_v4 AS ENUM (
    'Account', 'ActivityDefinition', 'AdverseEvent', 'AllergyIntolerance', 'Appointment', 'AppointmentResponse', 'AuditEvent', 'Basic', 'Binary', 'BiologicallyDerivedProduct', 'BodyStructure', 'Bundle', 'CapabilityStatement', 'CarePlan', 'CareTeam', 'CatalogEntry', 'ChargeItem', 'ChargeItemDefinition', 'Claim', 'ClaimResponse', 'ClinicalImpression', 'CodeSystem', 'Communication', 'CommunicationRequest', 'CompartmentDefinition', 'Composition', 'ConceptMap', 'Condition', 'Consent', 'Contract', 'Coverage', 'CoverageEligibilityRequest', 'CoverageEligibilityResponse', 'DetectedIssue', 'Device', 'DeviceDefinition', 'DeviceMetric', 'DeviceRequest', 'DeviceUseStatement', 'DiagnosticReport', 'DocumentManifest', 'DocumentReference', 'EffectEvidenceSynthesis', 'Encounter', 'Endpoint', 'EnrollmentRequest', 'EnrollmentResponse', 'EpisodeOfCare', 'EventDefinition', 'Evidence', 'EvidenceVariable', 'ExampleScenario', 'ExplanationOfBenefit', 'FamilyMemberHistory', 'Flag', 'Goal', 'GraphDefinition', 'Group', 'GuidanceResponse', 'HealthcareService', 'ImagingStudy', 'Immunization', 'ImmunizationEvaluation', 'ImmunizationRecommendation', 'ImplementationGuide', 'InsurancePlan', 'Invoice', 'Library', 'Linkage', 'List', 'Location', 'Measure', 'MeasureReport', 'Media', 'Medication', 'MedicationAdministration', 'MedicationDispense', 'MedicationKnowledge', 'MedicationRequest', 'MedicationStatement', 'MedicinalProduct', 'MedicinalProductAuthorization', 'MedicinalProductContraindication', 'MedicinalProductIndication', 'MedicinalProductIngredient', 'MedicinalProductInteraction', 'MedicinalProductManufactured', 'MedicinalProductPackaged', 'MedicinalProductPharmaceutical', 'MedicinalProductUndesirableEffect', 'MessageDefinition', 'MessageHeader', 'MolecularSequence', 'NamingSystem', 'NutritionOrder', 'Observation', 'ObservationDefinition', 'OperationDefinition', 'OperationOutcome', 'Organization', 'OrganizationAffiliation', 'Parameters', 'Patient', 'PaymentNotice', 'PaymentReconciliation', 'Person', 'PlanDefinition', 'Practitioner', 'PractitionerRole', 'Procedure', 'Provenance', 'Questionnaire', 'QuestionnaireResponse', 'RelatedPerson', 'RequestGroup', 'ResearchDefinition', 'ResearchElementDefinition', 'ResearchStudy', 'ResearchSubject', 'RiskAssessment', 'RiskEvidenceSynthesis', 'Schedule', 'SearchParameter', 'ServiceRequest', 'Slot', 'Specimen', 'SpecimenDefinition', 'StructureDefinition', 'StructureMap', 'Subscription', 'Substance', 'SubstanceNucleicAcid', 'SubstancePolymer', 'SubstanceProtein', 'SubstanceReferenceInformation', 'SubstanceSourceMaterial', 'SubstanceSpecification', 'SupplyDelivery', 'SupplyRequest', 'Task', 'TerminologyCapabilities', 'TestReport', 'TestScript', 'ValueSet', 'VerificationResult', 'VisionPrescription'
);

/**
  FHIR FUNCTIONS
**/

CREATE FUNCTION {{ dbt_schema }}.canonical_table_name(
    table_ref regclass
) RETURNS text as $$
DECLARE
    canonical_name text;
BEGIN
    SELECT relnamespace::regnamespace::text || '.' || relname INTO canonical_name from pg_catalog.pg_class where oid=table_ref;
    RETURN canonical_name;
END;
$$ LANGUAGE plpgsql IMMUTABLE;

COMMENT ON FUNCTION {{ dbt_schema }}.canonical_table_name (table_ref regclass) IS 'Returns a canonical table name';

CREATE FUNCTION {{ dbt_schema }}.fhir_id(
    table_ref   regclass,
    ref         text
) RETURNS uuid AS $$
DECLARE
    namespace uuid;
    table_name text;
    table_namespace uuid;
BEGIN
    SELECT project_id INTO namespace FROM {{ dbt_schema }}.{{ dbt_meta_table }};
    table_name := {{ dbt_schema }}.canonical_table_name(table_ref);
    table_namespace := {{ dbt_schema }}.uuid_generate_v5(namespace, table_name);
    RETURN {{ dbt_schema }}.uuid_generate_v5(table_namespace, ref);
END;
$$ LANGUAGE plpgsql IMMUTABLE;

COMMENT ON FUNCTION {{ dbt_schema }}.fhir_id (table_ref regclass, ref text) IS 'Returns a fhir id';

CREATE FUNCTION {{ dbt_schema }}.fhir_ref(
    resource_type   {{ dbt_schema }}.fhir_v4,
    table_ref       regclass,
    ref             text
) RETURNS text AS $$
BEGIN
    RETURN resource_type || '/' || {{ dbt_schema }}.fhir_id(table_ref, ref);
END;
$$ LANGUAGE plpgsql IMMUTABLE;

COMMENT ON FUNCTION {{ dbt_schema }}.fhir_ref (resource_type {{ dbt_schema }}.fhir_v4, table_ref regclass, ref text) IS 'Returns a fhir reference';

/**
  PROJECT USER
**/

GRANT USAGE ON SCHEMA {{ dbt_schema }} TO "{{ role }}";
GRANT SELECT ON TABLE {{ dbt_schema }}.{{ dbt_meta_table }} TO "{{ role }}";
GRANT CREATE ON SCHEMA {{ dbt_schema }} TO "{{ role }}";
GRANT EXECUTE ON FUNCTION {{ dbt_schema }}.fhir_id TO "{{ role }}";
GRANT EXECUTE ON FUNCTION {{ dbt_schema }}.fhir_ref TO "{{ role }}";
GRANT USAGE ON TYPE {{ dbt_schema }}.fhir_v4 TO "{{ role }}";
ALTER DEFAULT PRIVILEGES IN SCHEMA {{ dbt_schema }} GRANT ALL PRIVILEGES ON TABLES TO "{{ role }}";
ALTER DEFAULT PRIVILEGES IN SCHEMA {{ dbt_schema }} GRANT ALL PRIVILEGES ON FUNCTIONS TO "{{ role }}";

GRANT CREATE ON DATABASE "{{ database }}" TO "{{ role }}";
CREATE SCHEMA {{ dbt_schema }}_fhir;
CREATE SCHEMA {{ dbt_schema }}_omop;

GRANT USAGE ON SCHEMA {{ dbt_schema }}_fhir TO "{{ role }}";
GRANT USAGE ON SCHEMA {{ dbt_schema }}_omop TO "{{ role }}";
GRANT CREATE ON SCHEMA {{ dbt_schema }}_fhir TO "{{ role }}";
GRANT CREATE ON SCHEMA {{ dbt_schema }}_omop TO "{{ role }}";
ALTER DEFAULT PRIVILEGES IN SCHEMA {{ dbt_schema }}_fhir GRANT ALL PRIVILEGES ON TABLES TO "{{ role }}";
ALTER DEFAULT PRIVILEGES IN SCHEMA {{ dbt_schema }}_omop GRANT ALL PRIVILEGES ON TABLES TO "{{ role }}";
