Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend API to save and load cohort and dataselection #374

Open
juliangruendner opened this issue Sep 20, 2024 · 14 comments · May be fixed by #459
Open

Extend API to save and load cohort and dataselection #374

juliangruendner opened this issue Sep 20, 2024 · 14 comments · May be fixed by #459
Assignees
Labels
enhancement New feature or request
Milestone

Comments

@juliangruendner
Copy link
Contributor

juliangruendner commented Sep 20, 2024

Update: 2025-02-14: Please see this comment for the current state of discussion.

Extend API to save and load cohort and dataselection.

The API should be extended to allow the saving and loading of a cohort selection (CCDL) and a dataselection (dataExtraction part CRTDL).

Further it should be possible to save a CRTDL, which combines the cohort seleection and dataselection parts.

For this the endpoint
POST /query/{queryId}/saved
should be changed to
POST /query/saved and accept the following body:

{
"label": "my-query-1",
"comment": "I wanted to see how many patients I could find for my study XYZ",
"totalNumberOfPatients": 12345
"ccdlID": "id-of-ccdl",
"dataExtractionID": "id-of-dataExtractionPart"
}

Response: analogous to current saved Reponse, but with additional Id of saved query

{
  "queryId": 123123213,
  "used": 2,
  "total": 10
}

IMPORTANT: It should also be possible to POST a query with a query ID from a query not in /cohort-selection, but in /query (as in a query that has been sent)
Further the endpoint /query/by-user/{userId} should still return the totalNumberOfPatients if a query has been previously saved with a query from query instead of cohort-selection

This future post from the UI will then require a ccdlID and a dataExtractionId to be supplied.

For this two new endpoints should be created, one to post each part to the backend.

  1. Cohort Selection

POST /cohort-selection
Body: = CCDL (equivalent to what is currently send to query)

{
    "version": "http://to_be_decided.com/draft-1/schema#",
    "display": "Ausgewählte Merkmale",
    "inclusionCriteria": [
        [
            {
                "termCodes": [
                    {
                        "code": "263495000",
                        "system": "http://snomed.info/sct",
                        "display": "Geschlecht"
                    }
                ],
                "context": {
                    "code": "Patient",
                    "system": "fdpg.mii.cds",
                    "version": "1.0.0",
                    "display": "Patient"
                },
                "valueFilter": {
                    "selectedConcepts": [
                        {
                            "code": "female",
                            "display": "Female",
                            "system": "http://hl7.org/fhir/administrative-gender"
                        },
                        {
                            "code": "male",
                            "display": "Male",
                            "system": "http://hl7.org/fhir/administrative-gender"
                        }
                    ],
                    "type": "concept"
                }
            }
        ]
    ]
}

Response: analogous to current template endpoint, if successfull 201OK with Location Header and link to successfully stored cohort-selection

  1. Data Selection

POST /data-selection
Body: the dataExtraction part of the CRTDL = https://github.com/medizininformatik-initiative/clinical-resource-transfer-definition-language
example:

{
  "attributeGroups": [
    {
      "groupReference": "https://www.medizininformatik-initiative.de/fhir/core/modul-labor/StructureDefinition/ObservationLab",
      "attributes": [
        {
          "attributeRef": "Observation.code",
          "mustHave": false
        },
        {
          "attributeRef": "Observation.value",
          "mustHave": true
        }
      ],
      "filter": [
        {
          "type": "token",
          "name": "code",
          "codes": [
            {
              "code": "718-7",
              "system": "http://loinc.org",
              "display": "Hemoglobin [Mass/volume] in Blood"
            },
            {
              "code": "33509-1",
              "system": "http://loinc.org",
              "display": "Hemoglobin [Mass/volume] in Body fluid"
            }
          ]
        },
        {
          "type": "date",
          "name": "date",
          "start": "2021-09-09",
          "end": "2021-10-09"
        }
      ]
    }
  ]
}

Response: analogous to current template endpoint, if successfull 201OK with Location Header and link to successfully stored data-selection

Update 2025-02-17

