{"id":21702389,"url":"https://github.com/aphp/cohort360-queryexecutor","last_synced_at":"2026-04-18T06:03:14.715Z","repository":{"id":248115718,"uuid":"822469530","full_name":"aphp/Cohort360-QueryExecutor","owner":"aphp","description":null,"archived":false,"fork":false,"pushed_at":"2025-03-13T09:50:22.000Z","size":642,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-13T10:23:08.466Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aphp.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS.md","dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-07-01T08:05:04.000Z","updated_at":"2025-03-13T09:49:04.000Z","dependencies_parsed_at":"2024-09-17T12:02:28.872Z","dependency_job_id":"a2ff72ad-23ee-477e-8e4b-0e051ae64c61","html_url":"https://github.com/aphp/Cohort360-QueryExecutor","commit_stats":null,"previous_names":["aphp/cohort360-queryexecutor"],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aphp%2FCohort360-QueryExecutor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aphp%2FCohort360-QueryExecutor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aphp%2FCohort360-QueryExecutor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aphp%2FCohort360-QueryExecutor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aphp","download_url":"https://codeload.github.com/aphp/Cohort360-QueryExecutor/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244648226,"owners_count":20487224,"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":[],"created_at":"2024-11-25T21:15:09.930Z","updated_at":"2026-04-18T06:03:14.709Z","avatar_url":"https://github.com/aphp.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"# COHORT REQUESTER / SPARK JOB SERVER\n\n[![Actions Status](https://github.com/aphp/Cohort360-QueryExecutor/workflows/build/badge.svg)](https://github.com/aphp/Cohort360-QueryExecutor/actions)\n[![Coverage Status](https://sonarcloud.io/api/project_badges/measure?project=aphp_Cohort360-QueryExecutor\u0026metric=coverage)](https://sonarcloud.io/component_measures?id=aphp_Cohort360-QueryExecutor\u0026metric=coverage)\n[![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=aphp_Cohort360-QueryExecutor\u0026metric=alert_status)](https://sonarcloud.io/dashboard?id=aphp_Cohort360-QueryExecutor)\n\n[![License: MPL 2.0](https://img.shields.io/badge/License-MPL_2.0-brightgreen.svg)](https://opensource.org/licenses/MPL-2.0)\n\nThe Cohort Requester is a spark application server for querying FHIR data with a set of criteria and return a count or list of patients that match the criteria. \n\n## Quick Start\n\n### 1. Configuration\n\nFill in the configuration file `src/main/resources/application.conf` with the appropriate values.\nOr use environment variables. For local development, you can create a `.env` file at the root of the project:\n\n```bash\n# The URL of the FHIR server \nexport FHIR_URL=http://localhost:XXXX # \"if FHIR local otherwise put the URL of your FHIR server (for a test with a public FHIR #http://hapi.fhir.org/baseR4)\"\n# URL of the associated Django API for callbacks\nexport DJANGO_CALLBACK_URL=http://localhost:8000\n```\n\n### 2. Build\n\nBuild the project with maven:\n```bash\n./mvnw clean package -DskipTests\n```\n\n### 3. Run\n\nRun the application server:\n```bash\njava \\\n  --add-opens=java.base/java.lang=ALL-UNNAMED \\\n  --add-opens=java.base/java.lang.invoke=ALL-UNNAMED \\\n  --add-opens=java.base/java.lang.reflect=ALL-UNNAMED \\\n  --add-opens=java.base/java.io=ALL-UNNAMED \\\n  --add-opens=java.base/java.net=ALL-UNNAMED \\\n  --add-opens=java.base/java.nio=ALL-UNNAMED \\\n  --add-opens=java.base/java.util=ALL-UNNAMED \\\n  --add-opens=java.base/java.util.concurrent=ALL-UNNAMED \\\n  --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED \\\n  --add-opens=java.base/sun.nio.ch=ALL-UNNAMED \\\n  --add-opens=java.base/sun.nio.cs=ALL-UNNAMED \\\n  --add-opens=java.base/sun.security.action=ALL-UNNAMED \\\n  --add-opens=java.base/sun.util.calendar=ALL-UNNAMED \\\n  --add-opens=java.security.jgss/sun.security.krb5=ALL-UNNAMED \\\n  -jar target/cohort-requester.jar\n```\n\nLaunch a query with the following command:\n```bash\ncurl -X POST http://localhost:8090/jobs -H \"Content-Type: application/json\" -d '{\n    \"input\": {\n        \"cohortDefinitionSyntax\": \"{\\\"sourcePopulation\\\":{\\\"caresiteCohortList\\\":[118]},\\\"_type\\\":\\\"request\\\",\\\"request\\\":{\\\"_type\\\":\\\"andGroup\\\",\\\"_id\\\":0,\\\"isInclusive\\\":true,\\\"criteria\\\":[{\\\"_type\\\":\\\"basicResource\\\",\\\"_id\\\":1,\\\"isInclusive\\\":true,\\\"resourceType\\\":\\\"Patient\\\",\\\"filterFhir\\\":\\\"active=true\u0026gender=female\\\",\\\"criteria\\\":[],\\\"dateRangeList\\\":[],\\\"temporalConstraints\\\":[]},{\\\"_type\\\":\\\"basicResource\\\",\\\"_id\\\":2,\\\"isInclusive\\\":true,\\\"resourceType\\\":\\\"Observation\\\",\\\"filterFhir\\\":\\\"code=http://snomed.info/sct|224299000\\\",\\\"criteria\\\":[],\\\"occurrence\\\":{\\\"n\\\":1,\\\"operator\\\":\\\"\u003e=\\\"},\\\"dateRangeList\\\":[],\\\"temporalConstraints\\\":[]}],\\\"dateRangeList\\\":[],\\\"temporalConstraints\\\":[]},\\\"temporalConstraints\\\":[]}\",\n        \"mode\": \"count\"\n    }\n}'\n```\n\n### Check Job Status\n\nYou can list all jobs:\n```bash\ncurl http://localhost:8090/jobs\n```\n\nOr check the status of a specific job using its `jobId` (returned in the POST response):\n```bash\ncurl http://localhost:8090/jobs/\u003cjobId\u003e\n```\n\nTo cancel a job:\n```bash\ncurl -X DELETE http://localhost:8090/jobs/\u003cjobId\u003e\n```\n\n## Job Queries\n\nThe job query format is as follows :\n```json\n{\n    \"input\": {\n        \"cohortDefinitionSyntax\": \"\u003ccohort definition syntax\u003e\",\n        \"mode\": \"\u003cmode\u003e\",\n        \"modeOptions\": {\n           \"details\": \"\u003cdetails\u003e\",\n           \"sampling\": \"\u003csampling\u003e\",\n           \"baseCohortId\": \"\u003cbase cohort id\u003e\"\n        },\n        \"callbackUrl\": \"\u003ccallback url\u003e\"\n    }\n}\n```\n\nwith `mode` being one of the following values:\n- `count` : Return the number of patients that match the criteria of the `cohortDefinitionSyntax`\n- `count_all`: Return the number of patients that match the criteria of the `cohortDefinitionSyntax` and an estimation minimum and maximum bounds\n- `count_with_details`: Return the number of patients that match the criteria of the `cohortDefinitionSyntax` with a detailed count per organization\n- `create`: Create a cohort of patients that match the criteria of the `cohortDefinitionSyntax`\n- `create_diff`: Create a change list from a base cohort of patients (defined in `modeOptions`) and the new/deleted ones that match the criteria of the `cohortDefinitionSyntax`\n\nand `cohortDefinitionSyntax` being a JSON string that represents the criteria described in the [query format section](#query-format).\n\n### Job Response\n\nIf a `callbackUrl` is provided (else the result will be printed in the logs), the response will be sent to the provided URL with the following format:\n```typescript\ntype RESPONSE = {\n    _type: string; // the job mode (count or create)\n    message: string; // the message of the response (usually the job status)\n    groupId: string; // the cohort id in case of a cohort creation job\n    count: number; // the count of patients in case of a count job\n    extra: Map\u003cstring, string\u003e; // extra information about the count job (like details count per organization or per criteria)\n    stack: string; // the stack trace in case of an error\n}\n```\n\n### Query Format\n\nThe query format of the `cohortDefinitionSyntax` field is as follows (described in `typescript`):\n\n```typescript\ntype REQUEST = {\n    sourcePopulation: {\n        caresiteCohortList?: Array\u003cInteger\u003e // Optional list of caresite ids that will be used to filter the resource with the fhir param `_list` \n    },\n    _type: \"request\",\n    request: CRITERIA,\n    resourceType?: string // The fhir resource type of the cohort (Patient being the default)\n} \n\ntype CRITERIA = {\n    _type: \"andGroup\" | \"orGroup\" | \"nAmongM\" | \"basicResource\",\n    _id: Integer, // Unique identifier of the criteria\n    isInclusive: Boolean // If true, the criteria is inclusive, if false, the criteria is exclusive\n}\n\ntype GROUP_CRITERIA = CRITERIA \u0026 {\n    _type: \"andGroup\" | \"orGroup\" | \"nAmongM\", // the type of the group \"and\" or \"or\" or \"at least n matches among subcriterias\"\n    criteria: Array\u003cCRITERIA\u003e, // list of subcriterias (can be basicResource or group)\n    temporalConstraints: Array\u003cTEMPORAL_CONSTRAINT\u003e, // list of temporal constraints between the subcriterias\n    nAmongMOptions: Array\u003cOCCURENCE_CONSTRAINT\u003e // list of occurrence constraints for the nAmongM type\n}\n\ntype BASIC_RESOURCE = CRITERIA \u0026 {\n    _type: \"basicResource\",\n    resourceType: string, // The fhir resource type to filter\n    filterFhir: string, // The fhir query string to filter the resource\n    filterSolr?: string, // The solr query string to filter the resource (if using solr resolver)\n    occurrence?: OCCURENCE_CONSTRAINT, // The occurrence constraint of the resource\n    patientAge?: PATIENT_AGE, // The age constraint of the patient\n    dateRangeList?: Array\u003cDATE_RANGE\u003e, // The date range constraint of the resource\n    encounterDateRange?: DATE_RANGE // The date range constraint of the related encounter\n    uniqueFields?: Array\u003cUNIQUE_FIELD\u003e // The unique fields of the resource to count the patients\n}\n\ntype PATIENT_AGE = {\n    minAge?: string, // with the format {year}-{month}-{day}, eg. for someone of 21 years old this would be 21-0-0\n    maxAge?: string, // with the format {year}-{month}-{day}, eg. for someone of 21 years old this would be 21-0-0\n    datePreference?: string[], // resource reference field of the date to calculate the age\n    dateIsNotNull?: boolean\n}\n\ntype DATE_RANGE = {\n    minDate?: string, // with the standard format {year}-{month}-{day}, eg. for 2024-01-25\n    maxDate?: string, // with the standard format {year}-{month}-{day}, eg. for 2024-01-25\n    datePreference?: string[], // resource reference field of the date to filter\n    dateIsNotNull?: boolean\n}\n\ntype UNIQUE_FIELD = {\n    name?: string, // The fhir resource field to verify, for now only codes are supported and it is not need to fill this field which is ignored\n    operator: string, // The operator to use for the verification\n    n: number // The number of unique values\n}\n\ntype TEMPORAL_CONSTRAINT = {\n    idList: string | Array\u003cnumber\u003e,\n    constraintType: \"sameEncounter\" | \"differentEncounter\" | \"directChronologicalOrdering\" | \"sameEpisodeOfCare\",\n    occurrenceChoiceList?: Array\u003c{_id: number, occurrenceChoice: string}\u003e,\n    timeRelationMinDuration?: TEMPORAL_CONSTRAINT_DURATION,\n    timeRelationMaxDuration?: TEMPORAL_CONSTRAINT_DURATION,\n    datePreferenceList?: Array\u003c{_id: number, occurrenceChoice: string}\u003e,\n    filteredCriteriaIdList?: string | Array\u003cnumber\u003e,\n    dateIsNotNullList?: boolean | {_id: number, dateIsNotNull: boolean}\n}\n\ntype TEMPORAL_CONSTRAINT_DURATION = {\n    years?: number,\n    months?: number,\n    days?: number,\n    hours?: number,\n    minutes?: number,\n    seconds?: number\n}\n\ntype OCCURENCE_CONSTRAINT = {\n    n: number,\n    operator: string,\n    sameEncounter?: boolean,\n    sameDay?: boolean,\n    timeDelayMin?: boolean,\n    timeDelayMax?: boolean\n}\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faphp%2Fcohort360-queryexecutor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faphp%2Fcohort360-queryexecutor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faphp%2Fcohort360-queryexecutor/lists"}