Following the discussion in this comment ff.
Modified 2025-02-26: Changed Dataquery json slightly (don't put label/comment/nrofresults in another object) and move saved query slots endpoint (not sure if this is still needed anyways...)

The preliminary OpenAPI description
openapi: 3.1.1
info:
  title: Dataportal Backend REST API
  license:
    name: Apache 2.0
    url: http://www.apache.org/licenses/LICENSE-2.0.html
  version: 7.0.0
externalDocs:
  description: Check out the github repository
  url: https://github.com/medizininformatik-initiative/feasibility-backend
servers:
  - url: https://to.be.defined
    variables:
      basePath:
        default: /api/v5
tags:
  - name: dataquery
    description: operations for dataqueries
  - name: feasibility
    description: operations for feasibility queries
  - name: terminology
    description: operations to work with the ontology
  - name: codeable concepts
    description: operations on codeable concepts
  - name: dse
    description: Data Selection and Extraction
  - name: intrinsics
    description: Offers intrinsic information about this application.
paths:
  /query/data:
    post:
      tags:
        - dataquery
      summary: Store a dataquery in the backend.
      description: The query will only be stored, nothing will be dispatched. Does not have to pass any validation and may be incomplete. May or may not contain result.
      operationId: storeDataQuery
      requestBody:
        description: Dataquery
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Dataquery"
        required: true
      responses:
        201:
          description: Dataquery successfully stored
          headers:
            Location:
              description: Path to the result of your newly created dataquery
              schema:
                type: string
                format: url
        401:
          description: Unauthorized - please login first
        422:
          description: Invalid input
      security:
        - dataportal_auth:
            - user
    get:
      tags:
        - dataquery
      summary: Get the list of the calling users dataqueries
      description: This returns a list with basic information about the queries. Id, label (if present) and creation date. Basically for all parameters I'm not sure if we need them (at least right away)
      operationId: getDataQueryList
      parameters:
        - name: filter
          in: query
          description: filters query...either for those with linked feasibility and or results? Or by name?
          required: false
          schema:
            type: string
            enum:
              - feasibility
        - name: skip-validation
          in: query
          description: If true, do not validate the query and do not include a list of invalid terms. TODO - maybe invert this?
          required: false
          schema:
            type: boolean
            default: false
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/DataQueryListEntry"
        401:
          description: Unauthorized - please login first
      security:
        - dataportal_auth:
            - user
  /query/data/by-user/{userId}:
    get:
      tags:
        - dataquery
      summary: Finds query summary (id, label, lastModified) of all queries of one user
      operationId: findDataQueriesByUser
      parameters:
        - name: userId
          in: path
          description: User to filter by (keycloak id)
          required: true
          schema:
            type: string
        - name: skip-validation
          in: query
          description: If true, do not validate the query and do not include a list of invalid terms. TODO - maybe invert this?
          required: false
          schema:
            type: boolean
            default: false
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/DataQueryListEntry"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: User not found
      security:
        - dataportal_auth:
            - admin
  /query/data/{queryId}:
    get:
      tags:
        - dataquery
      summary: Read dataquery by ID
      description: Returns a single dataquery.
      operationId: getDataQueryById
      parameters:
        - name: queryId
          in: path
          description: ID of query to return
          required: true
          schema:
            type: integer
            format: int64
        - name: skip-validation
          in: query
          description: If true, do not validate the query and do not include a list of invalid terms
          required: false
          schema:
            type: boolean
            default: false
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Dataquery"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Query not found
      security:
        - dataportal_auth:
            - user
    put:
      tags:
        - dataquery
      summary: Update a dataquery in the backend.
      description: The query will be updated. It must be provided completely, there are no partial updates.
      operationId: updateDataQuery
      requestBody:
        description: CRTDL
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Dataquery"
        required: true
      responses:
        204:
          description: Dataquery successfully updated
          content: {}
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: The dataquery could not be found
      security:
        - dataportal_auth:
            - user
    delete:
      tags:
        - dataquery
      summary: Delete a dataquery
      operationId: deleteDataQuery
      parameters:
        - name: queryId
          in: path
          required: true
          schema:
            type: integer
            format: int64
      responses:
        204:
          description: No content
          content:
            {}
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: The dataquery could not be found
      security:
        - dataportal_auth:
            - user
  /query/data/{queryId}/crtdl:
    get:
      tags:
        - dataquery
      summary: Read dataquery CRTDL by ID
      description: Returns only the CRTDL part of a dataquery
      operationId: getDataQueryCRTDLById
      parameters:
        - name: queryId
          in: path
          description: ID of query to return
          required: true
          schema:
            type: integer
            format: int64
        - name: skip-validation
          in: query
          description: If true, do not validate the query and do not include a list of invalid terms
          required: false
          schema:
            type: boolean
            default: false
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CRTDL"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Query not found
      security:
        - dataportal_auth:
            - admin
            - user
  /query/feasibility:
    post:
      tags:
        - feasibility
      summary: Create a feasibility query in the broker
      description: The query will be spawned in the broker and directly be dispatched.
      operationId: runQuery
      parameters:
      requestBody:
        description: Structured query to create and dispatch
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/StructuredQuery"
        required: true
      responses:
        201:
          description: Query successfully dispatched
          headers:
            Location:
              description: Path to the result of your newly created query
              schema:
                type: string
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        422:
          description: Invalid input
        429:
          description: Too many requests in a given amount of time (configurable)
        500:
          description: Dispatch error
      security:
        - dataportal_auth:
            - user
  /query/feasibility/{queryId}/summary-result:
    get:
      tags:
        - feasibility
      summary: Read query result summary by query ID
      description: Returns the aggregated results to a query. There is no breakdown by site. So, the resultLines parameter of the response is de facto an array of QueryResultLines, but it will always be empty in this case.
      operationId: getQueryResultSummary
      parameters:
        - name: queryId
          in: path
          description: ID of query for which the results are requested
          required: true
          schema:
            type: integer
            format: int64
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/QueryResultSummary"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Query not found
        429:
          description: Too many requests
      security:
        - dataportal_auth:
            - admin
            - user
  /query/feasibility/{queryId}/detailed-result:
    get:
      tags:
        - feasibility
      summary: Read query result by ID
      description: Returns results to query with the real site names - admin rights required
      operationId: getQueryResultDetailed
      parameters:
        - name: queryId
          in: path
          description: ID of query for which the results are requested
          required: true
          schema:
            type: integer
            format: int64
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/QueryResult"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Query not found
      security:
        - dataportal_auth:
            - admin
  /query/feasibility/{queryId}/detailed-obfuscated-result:
    get:
      tags:
        - feasibility
      summary: Read obfuscated query result by ID
      description: Returns all results to query with the site names obfuscated.
      operationId: getQueryResultDetailedObfuscated
      parameters:
        - name: queryId
          in: path
          description: ID of query for which the results are requested
          required: true
          schema:
            type: integer
            format: int64
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/QueryResultObfuscated"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Query not found
        429:
          description: Too many requests
      security:
        - dataportal_auth:
            - admin
            - user
  /query/feasibility/detailed-obfuscated-result-rate-limit:
    get:
      tags:
        - feasibility
      summary: get the rate limit for detailed obfuscated results
      operationId: getDetailedObfuscatedResultRateLimit
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/QueryResultRateLimit"
  /query/data/query-slots:
    get:
      tags:
        - dataquery
      summary: Show how many data query slots a user already used and how many he has left.
      operationId: getDataQuerySlots
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataQuerySlots"
      security:
        - dataportal_auth:
            - user
  /query/validate:
    post:
      tags:
        - dataquery
      summary: Validates a submitted CRTDL or just CCDL? to check for schema violations or invalid termCodes
      description: It could be useful to split this in ccdl and dataquery or at least offer a parameter to determine which should be checked.
      operationId: validateQuery
      requestBody:
        description: Query to validate
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CRTDL"
        required: true
      responses:
        200:
          description: Query adheres to json schema. If invalid termCodes are present, they will be in the response.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/CRTDL"
        400:
          description: Query does not adhere to json schema
        401:
          description: Unauthorized - please login first
  /terminology/search/filter:
    get:
      tags:
        - terminology
      summary: Get the list of available filters
      operationId: getFilters
      responses:
        200:
          description: Ok, return the list of available filters
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Filter"
  /terminology/systems:
    get:
      tags:
        - terminology
      summary: Get the mapping of system urls to display names
      operationId: getTerminologySystems
      responses:
        200:
          description: System mapping file found and readable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TerminologySystems"
  /terminology/entry/search:
    get:
      tags:
        - terminology
      summary: Parametrized search in the configured elastic search service.
      operationId: searchEntry
      parameters:
        - name: searchterm
          in: query
          description: The term to search for. In case of an empty searchterm, return the first page of the whole index, sorted alphabetically
          schema:
            type: string
          examples: Diabetes Mellitus
        - name: contexts
          in: query
          description: Limit the search to any of the given contexts
          schema:
            type: array
            items:
              type: string
              example: Diagnosis
          style: form
          explode: false
        - name: terminologies
          in: query
          description: Limit the search to a any of the given terminologies
          schema:
            type: array
            items:
              type: string
              example: ICD10
          style: form
          explode: false
        - name: kds-modules
          in: query
          description: Limit the search to any of the given KDS modules
          schema:
            type: array
            items:
              type: string
              example: Condition
          style: form
          explode: false
        - name: criteria-sets
          in: query
          description: Limit the search to certain criteria sets (specified via url)
          schema:
            type: array
            items:
              type: string
              example: http://fhir.de/CodeSystem/bfarm/icd-10-gm
          style: form
          explode: false
        - name: availability
          in: query
          description: Limit the search to available items? (Maybe better invert this one to make this the default?)
          schema:
            type: boolean
          example: true
        - name: page-size
          in: query
          description: How many results shall be returned per page
          schema:
            type: integer
          example: 10
        - name: page
          in: query
          description: Which page shall be returned
          schema:
            type: integer
          example: 42
      responses:
        200:
          description: Ok, return the list of results for the search
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ElasticSearchResult"
  /terminology/entry/{id}/relations:
    get:
      tags:
        - terminology
      summary: Get the detailed entry for a criterion, containing children and translations
      operationId: getEntryById
      parameters:
        - name: id
          in: path
          description: The id (contextualized termcode hash) of the entry that shall be retrieved
          required: true
          schema:
            type: string
            example: 203e04cd-4f0a-321b-b1ad-9ec6d211e0a8
      responses:
        200:
          description: Entry found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RelationsEntry"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Entry not found
  /terminology/entry/{id}:
    get:
      tags:
        - terminology
      summary: Get the detailed entry for a criterion, containing children and translations
      description: This should be in the getEntryById call, but for better distinction between the return values it is listed seperately here
      operationId: getEntriesById
      parameters:
        - name: id
          in: path
          description: The ids (contextualized termcode hash) of the entries that shall be retrieved
          required: true
          schema:
            type: string
            example: 203e04cd-4f0a-321b-b1ad-9ec6d211e0a8
      responses:
        200:
          description: Entry found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ElasticSearchResultEntry"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Entry not found
  /terminology/criteria-profile-data:
    get:
      tags:
        - terminology
      summary: Get the profile data for criteria, containing uiProfile context and termCodes
      description: This should return all the information needed to build criteria in the frontend.
      operationId: getEntriesByIdsWithDetail
      parameters:
        - name: ids
          in: query
          style: form
          explode: false
          description: A comma-separated list of IDs (contextualized termcode hashes) of the entries that shall be retrieved.
          required: true
          schema:
            type: string
            example: 203e04cd-4f0a-321b-b1ad-9ec6d211e0a8,203e04cd-4f0a-321b-b1ad-9ec6d211e0a9
      responses:
        200:
          description: Entries found. May contain empty entries if some were not found.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/CriteriaProfileData"
        401:
          description: Unauthorized - please login first.
        403:
          description: Forbidden - insufficient access rights.
  /codeable-concept/entry/search:
    get:
      tags:
        - codeable concepts
      summary: Search for codeable concepts by code or display. Optionally filter by value sets
      operationId: searchCodeableConcepts
      parameters:
        - name: searchterm
          in: query
          description: The term to search for. In case of an empty searchterm, return the first page of the whole index, sorted alphabetically
          schema:
            type: string
          example: Diabetes Mellitus
        - name: value-sets
          in: query
          description: Limit the search to certain value sets (specified via url)
          schema:
            type: array
            items:
              type: string
              example: http://fhir.de/CodeSystem/bfarm/icd-10-gm
          style: form
          explode: false
        - name: page-size
          in: query
          description: How many results shall be returned per page
          schema:
            type: integer
          example: 10
        - name: page
          in: query
          description: Which page shall be returned
          schema:
            type: integer
          example: 42
      responses:
        200:
          description: Ok, return the page of results
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CodeableConceptSearchResult"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
  /codeable-concept/entry:
    get:
      tags:
        - codeable concepts
      summary: Retrieve Codeable Concepts by their ids
      operationId: getCodeableConceptsByCode
      parameters:
        - name: ids
          in: query
          style: form
          explode: false
          description: The ids (contextualized termcode hash) of the entry that shall be retrieved
          required: true
          schema:
            type: string
            example: 203e04cd-4f0a-321b-b1ad-9ec6d211e0a8,203e04cd-4f0a-321b-b1ad-9ec6d211e0a9
      responses:
        200:
          description: Ok, return the codeable concept
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CodeableConceptEntry"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Entry not found
  /dse/profile-tree:
    get:
      tags:
        - dse
      summary: Get the complete DSE profile tree
      description: This can not be filtered or paginated or anything since for now it is rather small. All filtering will be done in the frontend for now. Might change if problems with that approach occur.
      operationId: getProfileTree
      responses:
        200:
          description: Profile tree file found and readable
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProfileTreeNode"
  /dse/profile-data:
    get:
      tags:
        - dse
      summary: Get the profile data for the submitted ids
      description: Get profile data for all submitted ids. If a profile is not found, an error message will be supplied.
      operationId: getProfileData
      parameters:
        - name: ids
          in: query
          style: form
          explode: false
          description: A comma-separated list of IDs (here - mostly URLs) of the entries that shall be retrieved.
          required: true
          schema:
            type: string
            example: https://www.medizininformatik-initiative.de/fhir/core/modul-labor/StructureDefinition/ObservationLab,https://www.medizininformatik-initiative.de/fhir/core/modul-prozedur/StructureDefinition/Procedure
      responses:
        200:
          description: Success, returning profiles - may contain profiles with error messages
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProfileDataList"
  /actuator/health:
    get:
      summary: Offers health information about this application.
      description: ''
      operationId: ''
      responses:
        200:
          description: Successful health information.
          content:
            application/vnd.spring-boot.actuator.v3+json:
              examples:
                Healthy Application:
                  value: |-
                    {
                        "status": "UP"
                    }
      tags:
        - intrinsics
components:
  schemas:
    Dataquery:
      type: object
      required:
        - info
        - crtdl
      properties:
        label:
          type: string
          examples:
            - my query
        comment:
          type: string
          examples:
            - this can be a longer text explaining what this query is for
        totalNumberOfResults:
          type: integer
        crtdl:
          type: object
          $ref: "#/components/schemas/CRTDL"
    CRTDL:
      type: object
      properties:
        display:
          type: string
          examples:
            - Example CRTDL
        cohortDefinition:
          type: object
          $ref: "#/components/schemas/StructuredQuery"
        dataExtraction:
          type: object
          $ref: "#/components/schemas/DataExtractionQuery"
    DataExtractionQuery:
      type: object
      properties:
        id:
          type: string
          examples:
            - 123
        attributeGroups:
          type: array
          items:
            type: string
            examples:
              - to be done correctly...for now just a placeholder because it doesn't matter for this conversation
    DataQueryListEntry:
      type: object
      required:
        - id
        - label
      properties:
        id:
          type: integer
          format: int64
        label:
          type: string
        comment:
          type: string
        createdAt:
          type: string
          format: date-time
        totalNumberOfResults:
          type: integer
        ccdl:
          type: object
          properties:
            exists:
              type: boolean
            isValid:
              type: boolean
        dataSelection:
          type: object
          properties:
            exists:
              type: boolean
            isValid:
              type: boolean
    Query:
      type: object
      required:
        - id
        - content
      properties:
        id:
          type: integer
          format: int64
        content:
          $ref: "#/components/schemas/StructuredQuery"
        label:
          type: string
        results:
          $ref: "#/components/schemas/QueryResult"
    QueryResultSummary:
      type: object
      properties:
        totalNumberOfPatients:
          type: integer
          format: int64
        queryId:
          type: string
        resultLines:
          type: array
          items:
            $ref: "#/components/schemas/QueryResultLine"
    QueryResultObfuscated:
      type: object
      properties:
        totalNumberOfPatients:
          type: integer
          format: int64
        queryId:
          type: string
        resultLines:
          type: array
          items:
            $ref: "#/components/schemas/QueryResultLineObfuscated"
    QueryResult:
      type: object
      properties:
        totalNumberOfPatients:
          type: integer
          format: int64
        queryId:
          type: string
        resultLines:
          type: array
          items:
            $ref: "#/components/schemas/QueryResultLine"
    QueryResultLine:
      type: object
      required:
        - siteName
        - numberOfPatients
      properties:
        siteName:
          type: string
        numberOfPatients:
          type: integer
          format: int64
    QueryResultLineObfuscated:
      type: object
      required:
        - siteName
        - numberOfPatients
      properties:
        siteName:
          type: string
          description: obfuscated site name
        numberOfPatients:
          type: integer
          format: int64
    QueryResultRateLimit:
      type: object
      properties:
        limit:
          type: number
          format: int64
        remaining:
          type: number
          format: int64
    StructuredQuery:
      type: object
      required:
        - version
        - inclusionCriteria
      properties:
        version:
          type: string
          format: uri
          description: The json schema version
          examples:
            - http://to_be_decided.com/draft-1/schema#
        display:
          type: string
          examples:
            - foobar
        inclusionCriteria:
          type: array
          items:
            $ref: "#/components/schemas/CriterionList"
        exclusionCriteria:
          type: array
          items:
            $ref: "#/components/schemas/CriterionList"
    DataQuerySlots:
      type: object
      required:
        - used
        - total
      properties:
        used:
          type: integer
          description: The amount of used dataquery slots for a user.
          examples:
            - 2
        total:
          type: integer
          description: The total amount of dataquery slots per user.
          examples:
            - 10
    TermCode:
      description: The termCode defines a concept based on a coding system (i.e. LOINC). The triplet of code, system and version identify the concept.
      type: object
      required:
        - code
        - system
        - display
      properties:
        code:
          type: string
          examples:
            - 119373006
        system:
          type: string
          examples:
            - http://snomed.info/sct
        version:
          type: string
          examples:
            - http://snomed.info/sct/900000000000207008/version/20210731
        display:
          type: string
          examples:
            - Amniotic fluid specimen (specimen)
    beforeDate:
      type: string
      format: date-time
    afterDate:
      type: string
      format: date-time
    TimeRestriction:
      anyOf:
        - $ref: "#/components/schemas/beforeDate"
        - $ref: "#/components/schemas/afterDate"
    Unit:
      type: object
      required:
        - code
        - display
      properties:
        code:
          type: string
        display:
          type: string
    AttributeFilter:
      type: object
      description: An AttributeFilter requires different properties, depending on the type. Please refer to the JSON Schema for this.
      required:
        - type
      properties:
        attributeCode:
          $ref: "#/components/schemas/TermCode"
    ValueFilter:
      type: object
      description: A ValueFilter requires different properties, depending on the type. Please refer to the JSON Schema for this.
      required:
        - type
      properties:
        type:
          type: string
          enum:
            - concept
            - quantity-comparator
            - quantity-range
        selectedConcepts:
          type: array
          items:
            $ref: "#/components/schemas/TermCode"
        comparator:
          type: string
          enum:
            - eq
            - ue
            - le
            - lt
            - ge
            - gt
        unit:
          $ref: "#/components/schemas/Unit"
        value:
          type: number
          format: double
        minValue:
          type: number
          format: double
        maxValue:
          type: number
          format: double
    Criterion:
      type: object
      required:
        - termCodes
      properties:
        termCodes:
          type: array
          items:
            $ref: "#/components/schemas/TermCode"
        attributeFilters:
          type: array
          items:
            $ref: "#/components/schemas/AttributeFilter"
        valueFilter:
          $ref: "#/components/schemas/ValueFilter"
        timeRestriction:
          $ref: "#/components/schemas/TimeRestriction"
        issues:
          type: array
          items:
            $ref: "#/components/schemas/ValidationIssue"
    CriterionList:
      type: array
      items:
        $ref: "#/components/schemas/Criterion"
    ContextualizedTermCodeList:
      type: object
      properties:
        contextualizedTermCodes:
          type: array
          items:
            $ref: "#/components/schemas/ContextualizedTermCode"
    ContextualizedTermCode:
      type: object
      properties:
        termcode:
          $ref: "#/components/schemas/TermCode"
        context:
          $ref: "#/components/schemas/TermCode"
    ValidationIssue:
      type: object
      required:
        - code
        - detail
      properties:
        code:
          type: string
          examples:
            - VAL-20001
        detail:
          type: string
          examples:
            - The combination of context and termcode(s) is not found.
    TranslationEntry:
      type: object
      required:
        - language
        - value
      properties:
        language:
          type: string
          examples:
            - de-DE
            - en-US
        value:
          type: string
          examples:
            - translated entry
    ElasticSearchResult:
      type: object
      properties:
        totalHits:
          type: integer
          examples:
            - 42
        results:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchResultEntry"
    RelationsEntry:
      type: object
      properties:
        display:
          $ref: "#/components/schemas/DisplayEntry"
        parents:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchRelationEntry"
        children:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchRelationEntry"
        relatedTerms:
          type: array
          items:
            $ref: "#/components/schemas/ElasticSearchRelationEntry"
    ElasticSearchResultEntry:
      type: object
      properties:
        display:
          $ref: "#/components/schemas/DisplayEntry"
        id:
          type: string
          format: uuid
          examples:
            - 203e04cd-4f0a-321b-b1ad-9ec6d211e0a8
        availability:
          description: Not sure if we want this as numeric value, percentage or just boolean?
          type: integer
          minimum: 0
          examples:
            - 119578
        context:
          type: string
          examples:
            - Diagnosis
        terminology:
          type: string
          examples:
            - icd-10
        termcode:
          type: string
          examples:
            - E10-E14
        kdsModule:
          type: string
          examples:
            - Condition
        selectable:
          type: boolean
          examples:
            - true
    ElasticSearchTranslationEntry:
      type: object
      properties:
        lang:
          type: string
          examples:
            - en
        value:
          type: string
          examples:
            - Diabetes Mellitus
    ElasticSearchRelationEntry:
      type: object
      properties:
        name:
          type: string
          examples:
            - Endokrine, Ernährungs- und Stoffwechselerkrankungen
        contextualizedTermcodeHash:
          type: string
          examples:
            - c55d0d62-6c47-30b0-94b2-afa383ce35f7
    Filter:
      type: object
      properties:
        name:
          type: string
          examples:
            - Terminology
        values:
          type: array
          items:
            $ref: "#/components/schemas/FilterValue"
          examples:
            - ICD10
            - SNOMED
            - LOINC
    FilterValue:
      type: string
      examples:
        - icd10
    LocalizedValue:
      type: object
      properties:
        language:
          type: string
          examples:
            - de-DE
            - en-US
        value:
          type: string
          examples:
            - localized entry
            - lokalisierter Eintrag
    DisplayEntry:
      type: object
      properties:
        original:
          type: string
          examples:
            - display entry
        translations:
          type: array
          items:
            $ref: "#/components/schemas/LocalizedValue"
    CodeableConceptEntry:
      type: object
      properties:
        id:
          type: string
          format: uuid
        termCode:
          $ref: "#/components/schemas/TermCode"
        display:
          $ref: "#/components/schemas/DisplayEntry"
    CodeableConceptSearchResult:
      type: object
      properties:
        totalHits:
          type: integer
          examples:
            - 42
        results:
          type: array
          items:
            $ref: "#/components/schemas/CodeableConceptEntry"
    CriteriaProfileData:
      type: object
      properties:
        id:
          type: string
          format: uuid
        display:
          $ref: "#/components/schemas/DisplayEntry"
        context:
          $ref: "#/components/schemas/TermCode"
        termCodes:
          type: array
          items:
            $ref: "#/components/schemas/TermCode"
        uiProfile:
          $ref: "#/components/schemas/UiProfileEntry"
    UiProfileEntry:
      type: object
      properties:
        attributeDefinitions:
          type: array
          items:
            $ref: "#/components/schemas/AttributeDefinition"
        name:
          type: string
          examples:
            - Diagnose
        timeRestrictionAllowed:
          type: boolean
          examples:
            - false
        valueDefinition:
          type: string
    AttributeDefinition:
      type: object
      properties:
        allowedUnits:
          type: array
          items:
            $ref: "#/components/schemas/Unit"
        attributeCode:
          $ref: "#/components/schemas/TermCode"
        max:
          type: number
          examples:
            - null
        min:
          type: number
          examples:
            - null
        optional:
          type: boolean
          examples:
            - true
        precision:
          type: number
          examples:
            - 1
        referencedCriteriaSet:
          type: string
          examples:
            - http://fdpg.mii.cds/CriteriaSet/Diagnose/icd-10-gm
        referencedValueSet:
          type: string
          examples:
            - http://hl7.org/fhir/sid/icd-o-3
        type:
          type: string
          examples:
            - reference
    TerminologySystems:
      type: object
      required:
        - url
        - name
      properties:
        url:
          type: string
          format: uri
          examples:
            - http://fhir.de/CodeSystem/bfarm/ops
        name:
          type: string
          examples:
            - OPS
    ProfileTreeNode:
      type: object
      properties:
        id:
          type: string
          format: uuid
          examples:
            - aee6afe1-3b96-4449-85cd-be8046ccbb84
        children:
          type: array
          items:
            $ref: "#/components/schemas/ProfileTreeNode"
        name:
          type: string
          examples:
            - ProfileObservationLaboruntersuchung
        display:
          $ref: "#/components/schemas/DisplayEntry"
        module:
          type: string
          examples:
            - modul-labor
        url:
          type: string
          format: uri
          examples:
            - https://www.medizininformatik-initiative.de/fhir/core/modul-labor/StructureDefinition/ObservationLab
        leaf:
          type: boolean
          examples:
            - true
        selectable:
          type: boolean
          examples:
            - false
    ProfileDataField:
      type: object
      properties:
        id:
          type: string
          examples:
            - Observation.value[x]:valueQuantity.id
        display:
          $ref: "#/components/schemas/DisplayEntry"
        description:
          $ref: "#/components/schemas/DisplayEntry"
        type:
          type: string
        recommended:
          type: boolean
        required:
          type: boolean
        children:
          type: array
          items:
            $ref: "#/components/schemas/ProfileDataField"
    ProfileDataFilter:
      type: object
      properties:
        type:
          type: string
          examples:
            - token
        name:
          type: string
          examples:
            - code
        ui_type:
          type: string
          examples:
            - code
        referencedCriteriaSet:
          type: string
          format: uri
          examples:
            - http://fdpg.mii.cds/CriteriaSet/Diagnose/icd-10-gm
    ProfileDataEntry:
      type: object
      properties:
        url:
          type: string
          format: uri
          examples:
            - https://www.medizininformatik-initiative.de/fhir/core/modul-labor/StructureDefinition/ObservationLab
        display:
          $ref: "#/components/schemas/DisplayEntry"
        fields:
          type: array
          items:
            $ref: "#/components/schemas/ProfileDataField"
        filters:
          type: array
          items:
            $ref: "#/components/schemas/ProfileDataFilter"
        errorCode:
          type: string
          examples:
            - TBD-000
        errorCause:
          type: string
          examples:
            - Profile entry not found
    ProfileDataList:
      type: array
      items:
        $ref: "#/components/schemas/ProfileDataEntry"
  securitySchemes:
    dataportal_auth:
      type: oauth2
      flows:
        implicit:
          authorizationUrl: http://to.be.defined/auth
          scopes:
            user: Dataportal user role
            admin: Dataportal admin role
@michael-82
Copy link
Collaborator

Disclaimer

Since we decided to overhaul the query endpoint after the q4 release, here are some of my thoughts (not yet in a structured way) as a basis for discussion. I am quite sure that there are things I missed (or just do not know for now).

General

Queries will always be saved with the criteria and at least a label. There is no longer a distinction between "query" "saved query" and the dreaded "template".
The proposed "split" between cohorts and data extraction only refers to the backend side. This does not have to be that way in the frontend.

Cohorts

Cohorts are similar to our current "query", but they can not have results at any time. They must however have a label and may or may not have a description. In my opinion, we do not need to impose any limits on cohorts. Let users save as many as they want. Maybe we can offer an option to archive them or mark as favorites?

Needed endpoints

  • create
  • read list (own user)
  • read list by user (is this necessary here? I don't think this has to be called externally)
  • read one
  • update (which parts can be edited? only description? modifying the actual ccdl could lead to problems when linking by id later. if archive/favorite is needed...do it here)
  • delete (can we delete this or only mark as deleted? avoid deletion when it is used in queries?)
  • validate

Data Extractionl (DEQ part of CRTDL)

Needed endpoints

  • create
  • read list (own user)
  • read list by user (is this necessary here? I don't think this has to be called externally)
  • read one
  • update (which parts can be edited? only description? modifying the actual ccdl could lead to problems when linking by id later. if archive/favorite is needed...do it here)
  • delete (can we delete this or only mark as deleted? avoid deletion when it is used in queries?)
  • validate

Queries

Queries are a combination of CCDL query, DEQ query + label + description + results

Feasibility queries

Either a CRTDL with an empty DEQ part or some other format?

Needed endpoints

  • create (ccdl+label+description). save only, no dispatch
  • create (ccdl-id+label+description). save only, no dispatch
  • read list (own)
  • read list by user (maybe filter by not-archived or favorites if this is done)
  • read one
  • update (only label/comment)
  • execute/dispatch
  • read summary result
  • read detailed result
  • read detailed obfuscated result

Data Extraction-Queries

CRTDL with filled DEQ part + label + description + results

Needed endpoints

  • create (ccdl+deq+label+description). save only, no dispatch
  • create (ccdl-id+deq-id+label+description). save only, no dispatch
  • read list (own)
  • read list by user (maybe filter by not-archived or favorites if this is done)
  • read one
  • update (only label/comment)
  • execute/dispatch (probably limited)
  • read result (how do results look here? do we need multiple endpoints? will a limit be imposed here?)

Questions

  • what will be retrieved by the "antragsportal"? Only feasibility or also data extraction?
  • which endpoints need to be limited? which limits do we need?

@michael-82 michael-82 added the enhancement New feature or request label Jan 16, 2025
@juliangruendner
Copy link
Contributor Author

juliangruendner commented Jan 30, 2025

it was decided to drop the prvious saving mechanism and from now on only save a CRTDL, which may or may not be filled out fully.

therefore the following changes will be required:

  • Convert all templates and queries into CRTDL queries
  • Change all query endpoints to recieve and send CRTDL queries instead of CCDL queries
  • Drop all Template endpoints and db tables

@juliangruendner
Copy link
Contributor Author

juliangruendner commented Jan 30, 2025

@kleinertp, @mgebhardttmf: should there still be a restriction on how many queries a user can save with a result ?

@michael-82
Copy link
Collaborator

michael-82 commented Jan 30, 2025

Following todays discussion, the suggestion in the earlier comment will be changed to:

Disclaimer

The requirements have now become clear(er), but this is still just a proposal as a foundation for further discussion/specification.

General

Queries will always be saved with the criteria and at least a label. There is no longer a distinction between "saved query" and the dreaded "template".
The proposed "split" between cohorts and data extraction only refers to the backend side. This does not have to be that way in the frontend.
All queries sent between frontend and backend always contain the whole CRTDL, but parts may be empty. (Note: This is currently not allowed in the CRTDL schema but shall be changed.

As for the backend (basically not important here, but just for the sake of clarification), this will lead to the following changes:

  • query_content -> basically as is, but converted to CRTDL
  • query_template -> move to saved_query and delete table afterwards

Naming

Cohorts

Cohorts are simply CRTDL entities without a dataExtraction part.

Query annotations

A label, description and results

Data Queries

Data Queries are CRTDL queries with both CCDL and dataExtraction parts

Saved Queries

Saved queries are Data Queries + Query Annotations

Needed endpoints

Basically the same api but all query objects are now CRTDL objects.

  • post feasibility query (receives CRTDL and forwards CCDL parts)
  • read list (own)
  • read list by user
  • get data query by id (only the CRTDL)
  • get query annotations by id
  • read summary result
  • read detailed result
  • read detailed obfuscated result
  • save query
  • update query annotations
  • delete saved query annotations
  • get slots to save queries

@juliangruendner juliangruendner added this to the Next Release milestone Feb 3, 2025
@juliangruendner
Copy link
Contributor Author

juliangruendner commented Feb 3, 2025

@michael-82
this. "Data Extraction queries are simply CRTDL entities without a CCDL part." is not correct, as Data Extraction Queries are only valid with the cohort part.
basically data extraction queries do not exist as such - only data queries.
Torch can actually not exract anything if no cohort part is defined

@juliangruendner
Copy link
Contributor Author

@michael-82
required changes in the description above:

  1. Data Extraction not possible by itself.
  2. yes - label should be required when a user saves a query (note - that sendig a query is not included in this)
  3. I would only provided one endpoint to read queries and query contents - response is always a CRTDL.

@michael-82
Copy link
Collaborator

@juliangruendner I changed the entry above accordingly. Please check if it is now the way it should be

@juliangruendner
Copy link
Contributor Author

@michael-82 some changes are still necessary:

  1. post data query = post feasibility query -> recieves a CRTDL with or without a dataExtraction part filled, extracts the cohortDefinition part as a CCDL and sends the CCDL as a feasibility query.
    -- note that posting a data query is as such currently not possible or required - but such an endpoint might be added later
  2. remove mentioning of label is required -> remove "In the earlier proposal from 09/24 a change was suggested to always require queries to be saved with at least a label, even if it is just a feasibility query that will be "forgotten" afterwards and then having an extra endpoint to dispatch that query. Not sure if this is really wanted or necessary, in that case the following list would slightly change."
  3. i would not add endpoints to retrieve only parts of the CRTDL -> as revieving the whole CRTDL is not a problem, but simplifies the api
  4. note that all results of query actually refer to feasibility results @michael-82 maybe we should consider renaming the endpoints accordingly

@michael-82
Copy link
Collaborator

@juliangruendner I changed the post accordingly. However, I do not yet have a good idea for naming the results endpoints, but I agree that we should probably do that.

@michael-82
Copy link
Collaborator

michael-82 commented Feb 5, 2025

Update after discussion from 2025-02-05

After further consideration, the following was "decided" (still preliminary if anything comes up)

General

In the backend we distinguish between "data query" and "feasibiliy query" (maybe a better wording could be found). Feasibility queries are (right now) the only kind of query that will be sent somewhere.

User side of the story

The user can (without knowing what's under the hood) create / read / update / delete CRTDLs (called "Data Query"). Basically this is like the template idea from earlier. There will be no necessary validation of anything. The only additional thing that is needed is a name for the query when stored.
Whenever the user wants (there should be a check if the cohort part of this query is valid...there is already a validate endpoint in place, which should be adapted to accept CRTDL), a feasibility query from the current "version" (there will be no versioning, but the currently saved state of the query) can be "spawned". At this moment, the query becomes "locked" and can not be modified again. (This would be done by sending the ccdl query to the post query endpoint). Internally that means that the CRTDL will get an entry for an FK to the feasibility query. This link can be deleted if necessary, if the user wants to execute the same query again. This would basically be the equivalent to the "old" saved query.
Additionally, when there is also a result available, this can be stored to this CRTDL as well (being the old "query with result" which is limited to a certain amount of queries and will be available for download from the appsfactory app). Once again, this can also be deleted by the user if he wants to.

Query "states"

So basically we have 3 different types of "saved query" (like we had earlier...but it will hopefully be clearer to the user what is up)

  1. Just a CRTDL query without any relation to a feasibility query. This can be modified, deleted, any amount can be stored. This can not be retrieved from the appsfactory app (Basically what was earlier called a template).
  2. CRTDL + linked feasibility query. This can now not be modified or deleted any more. There is no restriction on how many can be saved. These can be retrieved from the appsfactory app. The connection to the feasibility query can be deleted (the feasibility query itself will never be deleted), returning the query to state 1. (Basically the old saved query)
  3. CRTDL + linked feasibility query + result. When the query yielded results, they can be saved to the backend. This has the same restrictions as state 2 has. The result can be deleted and the query can be put back in state 2, or result and feasibility query (the link to it) can be removed and it goes back to state 1. (Basically the old saved query with result)

Question: It was made clear by @kleinertp that the appsfactory app must be able to retrieve queries with or without result (so state 2+3). Should the limit of N queries be imposed on both types? Or just on the one with results?

Feasibility only

It must also still be possible to execute a feasibility query without creating a CRTDL query first. This will simply use the same endpoint as spawning a feasibility query from a CRTDL does. In this case, the old behaviour from the well known dataportal occurs. The user can still save this as a CRTDL afterwards, but it is not necessary. In this case the create endpoint from earlier can be used. In this case, the feasibility query will instantly be linked. If the result shall be saved alongside, this should be 2 calls from the frontend to the backend (up for discussion however...maybe we could put something up to do it all in one call)

REST

As for the REST endpoints this would lead to the following (a swagger file will follow to better illustrate it)

Note: In order to include links to (or information from) the feasibility query and/or result we must either provide multiple resources to read all that or wrap the CRTDL in one more layer that holds that information.

Paths 1

POST ../dataquery (accepts json...does not validate) save a data query
GET ../dataquery lists id, name and timestamp of all of a users stored data queries. might want to include filter/pagination later if it becomes clear that users save lots of queries

GET ../dataquery/{id} load one data query. if a feasibility query is linked to that, include this information (if we go for an additional wrapper around the crtdl)
OR
GET ../dataquery/{id}/crtdl - get only the crtdl
GET ../dataquery/{id}/feasibility-query - get the info of the executed feasibility query (basically would be just timestamp or null)
GET ../dataquery/{id}/result - get the amount of patients and the timestamp of the result
OR
GET ../dataquery/{id}/crtdl - get only the crtdl
GET ../dataquery/{id}/feasibility-info - get the info of the executed feasibility query (basically would be just timestamp or null) and - if present - result

PUT ../dataquery/{id} - (accepts json...does not validate) update a data query. Only possible if no feasibility query is linked to it.
DELETE ../dataquery/{id} - delete the query. Only possible if no feasibility query is linked to it.

GET ../dataquery/saved-query-slots - basically as is

POST ../query/feasibility - the "old" execute query endpoint. accepts VALID ccdl
OPTIONAL
POST ../dataquery/{id}/feasibility - could be used to just take the ccdl of a crtdl to execute the feasibility query without the need to submit it again.

GET ../query/feasibilty/{id}/summary-result - basically as is
GET ../query/feasibilty/{id}/detailed-result - basically as is
GET ../query/feasibilty/{id}/detailed-obfuscated-result - basically as is

Another option would be to change the paths to

/query
/query/data
/query/feasibility

Paths 2

I guess it comes down to preference what to do here. For the sake of completeness I'll fully list it again here. The functionality behind it would be exactly the same.

POST ../query/data (accepts json...does not validate) save a data query
GET ../query/data lists id, name and timestamp of all of a users stored data queries. might want to include filter/pagination later if it becomes clear that users save lots of queries

GET ../query/data/{id} load one data query. if a feasibility query is linked to that, include this information (if we go for an additional wrapper around the crtdl)
OR
GET ../query/data/{id}/crtdl - get only the crtdl
GET ../query/data/{id}/feasibility-query - get the info of the executed feasibility query (basically would be just timestamp or null)
GET ../query/data/{id}/result - get the amount of patients and the timestamp of the result
OR
GET ../query/data/{id}/crtdl - get only the crtdl
GET ../query/data/{id}/feasibility-info - get the info of the executed feasibility query (basically would be just timestamp or null) and - if present - result

PUT ../query/data/{id} - (accepts json...does not validate) update a data query. Only possible if no feasibility query is linked to it.
DELETE ../query/data/{id} - delete the query. Only possible if no feasibility query is linked to it.

GET ../query/data/saved-query-slots - basically as is

POST ../query/feasibility - the "old" execute query endpoint. accepts VALID ccdl
OPTIONAL
POST ../query/data/{id}/feasibility - could be used to just take the ccdl of a crtdl to execute the feasibility query without the need to submit it again.

GET ../query/feasibilty/{id}/summary-result - basically as is
GET ../query/feasibilty/{id}/detailed-result - basically as is
GET ../query/feasibilty/{id}/detailed-obfuscated-result - basically as is

@michael-82
Copy link
Collaborator

michael-82 commented Feb 6, 2025

Some more minor endpoints are needed - e.g. to delete the connection between a dataquery and a feasibility query. The following two open api examples already contain this. There are some open questions in it that need to be addressed. There are no differences between the two openapi files besides the different paths.

Note: There might still be some inconsistencies (especially considering wording/spelling) but I wanted to put this up for discussion anyways.

As always...easiest to copy the following examples to https://editor-next.swagger.io/

Option 1
openapi: 3.1.0
info:
  title: Dataportal Backend REST API - Query Parts only
  license:
    name: Apache 2.0
    url: http://www.apache.org/licenses/LICENSE-2.0.html
  version: 6.0.0
externalDocs:
  description: Check out the github repository
  url: https://github.com/medizininformatik-initiative/feasibility-backend
servers:
  - url: https://to.be.defined
    variables:
      basePath:
        default: /api/v5
paths:
  /dataquery:
    post:
      tags:
        - dataquery
      summary: Store a dataquery in the backend.
      description: The query will only be stored, nothing will be dispatched. Does not have to pass any validation and may be incomplete
      operationId: storeDataQuery
      requestBody:
        description: CRTDL
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CRTDL"
        required: true
      responses:
        201:
          description: Dataquery successfully stored
          headers:
            Location:
              description: Path to the result of your newly created dataquery
              schema:
                type: string
                examples:
                  - https://my-dataportal-backend/api/v5/dataquery/42
          content: {}
        401:
          description: Unauthorized - please login first
        422:
          description: Invalid input
      security:
        - dataportal_auth:
            - user
    get:
      tags:
        - dataquery
      summary: Get the list of the calling users dataqueries
      description: This returns a list with basic information about the queries. Id, label (if present) and creation date. Basically for all parameters I'm not sure if we need them (at least right away)
      operationId: getDataQueryList
      parameters:
        - name: filter
          in: query
          description: filters query...either for those with linked feasibility and or results? Or by name?
          required: false
          schema:
            type: string
            enum:
              - feasibility
        - name: skip-validation
          in: query
          description: If true, do not validate the query and do not include a list of invalid terms. TODO - maybe invert this?
          required: false
          schema:
            type: boolean
            default: false
        - name: limit
          in: query
          description: How many queries to retrieve
          required:  false
          schema:
            type: integer
            default: 20
        - name: offset
          in: query
          description: Where to start the list of queries
          required:  false
          schema:
            type: integer
            default: 0
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/DataQueryListEntry"
        401:
          description: Unauthorized - please login first
      security:
        - dataportal_auth:
            - user
  /dataquery/by-user/{userId}:
    get:
      tags:
        - dataquery
      summary: Finds query summary (id, label, lastModified) of all queries of one user
      operationId: findDataQueriesByUser
      parameters:
        - name: userId
          in: path
          description: User to filter by (keycloak id)
          required: true
          schema:
            type: string
        - name: filter
          in: query
          description: filters query...either for those with linked feasibility and or results? Or by name?
          required: false
          schema:
            type: string
            enum:
              - feasibility
        - name: skip-validation
          in: query
          description: If true, do not validate the query and do not include a list of invalid terms. TODO - maybe invert this?
          required: false
          schema:
            type: boolean
            default: false
        - name: limit
          in: query
          description: How many queries to retrieve
          required:  false
          schema:
            type: integer
            default: 20
        - name: offset
          in: query
          description: Where to start the list of queries
          required:  false
          schema:
            type: integer
            default: 0
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/DataQueryListEntry"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: User not found
      security:
        - dataportal_auth:
            - admin
  /dataquery/{queryId}:
    get:
      tags:
        - dataquery
      summary: (Option A - only this one) Read dataquery by ID
      description: Returns a single dataquery. Contains everything known about the query, including results and structured query
      operationId: getDataQueryById
      parameters:
        - name: queryId
          in: path
          description: ID of query to return
          required: true
          schema:
            type: integer
            format: int64
        - name: skip-validation
          in: query
          description: If true, do not validate the query and do not include a list of invalid terms
          required: false
          schema:
            type: boolean
            default: false
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CRTDLplus"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Query not found
      security:
        - dataportal_auth:
            - user
            - admin
    put:
      tags:
        - dataquery
      summary: Update a dataquery in the backend.
      description: The query will be updated, but only if no feasibility query is linked to it. It must be provided completely, there are no partial updates.
      operationId: updateDataQuery
      requestBody:
        description: CRTDL
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CRTDL"
        required: true
      responses:
        200:
          description: Dataquery successfully updated
          content: {}
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: The dataquery could not be found
        409:
          description: The dataquery is linked to a feasibility query and can not be updated (or should this maybe be 400)
      security:
        - dataportal_auth:
            - user
    delete:
      tags:
        - dataquery
      summary: Delete a dataquery (only possible if no feasibility query is linked)
      operationId: deleteDataQuery
      parameters:
        - name: queryId
          in: path
          required: true
          schema:
            type: integer
            format: int64
      responses:
        204:
          description: No content
          content:
            {}
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: The dataquery could not be found
        409:
          description: The dataquery is linked to a feasibility query and can not be deleted (or should this maybe be 400)
  /dataquery/{queryId}/crtdl:
    get:
      tags:
        - dataquery
      summary: (Option B+C - 1/3) Read dataquery CRTDL by ID
      description: Returns a single dataquery. Contains only the CRTDL
      operationId: getDataQueryCRTDLById
      parameters:
        - name: queryId
          in: path
          description: ID of query to return
          required: true
          schema:
            type: integer
            format: int64
        - name: skip-validation
          in: query
          description: If true, do not validate the query and do not include a list of invalid terms
          required: false
          schema:
            type: boolean
            default: false
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CRTDL"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Query not found
      security:
        - dataportal_auth:
            - user
            - admin
  /dataquery/{queryId}/feasibility-query:
    get:
      tags:
        - dataquery
      summary: (Option B - 2/3) Read information about feasibility query linked to dataquery by dataquery ID
      description: Returns a single dataquery. Contains only the info about feasibility query
      operationId: getDataQueryFeasibilityQueryById
      parameters:
        - name: queryId
          in: path
          description: ID of query to return
          required: true
          schema:
            type: integer
            format: int64
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  dispatchedAt:
                    type: string
                    format: date-time
                    example: "2025-02-06T12:34:56Z"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Query not found or no feasibility part available for this query
      security:
        - dataportal_auth:
            - user
            - admin
    delete:
      tags:
        - dataquery
      summary: Delete the link between the dataquery and the feasibility query. The feasibility query itself can never be deleted, only the link between the two is deleted. This also deletes a possibly saved result.
      operationId: deleteFeasibilityQueryConnection
      parameters:
        - name: queryId
          in: path
          required: true
          schema:
            type: integer
            format: int64
      responses:
        204:
          description: Link to feasibility query was deleted (or there was none linked)
          content:
            { }
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: The dataquery could not be found
  /dataquery/{queryId}/feasibility-result:
    get:
      tags:
        - dataquery
      summary: (Option B - 3/3) Read information about feasibility result linked to dataquery by dataquery ID
      description: Returns a single dataquery. Contains only the info about feasibility result
      operationId: getDataQueryFeasibilityResultById
      parameters:
        - name: queryId
          in: path
          description: ID of query to return
          required: true
          schema:
            type: integer
            format: int64
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  receivedAt:
                    type: string
                    format: date-time
                    examples:
                      - "2025-02-06T12:34:56Z"
                  totalNumberOfResults:
                    type: integer
                    examples:
                      - 42
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Query not found or no feasibility part available for this query
      security:
        - dataportal_auth:
            - user
            - admin
    delete:
      tags:
        - dataquery
      summary: Delete the link between the dataquery and the feasibility result
      operationId: deleteFeasibilityQueryResult
      parameters:
        - name: queryId
          in: path
          required: true
          schema:
            type: integer
            format: int64
      responses:
        204:
          description: Link to feasibility result was deleted (or there was none linked)
          content:
            { }
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: The dataquery could not be found
  /dataquery/{queryId}/feasibility-info:
    get:
      tags:
        - dataquery
      summary: (Option C - 2/2) Read information about feasibility query and result linked to dataquery by dataquery ID
      description: Returns a single dataquery. Contains only the info about feasibility query and possibly result
      operationId: getDataQueryFeasibilityInfoById
      parameters:
        - name: queryId
          in: path
          description: ID of query to return
          required: true
          schema:
            type: integer
            format: int64
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FeasibilityAndResult"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Query not found or no feasibility part available for this query
      security:
        - dataportal_auth:
            - user
            - admin
    delete:
      tags:
        - dataquery
      summary: Delete the link between the dataquery and the feasibility query AND result.
      operationId: deleteFeasibilityQueryConnectionAndResult
      parameters:
        - name: queryId
          in: path
          required: true
          schema:
            type: integer
            format: int64
      responses:
        204:
          description: Link to feasibility query was deleted (or there was none linked)
          content:
            { }
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: The dataquery could not be found
  /dataquery/saved-query-slots:
    get:
      tags:
        - dataquery
      summary: Show how many saved query slots a user already used and how many he has left.
      operationId: getSavedDataQuerySlots
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SavedQuerySlots"
      security:
        - dataportal_auth:
            - user
  /query/validate:
    post:
      tags:
        - query
        - validation
      summary: Validates a submitted CRTDL or just CCDL? to check for schema violations or invalid termCodes
      description: It could be useful to split this in ccdl and dataquery or at least offer a parameter to determine which should be checked.
      operationId: validateQuery
      requestBody:
        description: Query to validate
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CRTDL"
        required: true
      responses:
        200:
          description: Query adheres to json schema. If invalid termCodes are present, they will be in the response.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/CRTDL"
        400:
          description: Query does not adhere to json schema
        401:
          description: Unauthorized - please login first
  /query/feasibility/{queryId}/summary-result:
    get:
      tags:
        - query
      summary: Read query result summary by query ID
      description: Returns the aggregated results to a query. There is no breakdown by site. So, the resultLines parameter of the response is de facto an array of QueryResultLines, but it will always be empty in this case.
      operationId: getQueryResultSummary
      parameters:
        - name: queryId
          in: path
          description: ID of query for which the results are requested
          required: true
          schema:
            type: integer
            format: int64
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/QueryResultSummary"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Query not found
        429:
          description: Too many requests
      security:
        - dataportal_auth:
            - admin
            - user
  /query/feasibility/{queryId}/detailed-result:
    get:
      tags:
        - query
      summary: Read query result by ID
      description: Returns results to query with the real site names - admin rights required
      operationId: getQueryResultDetailed
      parameters:
        - name: queryId
          in: path
          description: ID of query for which the results are requested
          required: true
          schema:
            type: integer
            format: int64
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/QueryResult"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Query not found
      security:
        - dataportal_auth:
            - admin
  /query/feasibility/{queryId}/detailed-obfuscated-result:
    get:
      tags:
        - query
      summary: Read obfuscated query result by ID
      description: Returns all results to query with the site names obfuscated.
      operationId: getQueryResultDetailedObfuscated
      parameters:
        - name: queryId
          in: path
          description: ID of query for which the results are requested
          required: true
          schema:
            type: integer
            format: int64
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/QueryResultObfuscated"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Query not found
        429:
          description: Too many requests
      security:
        - dataportal_auth:
            - admin
            - user
  /query/feasibility/detailed-obfuscated-result-rate-limit:
    get:
      summary: get the rate limit for detailed obfuscated results
      operationId: getDetailedObfuscatedResultRateLimit
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/QueryResultRateLimit"
  /query/feasibility:
    post:
      tags:
        - query
      summary: Create a feasibility query in the broker
      description: The query will be spawned in the broker and directly be dispatched. It CAN be linked to a dataquery
      operationId: runQuery
      parameters:
        - name: dataquery-id
          in: query
          description: If this is a feasibility query that is spawned from a saved dataquery, provide the id of said dataquery
          required: false
          schema:
            type: integer
            examples:
              - 42
      requestBody:
        description: Structured query to create and dispatch
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/StructuredQuery"
        required: true
      responses:
        201:
          description: Query successfully dispatched
          headers:
            Location:
              description: Path to the result of your newly created query
              schema:
                type: string
                examples:
                  - https://to.be.defined/api/v5/query/42
          content: {}
        400:
          description: If a dataquery-id was supplied but this could not be saved (either because it does not exist or already has a linked feasibility query)
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        422:
          description: Invalid input
        429:
          description: Too many requests in a given amount of time (configurable)
        500:
          description: Dispatch error
      security:
        - dataportal_auth:
            - user
      x-codegen-request-body-name: body

components:
  schemas:
    CRTDLplus:
      type: object
      properties:
        feasibility:
          type: object
          $ref: "#/components/schemas/FeasibilityAndResult"
        dataQuery:
          type: object
          $ref: "#/components/schemas/CRTDL"
    CRTDL:
      type: object
      properties:
        display:
          type: string
          examples:
            - Example CRTDL
        cohortDefinition:
          type: object
          $ref: "#/components/schemas/StructuredQuery"
        dataExtraction:
          type: object
          $ref: "#/components/schemas/DataExtractionQuery"
    DataExtractionQuery:
      type: object
      properties:
        id:
          type: string
          examples:
            - 123
        attributeGroups:
          type: array
          items:
            type: string
            examples:
              - to be done correctly...for now just a placeholder because it doesn't matter for this conversation
    FeasibilityAndResult:
      type: object
      properties:
        dispatchDate:
          type: string
          format: date-time
        resultDate:
          type: string
          format: date-time
        totalNumberOfResults:
          type: integer
    DataQueryListEntry:
      type: object
      required:
        - id
        - label
      properties:
        id:
          type: integer
          format: int64
        label:
          type: string
        comment:
          type: string
        createdAt:
          type: string
          format: date-time
        totalNumberOfPatients:
          type: integer
        isValid:
          type: boolean
    Query:
      type: object
      required:
        - id
        - content
      properties:
        id:
          type: integer
          format: int64
        content:
          $ref: "#/components/schemas/StructuredQuery"
        label:
          type: string
        results:
          $ref: "#/components/schemas/QueryResult"
    QueryResultSummary:
      type: object
      properties:
        totalNumberOfPatients:
          type: integer
          format: int64
        queryId:
          type: string
        resultLines:
          type: array
          items:
            $ref: "#/components/schemas/QueryResultLine"
    QueryResultObfuscated:
      type: object
      properties:
        totalNumberOfPatients:
          type: integer
          format: int64
        queryId:
          type: string
        resultLines:
          type: array
          items:
            $ref: "#/components/schemas/QueryResultLineObfuscated"
    QueryResult:
      type: object
      properties:
        totalNumberOfPatients:
          type: integer
          format: int64
        queryId:
          type: string
        resultLines:
          type: array
          items:
            $ref: "#/components/schemas/QueryResultLine"
    QueryResultLine:
      type: object
      required:
        - siteName
        - numberOfPatients
      properties:
        siteName:
          type: string
        numberOfPatients:
          type: integer
          format: int64
    QueryResultLineObfuscated:
      type: object
      required:
        - siteName
        - numberOfPatients
      properties:
        siteName:
          type: string
          description: obfuscated site name
        numberOfPatients:
          type: integer
          format: int64
    QueryResultRateLimit:
      type: object
      properties:
        limit:
          type: number
          format: int64
        remaining:
          type: number
          format: int64
    QueryTemplateListItem:
      type: object
      required:
        - label
      properties:
        id:
          type: integer
          format: int64
        label:
          type: string
          description: The 'name' of the query. Is assigned by the user via GUI.
          examples:
            - my-query-1
        comment:
          type: string
          description: A more detailed information about the query. Is also assigned by the user via GUI.
          examples:
            - I wanted to see how many patients I could find for my study XYZ
        lastModified:
          type: string
          format: date-time
        createdBy:
          type: string
          description: Keycloak id of the user who created the query
        isValid:
          type: boolean
          description: is the query valid?
    QueryTemplate:
      type: object
      required:
        - label
      properties:
        id:
          type: integer
          format: int64
        label:
          type: string
          description: The 'name' of the query. Is assigned by the user via GUI.
          examples:
            - my-query-1
        comment:
          type: string
          description: A more detailed information about the query. Is also assigned by the user via GUI.
          examples:
            - I wanted to see how many patients I could find for my study XYZ
        content:
          $ref: "#/components/schemas/StructuredQuery"
        lastModified:
          type: string
          format: date-time
        createdBy:
          type: string
          description: Keycloak id of the user who created the query
    StructuredQuery:
      type: object
      required:
        - version
        - inclusionCriteria
      properties:
        version:
          type: string
          format: uri
          description: The json schema version
          examples:
            - http://to_be_decided.com/draft-1/schema#
        display:
          type: string
          examples:
            - foobar
        inclusionCriteria:
          type: array
          items:
            $ref: "#/components/schemas/CriterionList"
        exclusionCriteria:
          type: array
          items:
            $ref: "#/components/schemas/CriterionList"
    SavedQuery:
      type: object
      required:
        - label
      properties:
        label:
          type: string
          description: The 'name' of the query. Is assigned by the user via GUI.
          examples:
            - my-query-1
        comment:
          type: string
          description: A more detailed information about the query. Is also assigned by the user via GUI.
          examples:
            - I wanted to see how many patients I could find for my study XYZ
        totalNumberOfPatients:
          type: integer
          format: int64
          description: The number of results that were found for this query.
          examples:
            - 12345
    SavedQuerySlots:
      type: object
      required:
        - used
        - total
      properties:
        used:
          type: integer
          description: The amount of used saved query slots for a user.
          examples:
            - 2
        total:
          type: integer
          description: The total amount of saved query slots per user.
          examples:
            - 10
    TermCode:
      description: The termCode defines a concept based on a coding system (i.e. LOINC). The triplet of code, system and version identify the concept.
      type: object
      required:
        - code
        - system
        - display
      properties:
        code:
          type: string
          examples:
            - 119373006
        system:
          type: string
          examples:
            - http://snomed.info/sct
        version:
          type: string
          examples:
            - http://snomed.info/sct/900000000000207008/version/20210731
        display:
          type: string
          examples:
            - Amniotic fluid specimen (specimen)
    beforeDate:
      type: string
      format: date-time
    afterDate:
      type: string
      format: date-time
    TimeRestriction:
      anyOf:
        - $ref: "#/components/schemas/beforeDate"
        - $ref: "#/components/schemas/afterDate"
    Unit:
      type: object
      required:
        - code
        - display
      properties:
        code:
          type: string
        display:
          type: string
    AttributeFilter:
      type: object
      description: An AttributeFilter requires different properties, depending on the type. Please refer to the JSON Schema for this.
      required:
        - type
      properties:
        attributeCode:
          $ref: "#/components/schemas/TermCode"
    ValueFilter:
      type: object
      description: A ValueFilter requires different properties, depending on the type. Please refer to the JSON Schema for this.
      required:
        - type
      properties:
        type:
          type: string
          enum:
            - concept
            - quantity-comparator
            - quantity-range
        selectedConcepts:
          type: array
          items:
            $ref: "#/components/schemas/TermCode"
        comparator:
          type: string
          enum:
            - eq
            - ue
            - le
            - lt
            - ge
            - gt
        unit:
          $ref: "#/components/schemas/Unit"
        value:
          type: number
          format: double
        minValue:
          type: number
          format: double
        maxValue:
          type: number
          format: double
    Criterion:
      type: object
      required:
        - termCodes
      properties:
        termCodes:
          type: array
          items:
            $ref: "#/components/schemas/TermCode"
        attributeFilters:
          type: array
          items:
            $ref: "#/components/schemas/AttributeFilter"
        valueFilter:
          $ref: "#/components/schemas/ValueFilter"
        timeRestriction:
          $ref: "#/components/schemas/TimeRestriction"
        issues:
          type: array
          items:
            $ref: "#/components/schemas/ValidationIssue"
    CriterionList:
      type: array
      items:
        $ref: "#/components/schemas/Criterion"
    ContextualizedTermCodeList:
      type: object
      properties:
        contextualizedTermCodes:
          type: array
          items:
            $ref: "#/components/schemas/ContextualizedTermCode"
    ContextualizedTermCode:
      type: object
      properties:
        termcode:
          $ref: "#/components/schemas/TermCode"
        context:
          $ref: "#/components/schemas/TermCode"
    ValidationIssue:
      type: object
      required:
        - code
        - detail
      properties:
        code:
          type: string
          examples:
            - VAL-20001
        detail:
          type: string
          examples:
            - The combination of context and termcode(s) is not found.
  securitySchemes:
    dataportal_auth:
      type: oauth2
      flows:
        implicit:
          authorizationUrl: http://to.be.defined/auth
          scopes:
            user: Dataportal user role
            admin: Dataportal admin role

Option 2
openapi: 3.1.0
info:
  title: Dataportal Backend REST API - Query Parts only
  license:
    name: Apache 2.0
    url: http://www.apache.org/licenses/LICENSE-2.0.html
  version: 6.0.0
externalDocs:
  description: Check out the github repository
  url: https://github.com/medizininformatik-initiative/feasibility-backend
servers:
  - url: https://to.be.defined
    variables:
      basePath:
        default: /api/v5
paths:
  /query/data:
    post:
      tags:
        - dataquery
      summary: Store a dataquery in the backend.
      description: The query will only be stored, nothing will be dispatched. Does not have to pass any validation and may be incomplete
      operationId: storeDataQuery
      requestBody:
        description: CRTDL
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CRTDL"
        required: true
      responses:
        201:
          description: Dataquery successfully stored
          headers:
            Location:
              description: Path to the result of your newly created dataquery
              schema:
                type: string
                examples:
                  - https://my-dataportal-backend/api/v5/dataquery/42
          content: {}
        401:
          description: Unauthorized - please login first
        422:
          description: Invalid input
      security:
        - dataportal_auth:
            - user
    get:
      tags:
        - dataquery
      summary: Get the list of the calling users dataqueries
      description: This returns a list with basic information about the queries. Id, label (if present) and creation date. Basically for all parameters I'm not sure if we need them (at least right away)
      operationId: getDataQueryList
      parameters:
        - name: filter
          in: query
          description: filters query...either for those with linked feasibility and or results? Or by name?
          required: false
          schema:
            type: string
            enum:
              - feasibility
        - name: skip-validation
          in: query
          description: If true, do not validate the query and do not include a list of invalid terms. TODO - maybe invert this?
          required: false
          schema:
            type: boolean
            default: false
        - name: limit
          in: query
          description: How many queries to retrieve
          required:  false
          schema:
            type: integer
            default: 20
        - name: offset
          in: query
          description: Where to start the list of queries
          required:  false
          schema:
            type: integer
            default: 0
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/DataQueryListEntry"
        401:
          description: Unauthorized - please login first
      security:
        - dataportal_auth:
            - user
  /query/data/by-user/{userId}:
    get:
      tags:
        - dataquery
      summary: Finds query summary (id, label, lastModified) of all queries of one user
      operationId: findDataQueriesByUser
      parameters:
        - name: userId
          in: path
          description: User to filter by (keycloak id)
          required: true
          schema:
            type: string
        - name: filter
          in: query
          description: filters query...either for those with linked feasibility and or results? Or by name?
          required: false
          schema:
            type: string
            enum:
              - feasibility
        - name: skip-validation
          in: query
          description: If true, do not validate the query and do not include a list of invalid terms. TODO - maybe invert this?
          required: false
          schema:
            type: boolean
            default: false
        - name: limit
          in: query
          description: How many queries to retrieve
          required:  false
          schema:
            type: integer
            default: 20
        - name: offset
          in: query
          description: Where to start the list of queries
          required:  false
          schema:
            type: integer
            default: 0
      responses:
        200:
          description: successful operation
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/DataQueryListEntry"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: User not found
      security:
        - dataportal_auth:
            - admin
  /query/data/{queryId}:
    get:
      tags:
        - dataquery
      summary: (Option A - only this one) Read dataquery by ID
      description: Returns a single dataquery. Contains everything known about the query, including results and structured query
      operationId: getDataQueryById
      parameters:
        - name: queryId
          in: path
          description: ID of query to return
          required: true
          schema:
            type: integer
            format: int64
        - name: skip-validation
          in: query
          description: If true, do not validate the query and do not include a list of invalid terms
          required: false
          schema:
            type: boolean
            default: false
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CRTDLplus"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Query not found
      security:
        - dataportal_auth:
            - user
            - admin
    put:
      tags:
        - dataquery
      summary: Update a dataquery in the backend.
      description: The query will be updated, but only if no feasibility query is linked to it. It must be provided completely, there are no partial updates.
      operationId: updateDataQuery
      requestBody:
        description: CRTDL
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CRTDL"
        required: true
      responses:
        200:
          description: Dataquery successfully updated
          content: {}
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: The dataquery could not be found
        409:
          description: The dataquery is linked to a feasibility query and can not be updated (or should this maybe be 400)
      security:
        - dataportal_auth:
            - user
    delete:
      tags:
        - dataquery
      summary: Delete a dataquery (only possible if no feasibility query is linked)
      operationId: deleteDataQuery
      parameters:
        - name: queryId
          in: path
          required: true
          schema:
            type: integer
            format: int64
      responses:
        204:
          description: No content
          content:
            {}
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: The dataquery could not be found
        409:
          description: The dataquery is linked to a feasibility query and can not be deleted (or should this maybe be 400)
  /query/data/{queryId}/crtdl:
    get:
      tags:
        - dataquery
      summary: (Option B+C - 1/3) Read dataquery CRTDL by ID
      description: Returns a single dataquery. Contains only the CRTDL
      operationId: getDataQueryCRTDLById
      parameters:
        - name: queryId
          in: path
          description: ID of query to return
          required: true
          schema:
            type: integer
            format: int64
        - name: skip-validation
          in: query
          description: If true, do not validate the query and do not include a list of invalid terms
          required: false
          schema:
            type: boolean
            default: false
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CRTDL"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Query not found
      security:
        - dataportal_auth:
            - user
            - admin
  /query/data/{queryId}/feasibility-query:
    get:
      tags:
        - dataquery
      summary: (Option B - 2/3) Read information about feasibility query linked to dataquery by dataquery ID
      description: Returns a single dataquery. Contains only the info about feasibility query
      operationId: getDataQueryFeasibilityQueryById
      parameters:
        - name: queryId
          in: path
          description: ID of query to return
          required: true
          schema:
            type: integer
            format: int64
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  dispatchedAt:
                    type: string
                    format: date-time
                    example: "2025-02-06T12:34:56Z"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Query not found or no feasibility part available for this query
      security:
        - dataportal_auth:
            - user
            - admin
    delete:
      tags:
        - dataquery
      summary: Delete the link between the dataquery and the feasibility query. The feasibility query itself can never be deleted, only the link between the two is deleted. This also deletes a possibly saved result.
      operationId: deleteFeasibilityQueryConnection
      parameters:
        - name: queryId
          in: path
          required: true
          schema:
            type: integer
            format: int64
      responses:
        204:
          description: Link to feasibility query was deleted (or there was none linked)
          content:
            { }
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: The dataquery could not be found
  /query/data/{queryId}/feasibility-result:
    get:
      tags:
        - dataquery
      summary: (Option B - 3/3) Read information about feasibility result linked to dataquery by dataquery ID
      description: Returns a single dataquery. Contains only the info about feasibility result
      operationId: getDataQueryFeasibilityResultById
      parameters:
        - name: queryId
          in: path
          description: ID of query to return
          required: true
          schema:
            type: integer
            format: int64
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  receivedAt:
                    type: string
                    format: date-time
                    examples:
                      - "2025-02-06T12:34:56Z"
                  totalNumberOfResults:
                    type: integer
                    examples:
                      - 42
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Query not found or no feasibility part available for this query
      security:
        - dataportal_auth:
            - user
            - admin
    delete:
      tags:
        - dataquery
      summary: Delete the link between the dataquery and the feasibility result
      operationId: deleteFeasibilityQueryResult
      parameters:
        - name: queryId
          in: path
          required: true
          schema:
            type: integer
            format: int64
      responses:
        204:
          description: Link to feasibility result was deleted (or there was none linked)
          content:
            { }
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: The dataquery could not be found
  /query/data/{queryId}/feasibility-info:
    get:
      tags:
        - dataquery
      summary: (Option C - 2/2) Read information about feasibility query and result linked to dataquery by dataquery ID
      description: Returns a single dataquery. Contains only the info about feasibility query and possibly result
      operationId: getDataQueryFeasibilityInfoById
      parameters:
        - name: queryId
          in: path
          description: ID of query to return
          required: true
          schema:
            type: integer
            format: int64
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FeasibilityAndResult"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Query not found or no feasibility part available for this query
      security:
        - dataportal_auth:
            - user
            - admin
    delete:
      tags:
        - dataquery
      summary: Delete the link between the dataquery and the feasibility query AND result.
      operationId: deleteFeasibilityQueryConnectionAndResult
      parameters:
        - name: queryId
          in: path
          required: true
          schema:
            type: integer
            format: int64
      responses:
        204:
          description: Link to feasibility query was deleted (or there was none linked)
          content:
            { }
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: The dataquery could not be found
  /query/data/saved-query-slots:
    get:
      tags:
        - dataquery
      summary: Show how many saved query slots a user already used and how many he has left.
      operationId: getSavedDataQuerySlots
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SavedQuerySlots"
      security:
        - dataportal_auth:
            - user
  /query/validate:
    post:
      tags:
        - query
        - validation
      summary: Validates a submitted CRTDL or just CCDL? to check for schema violations or invalid termCodes
      description: It could be useful to split this in ccdl and dataquery or at least offer a parameter to determine which should be checked.
      operationId: validateQuery
      requestBody:
        description: Query to validate
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CRTDL"
        required: true
      responses:
        200:
          description: Query adheres to json schema. If invalid termCodes are present, they will be in the response.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/CRTDL"
        400:
          description: Query does not adhere to json schema
        401:
          description: Unauthorized - please login first
  /query/feasibility/{queryId}/summary-result:
    get:
      tags:
        - query
      summary: Read query result summary by query ID
      description: Returns the aggregated results to a query. There is no breakdown by site. So, the resultLines parameter of the response is de facto an array of QueryResultLines, but it will always be empty in this case.
      operationId: getQueryResultSummary
      parameters:
        - name: queryId
          in: path
          description: ID of query for which the results are requested
          required: true
          schema:
            type: integer
            format: int64
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/QueryResultSummary"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Query not found
        429:
          description: Too many requests
      security:
        - dataportal_auth:
            - admin
            - user
  /query/feasibility/{queryId}/detailed-result:
    get:
      tags:
        - query
      summary: Read query result by ID
      description: Returns results to query with the real site names - admin rights required
      operationId: getQueryResultDetailed
      parameters:
        - name: queryId
          in: path
          description: ID of query for which the results are requested
          required: true
          schema:
            type: integer
            format: int64
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/QueryResult"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Query not found
      security:
        - dataportal_auth:
            - admin
  /query/feasibility/{queryId}/detailed-obfuscated-result:
    get:
      tags:
        - query
      summary: Read obfuscated query result by ID
      description: Returns all results to query with the site names obfuscated.
      operationId: getQueryResultDetailedObfuscated
      parameters:
        - name: queryId
          in: path
          description: ID of query for which the results are requested
          required: true
          schema:
            type: integer
            format: int64
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/QueryResultObfuscated"
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        404:
          description: Query not found
        429:
          description: Too many requests
      security:
        - dataportal_auth:
            - admin
            - user
  /query/feasibility/detailed-obfuscated-result-rate-limit:
    get:
      summary: get the rate limit for detailed obfuscated results
      operationId: getDetailedObfuscatedResultRateLimit
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/QueryResultRateLimit"
  /query/feasibility:
    post:
      tags:
        - query
      summary: Create a feasibility query in the broker
      description: The query will be spawned in the broker and directly be dispatched. It CAN be linked to a dataquery
      operationId: runQuery
      parameters:
        - name: dataquery-id
          in: query
          description: If this is a feasibility query that is spawned from a saved dataquery, provide the id of said dataquery
          required: false
          schema:
            type: integer
            examples:
              - 42
      requestBody:
        description: Structured query to create and dispatch
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/StructuredQuery"
        required: true
      responses:
        201:
          description: Query successfully dispatched
          headers:
            Location:
              description: Path to the result of your newly created query
              schema:
                type: string
                examples:
                  - https://to.be.defined/api/v5/query/42
          content: {}
        400:
          description: If a dataquery-id was supplied but this could not be saved (either because it does not exist or already has a linked feasibility query)
        401:
          description: Unauthorized - please login first
        403:
          description: Forbidden - insufficient access rights
        422:
          description: Invalid input
        429:
          description: Too many requests in a given amount of time (configurable)
        500:
          description: Dispatch error
      security:
        - dataportal_auth:
            - user
      x-codegen-request-body-name: body

components:
  schemas:
    CRTDLplus:
      type: object
      properties:
        feasibility:
          type: object
          $ref: "#/components/schemas/FeasibilityAndResult"
        dataQuery:
          type: object
          $ref: "#/components/schemas/CRTDL"
    CRTDL:
      type: object
      properties:
        display:
          type: string
          examples:
            - Example CRTDL
        cohortDefinition:
          type: object
          $ref: "#/components/schemas/StructuredQuery"
        dataExtraction:
          type: object
          $ref: "#/components/schemas/DataExtractionQuery"
    DataExtractionQuery:
      type: object
      properties:
        id:
          type: string
          examples:
            - 123
        attributeGroups:
          type: array
          items:
            type: string
            examples:
              - to be done correctly...for now just a placeholder because it doesn't matter for this conversation
    FeasibilityAndResult:
      type: object
      properties:
        dispatchDate:
          type: string
          format: date-time
        resultDate:
          type: string
          format: date-time
        totalNumberOfResults:
          type: integer
    DataQueryListEntry:
      type: object
      required:
        - id
        - label
      properties:
        id:
          type: integer
          format: int64
        label:
          type: string
        comment:
          type: string
        createdAt:
          type: string
          format: date-time
        totalNumberOfPatients:
          type: integer
        isValid:
          type: boolean
    Query:
      type: object
      required:
        - id
        - content
      properties:
        id:
          type: integer
          format: int64
        content:
          $ref: "#/components/schemas/StructuredQuery"
        label:
          type: string
        results:
          $ref: "#/components/schemas/QueryResult"
    QueryResultSummary:
      type: object
      properties:
        totalNumberOfPatients:
          type: integer
          format: int64
        queryId:
          type: string
        resultLines:
          type: array
          items:
            $ref: "#/components/schemas/QueryResultLine"
    QueryResultObfuscated:
      type: object
      properties:
        totalNumberOfPatients:
          type: integer
          format: int64
        queryId:
          type: string
        resultLines:
          type: array
          items:
            $ref: "#/components/schemas/QueryResultLineObfuscated"
    QueryResult:
      type: object
      properties:
        totalNumberOfPatients:
          type: integer
          format: int64
        queryId:
          type: string
        resultLines:
          type: array
          items:
            $ref: "#/components/schemas/QueryResultLine"
    QueryResultLine:
      type: object
      required:
        - siteName
        - numberOfPatients
      properties:
        siteName:
          type: string
        numberOfPatients:
          type: integer
          format: int64
    QueryResultLineObfuscated:
      type: object
      required:
        - siteName
        - numberOfPatients
      properties:
        siteName:
          type: string
          description: obfuscated site name
        numberOfPatients:
          type: integer
          format: int64
    QueryResultRateLimit:
      type: object
      properties:
        limit:
          type: number
          format: int64
        remaining:
          type: number
          format: int64
    QueryTemplateListItem:
      type: object
      required:
        - label
      properties:
        id:
          type: integer
          format: int64
        label:
          type: string
          description: The 'name' of the query. Is assigned by the user via GUI.
          examples:
            - my-query-1
        comment:
          type: string
          description: A more detailed information about the query. Is also assigned by the user via GUI.
          examples:
            - I wanted to see how many patients I could find for my study XYZ
        lastModified:
          type: string
          format: date-time
        createdBy:
          type: string
          description: Keycloak id of the user who created the query
        isValid:
          type: boolean
          description: is the query valid?
    QueryTemplate:
      type: object
      required:
        - label
      properties:
        id:
          type: integer
          format: int64
        label:
          type: string
          description: The 'name' of the query. Is assigned by the user via GUI.
          examples:
            - my-query-1
        comment:
          type: string
          description: A more detailed information about the query. Is also assigned by the user via GUI.
          examples:
            - I wanted to see how many patients I could find for my study XYZ
        content:
          $ref: "#/components/schemas/StructuredQuery"
        lastModified:
          type: string
          format: date-time
        createdBy:
          type: string
          description: Keycloak id of the user who created the query
    StructuredQuery:
      type: object
      required:
        - version
        - inclusionCriteria
      properties:
        version:
          type: string
          format: uri
          description: The json schema version
          examples:
            - http://to_be_decided.com/draft-1/schema#
        display:
          type: string
          examples:
            - foobar
        inclusionCriteria:
          type: array
          items:
            $ref: "#/components/schemas/CriterionList"
        exclusionCriteria:
          type: array
          items:
            $ref: "#/components/schemas/CriterionList"
    SavedQuery:
      type: object
      required:
        - label
      properties:
        label:
          type: string
          description: The 'name' of the query. Is assigned by the user via GUI.
          examples:
            - my-query-1
        comment:
          type: string
          description: A more detailed information about the query. Is also assigned by the user via GUI.
          examples:
            - I wanted to see how many patients I could find for my study XYZ
        totalNumberOfPatients:
          type: integer
          format: int64
          description: The number of results that were found for this query.
          examples:
            - 12345
    SavedQuerySlots:
      type: object
      required:
        - used
        - total
      properties:
        used:
          type: integer
          description: The amount of used saved query slots for a user.
          examples:
            - 2
        total:
          type: integer
          description: The total amount of saved query slots per user.
          examples:
            - 10
    TermCode:
      description: The termCode defines a concept based on a coding system (i.e. LOINC). The triplet of code, system and version identify the concept.
      type: object
      required:
        - code
        - system
        - display
      properties:
        code:
          type: string
          examples:
            - 119373006
        system:
          type: string
          examples:
            - http://snomed.info/sct
        version:
          type: string
          examples:
            - http://snomed.info/sct/900000000000207008/version/20210731
        display:
          type: string
          examples:
            - Amniotic fluid specimen (specimen)
    beforeDate:
      type: string
      format: date-time
    afterDate:
      type: string
      format: date-time
    TimeRestriction:
      anyOf:
        - $ref: "#/components/schemas/beforeDate"
        - $ref: "#/components/schemas/afterDate"
    Unit:
      type: object
      required:
        - code
        - display
      properties:
        code:
          type: string
        display:
          type: string
    AttributeFilter:
      type: object
      description: An AttributeFilter requires different properties, depending on the type. Please refer to the JSON Schema for this.
      required:
        - type
      properties:
        attributeCode:
          $ref: "#/components/schemas/TermCode"
    ValueFilter:
      type: object
      description: A ValueFilter requires different properties, depending on the type. Please refer to the JSON Schema for this.
      required:
        - type
      properties:
        type:
          type: string
          enum:
            - concept
            - quantity-comparator
            - quantity-range
        selectedConcepts:
          type: array
          items:
            $ref: "#/components/schemas/TermCode"
        comparator:
          type: string
          enum:
            - eq
            - ue
            - le
            - lt
            - ge
            - gt
        unit:
          $ref: "#/components/schemas/Unit"
        value:
          type: number
          format: double
        minValue:
          type: number
          format: double
        maxValue:
          type: number
          format: double
    Criterion:
      type: object
      required:
        - termCodes
      properties:
        termCodes:
          type: array
          items:
            $ref: "#/components/schemas/TermCode"
        attributeFilters:
          type: array
          items:
            $ref: "#/components/schemas/AttributeFilter"
        valueFilter:
          $ref: "#/components/schemas/ValueFilter"
        timeRestriction:
          $ref: "#/components/schemas/TimeRestriction"
        issues:
          type: array
          items:
            $ref: "#/components/schemas/ValidationIssue"
    CriterionList:
      type: array
      items:
        $ref: "#/components/schemas/Criterion"
    ContextualizedTermCodeList:
      type: object
      properties:
        contextualizedTermCodes:
          type: array
          items:
            $ref: "#/components/schemas/ContextualizedTermCode"
    ContextualizedTermCode:
      type: object
      properties:
        termcode:
          $ref: "#/components/schemas/TermCode"
        context:
          $ref: "#/components/schemas/TermCode"
    ValidationIssue:
      type: object
      required:
        - code
        - detail
      properties:
        code:
          type: string
          examples:
            - VAL-20001
        detail:
          type: string
          examples:
            - The combination of context and termcode(s) is not found.
  securitySchemes:
    dataportal_auth:
      type: oauth2
      flows:
        implicit:
          authorizationUrl: http://to.be.defined/auth
          scopes:
            user: Dataportal user role
            admin: Dataportal admin role

@juliangruendner
Copy link
Contributor Author

@michael-82 i would prefer Option 2

@michael-82
Copy link
Collaborator

michael-82 commented Feb 14, 2025

Update after discussion from 2025-02-13

General

In the backend we distinguish between "data query" and "feasibility query" (maybe a better wording could be found). Feasibility queries are (right now) the only kind of query that will be sent somewhere.
We decided that there shall be a "wrapper" object around a CRTDL that (can) contain an additional "info" object that contains label, description and results. I guess we can call the object containing the CRTDL and the additional info the dataquery?

The user can create / read / update / delete dataqueries. Basically this is like the template idea from earlier. There will be no necessary validation of anything. The only additional thing that is needed is a name for the query when stored.
Feasibility queries can be posted as before. There will be no link to a dataquery.

Paths

CRUD

  • POST ../query/data save a data query
  • GET ../query/data/{id} load one data query. if a feasibility query is linked to that, include this information (if we go for an additional wrapper around the crtdl)
  • GET ../query/data/{id}/crtdl - get only the crtdl
  • PUT ../query/data/{id} - (accepts json...does not validate) update a data query
  • DELETE ../query/data/{id} - delete the query

List queries

  • GET ../query/data lists id, name and timestamp of all of the current users stored data queries
  • GET ../query/data/by-user/{userid} lists id, name and timestamp of all of a users stored data queries
  • GET ../query/data/saved-query-slots - basically as is

Feasibility

  • POST ../query/feasibility - the "old" execute query endpoint. accepts VALID ccdl
  • GET ../query/feasibilty/{id}/summary-result - basically as is
  • GET ../query/feasibilty/{id}/detailed-result - basically as is
  • GET ../query/feasibilty/{id}/detailed-obfuscated-result - basically as is

Please let me know your thoughts on this @juliangruendner @Shayan1375 @thkoehler11

@juliangruendner juliangruendner modified the milestones: v6.1.0, v7.0.0-alpha Feb 17, 2025
@Shayan1375
Copy link

Shayan1375 commented Feb 17, 2025

CRUD

- GET ../query/data/{id} load one data query. if a feasibility query is linked to that, include this information (if we go for an additional wrapper around the crtdl)

  1. This should also return totalNumberOfPatients, label, and comment.

List queries

- GET ../query/data lists id, name and timestamp of all of the current users stored data queries

  1. This should also return totalNumberOfPatients, label, and comment.
  2. Additionally, it would be useful to indicate whether a Feasibility or DataSelection was created in the CRTDL. The following object could be used:
[
    {
        "id": 119,
        "label": "test1",
        "comment": "test",
        "createdAt": 1738853937484,
        "totalNumberOfPatients": 1327,
        "CCDL": {
            "isValid": boolean,
            "isExistent": boolean // Name can be discussed
        
        },
        "DataSelection": {
            "isValid": boolean,
            "isExistent": boolean // Name can be discussed
        } 
    }
]

Validation

For the initial version, a validation endpoint for the CRTDL should be implemented to verify CCDL criteria and DSE profiles. Future iterations should include deeper validation, such as attributeFilter, valueFilter, and more.

michael-82 added a commit that referenced this issue Feb 18, 2025
- update swaggerfile
- bump version to next major snapshot
michael-82 added a commit that referenced this issue Feb 21, 2025
- update swaggerfile
- bump version to next major snapshot
michael-82 added a commit that referenced this issue Feb 24, 2025
- WIP
- move api to v5
- add Dataquery
- remove query template
- add database migration script
- implement CRUD functions for dataquery
- tests must be adapted
michael-82 added a commit that referenced this issue Feb 24, 2025
- convert saved queries and templates to dataqueries in db migration
michael-82 added a commit that referenced this issue Feb 25, 2025
- update swaggerfile
- bump version to next major snapshot
michael-82 added a commit that referenced this issue Feb 25, 2025
- remove some unused methods and variables
michael-82 added a commit that referenced this issue Feb 25, 2025
- modify script to copy saved queries and templates to not include a "null" dataExtraction object
michael-82 added a commit that referenced this issue Feb 26, 2025
- re-enable websecurity requestmatchers
- remove querytemplate validators
- move get saved query slots (not sure if needed tho)
michael-82 added a commit that referenced this issue Feb 26, 2025
michael-82 added a commit that referenced this issue Feb 26, 2025
- implement tests for DataqueryHandler
michael-82 added a commit that referenced this issue Feb 26, 2025
- add check if user has stored too many dataqueries with result
- fix missing result size in get dataquery
- start working on more tests (lot of code commented out)
michael-82 added a commit that referenced this issue Feb 27, 2025
- add max queries per user variable to DataquerySpringConfig
- don't throw storage full exception on dataquery without result
- fix wrong path on CodeableConceptRestController and TerminologyRestController
- add more tests to check for handling of full storage
michael-82 added a commit that referenced this issue Feb 27, 2025
- update swaggerfile
- bump version to next major snapshot
michael-82 added a commit that referenced this issue Feb 27, 2025
- WIP
- move api to v5
- add Dataquery
- remove query template
- add database migration script
- implement CRUD functions for dataquery
- tests must be adapted
michael-82 added a commit that referenced this issue Feb 27, 2025
- convert saved queries and templates to dataqueries in db migration
michael-82 added a commit that referenced this issue Feb 27, 2025
- remove some unused methods and variables
michael-82 added a commit that referenced this issue Feb 27, 2025
- modify script to copy saved queries and templates to not include a "null" dataExtraction object
michael-82 added a commit that referenced this issue Feb 27, 2025
- re-enable websecurity requestmatchers
- remove querytemplate validators
- move get saved query slots (not sure if needed tho)
michael-82 added a commit that referenced this issue Feb 27, 2025
michael-82 added a commit that referenced this issue Feb 27, 2025
- implement tests for DataqueryHandler
michael-82 added a commit that referenced this issue Feb 27, 2025
- add check if user has stored too many dataqueries with result
- fix missing result size in get dataquery
- start working on more tests (lot of code commented out)
michael-82 added a commit that referenced this issue Feb 27, 2025
- add max queries per user variable to DataquerySpringConfig
- don't throw storage full exception on dataquery without result
- fix wrong path on CodeableConceptRestController and TerminologyRestController
- add more tests to check for handling of full storage
michael-82 added a commit that referenced this issue Feb 27, 2025
- fix feasibility query url in github integration test
michael-82 added a commit that referenced this issue Feb 27, 2025
- update ontology tag in github integration test
- add debug output to check which curl cmd fails
- add check for data storage limits on updates in DataqueryHandlerTest
michael-82 added a commit that referenced this issue Feb 27, 2025
- fix missing path fragment in returned location header when creating a feasibility query
- add missing tests in DataqueryHandlerRestControllerIT
michael-82 added a commit that referenced this issue Feb 27, 2025
- fix wrong method in test for retrieving query slots
- revert verbosity in github action integration test
michael-82 added a commit that referenced this issue Feb 27, 2025
- enable FeasibilityQueryHandlerRestControllerIT
- remove unused tests from FeasibilityQueryHandlerRestControllerIT
michael-82 added a commit that referenced this issue Feb 27, 2025
- enable QueryHandlerServiceIT
- remove unused tests from QueryHandlerServiceIT
- todo: add those tests in a DataqueryHandlerIT
michael-82 added a commit that referenced this issue Feb 28, 2025
- remove unused exception classes
- add DataqueryHandlerIT
michael-82 added a commit that referenced this issue Feb 28, 2025
- remove unused exception classes
- add DataqueryHandlerIT
michael-82 added a commit that referenced this issue Feb 28, 2025
michael-82 added a commit that referenced this issue Feb 28, 2025
- move api to v5
- add Dataquery
- remove query template and saved query
- add database migration script
- remove unused methods, exceptions and tests
- update ontology tag in github integration test
- modify swagger file
- convert saved queries and templates to dataqueries in db migration
michael-82 added a commit that referenced this issue Feb 28, 2025
- remove some unused imports
- fix some minor potential errors
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
5 participants