def delete(self, dataset_uuid, study_id=None, user=None):
        """ Delete a dataset from a study given its unique identifier """
        prop_id_to_name = get_property_map(key="id", value="name")
        prop_name_to_id = reverse_map(prop_id_to_name)

        # Used for helper route using only dataset_uuid
        if study_id is None:
            study_id = find_study_id_from_lvl1_uuid("dataset", dataset_uuid,
                                                    prop_name_to_id)
            if study_id is None:
                raise Exception(
                    f"Dataset not found in any study (uuid = {dataset_uuid})")

        # 1. Get study data
        study = Study.objects().get(id=study_id)
        study_json = marshal(study, study_model)

        study_converter = FormatConverter(mapper=prop_id_to_name)
        study_converter.add_api_format(study_json["entries"])

        # 2. Delete specific dataset
        datasets_entry = study_converter.get_entry_by_name("datasets")
        datasets_entry.value.delete_nested_entry("uuid", dataset_uuid)

        if len(datasets_entry.value.value) == 0:
            study_converter.remove_entries(prop_names=["datasets"])

        # 3. Update study state, data and ulpoad on DB
        message = f"Deleted dataset"
        update_study(study, study_converter, api.payload, message, user)

        return {"message": message}
    def put(self, dataset_uuid, study_id=None, user=None):
        """ Update a dataset for a given study """
        prop_id_to_name = get_property_map(key="id", value="name")
        prop_name_to_id = reverse_map(prop_id_to_name)

        # Used for helper route using only dataset_uuid
        if study_id is None:
            study_id = find_study_id_from_lvl1_uuid("dataset", dataset_uuid,
                                                    prop_name_to_id)
            if study_id is None:
                raise Exception(
                    f"Dataset not found in any study (uuid = {dataset_uuid})")

        payload = api.payload

        # 1. Split payload
        form_name = payload["form_name"]
        entries = payload["entries"]
        entry_format = payload.get("entry_format", "api")

        # 2. Get study data
        study = Study.objects().get(id=study_id)
        study_json = marshal(study, study_model)

        study_converter = FormatConverter(mapper=prop_id_to_name)
        study_converter.add_api_format(study_json["entries"])

        # 3. Get current dataset data
        datasets_entry = study_converter.get_entry_by_name("datasets")
        dataset_nested_entry = datasets_entry.value.find_nested_entry(
            "uuid", dataset_uuid)[0]
        dataset_converter = FormatConverter(mapper=prop_id_to_name)
        dataset_converter.entries = dataset_nested_entry.value

        # 4. Get new dataset data and get entries to remove
        new_dataset_converter, entries_to_remove = get_entity_converter(
            entries, entry_format, prop_id_to_name, prop_name_to_id)

        # 5. Update current dataset by adding, updating and deleting entries
        # Nested entries not present in the original form are ignored (example: dataset["samples"])
        # won't be deleted if not present in the new data), it needs to be None or "" to be deleted
        dataset_converter.add_or_update_entries(new_dataset_converter.entries)
        dataset_converter.remove_entries(entries=entries_to_remove)
        dataset_nested_entry.value = dataset_converter.entries

        # 6. Validate dataset data against form
        validate_form_format_against_form(form_name,
                                          dataset_converter.get_form_format())

        # 7. Update study state, data and ulpoad on DB
        message = "Updated dataset"
        update_study(study, study_converter, payload, message, user)
        return {"message": message}
예제 #3
0
    def delete(self, study_id, user=None):
        """ Delete all samples from a study given its unique identifier """
        prop_id_to_name = get_property_map(key="id", value="name")

        # 1. Get study data
        study = Study.objects().get(id=study_id)
        study_json = marshal(study, study_model)

        study_converter = FormatConverter(mapper=prop_id_to_name)
        study_converter.add_api_format(study_json["entries"])

        # 2. Delete samples
        study_converter.remove_entries(prop_names=["samples"])

        # 3. Update study state, data and ulpoad on DB
        message = "Deleted samples"
        update_study(study, study_converter, api.payload, message, user)

        return {"message": message}
예제 #4
0
    def test_remove_entries(self):
        mapper = {
            "KEEP": "0",
            "REMOVE_1": "1",
            "REMOVE_2": "2",
            "REMOVE_3": "3"
        }

        form_format = {"KEEP": 1, "REMOVE_1": 2, "REMOVE_2": 3, "REMOVE_3": 4}
        c = FormatConverter(mapper=mapper).add_form_format(form_format)
        assert len(c.entries) == 4

        form_format_to_remove = {"REMOVE_1": 2}
        c_remove = FormatConverter(
            mapper=mapper).add_form_format(form_format_to_remove)

        c.remove_entries(entries=c_remove.entries)
        assert len(c.entries) == 3

        c.remove_entries(prop_names=["REMOVE_2"])
        assert len(c.entries) == 2

        c.remove_entries(prop_ids=["3"])
        assert len(c.entries) == 1
        assert c.entries[0].prop_name == "KEEP"
예제 #5
0
    def put(self, sample_uuid, study_id=None, user=None):
        """ Update a sample for a given study """
        prop_id_to_name = get_property_map(key="id", value="name")
        prop_name_to_id = reverse_map(prop_id_to_name)

        # Used for helper route using only sample_uuid
        if study_id is None:
            study_id = find_study_id_from_lvl1_uuid("sample", sample_uuid,
                                                    prop_name_to_id)
            if study_id is None:
                raise Exception(
                    f"Sample not found in any study (uuid = {sample_uuid})")

        payload = api.payload

        # 1. Split payload
        validate_dict = payload.get("validate", None)
        form_names = payload.get("form_names", None)
        entries = payload["entries"]
        entry_format = payload.get("entry_format", "api")

        # 2. Get forms for validation
        forms = {}
        for key, validate in validate_dict.items():
            if validate:
                forms[key] = app.form_manager.get_form_by_name(
                    form_name=form_names[key])

        # 3. Get study data
        study = Study.objects().get(id=study_id)
        study_json = marshal(study, study_model)

        study_converter = FormatConverter(mapper=prop_id_to_name)
        study_converter.add_api_format(study_json["entries"])

        # 3. Get current sample data
        samples_entry = study_converter.get_entry_by_name("samples")
        sample_nested_entry = samples_entry.value.find_nested_entry(
            "uuid", sample_uuid)[0]
        sample_converter = FormatConverter(mapper=prop_id_to_name)
        sample_converter.entries = sample_nested_entry.value

        # 4. Unify UUIDs with existing entities (including nested ones)
        # Format and clean entity
        new_sample_converter, _ = get_entity_converter(entries, entry_format,
                                                       prop_id_to_name,
                                                       prop_name_to_id)

        new_sample_form_format = new_sample_converter.get_form_format()

        [new_sample_form_format] = unify_sample_entities_uuids(
            existing_samples=study_converter.get_form_format().get(
                "samples", []),
            new_samples=[new_sample_form_format],
        )

        # 5. Clean new data and get entries to remove
        # Format and clean entity
        new_sample_converter, entries_to_remove = get_entity_converter(
            entries=new_sample_form_format,
            entry_format="form",
            prop_id_to_name=None,
            prop_name_to_id=prop_name_to_id,
        )

        # 6. Update current sample by adding, updating and deleting entries
        # Nested entries not present in the original form are ignored
        # won't be deleted if not present in the new data), it needs to be None or "" to be deleted
        sample_converter.add_or_update_entries(new_sample_converter.entries)
        sample_converter.remove_entries(entries=entries_to_remove)
        sample_nested_entry.value = sample_converter.entries

        # 7. Validate data against form
        validate_sample_against_form(sample_converter.get_form_format(),
                                     validate_dict, forms)

        # 8. Update study state, data and ulpoad on DB
        message = "Updated sample"
        update_study(study, study_converter, payload, message, user)
        return {"message": message}
예제 #6
0
    def post(self, study_id, user=None):
        """ Add multiple new samples for a given study """
        payload = api.payload

        prop_id_to_name = get_property_map(key="id", value="name")
        prop_name_to_id = reverse_map(prop_id_to_name)

        # 1. Split payload
        validate_dict = payload.get("validate", None)
        form_names = payload.get("form_names", None)
        entries_list = payload["entries"]
        entry_format = payload.get("entry_format", "api")
        replace = payload.get("replace", False)

        # 2. Get forms for validation
        forms = {}
        for key, validate in validate_dict.items():
            if validate:
                forms[key] = app.form_manager.get_form_by_name(
                    form_name=form_names[key])

        # 3. Get study data
        study = Study.objects().get(id=study_id)
        study_json = marshal(study, study_model)

        study_converter = FormatConverter(mapper=prop_id_to_name)
        study_converter.add_api_format(study_json["entries"])

        # 4. Unify UUIDs with existing entities (including nested ones)
        new_samples_form_format = []
        for entries in entries_list:
            # Format and clean entity
            sample_converter, _ = get_entity_converter(entries, entry_format,
                                                       prop_id_to_name,
                                                       prop_name_to_id)
            new_samples_form_format.append(sample_converter.get_form_format())

        new_samples_form_format = unify_sample_entities_uuids(
            existing_samples=study_converter.get_form_format().get(
                "samples", []),
            new_samples=new_samples_form_format,
        )

        # 5. Append new samples to "samples" in study
        if replace:
            study_converter.remove_entries(prop_names=["samples"])

        sample_uuids = []
        for sample_form_format in new_samples_form_format:
            # Format and clean entity
            sample_converter, _ = get_entity_converter(
                entries=sample_form_format,
                entry_format="form",
                prop_id_to_name=None,
                prop_name_to_id=prop_name_to_id,
            )

            # Generate UUID (redundant, UUIDs already generated by unify_sample_entities_uuids)
            sample_converter, sample_uuid = add_uuid_entry_if_missing(
                sample_converter, prop_name_to_id)

            study_converter = add_entity_to_study_nested_list(
                study_converter=study_converter,
                entity_converter=sample_converter,
                prop_name_to_id=prop_name_to_id,
                study_list_prop="samples",
            )

            sample_uuids.append(sample_uuid)

            # 6. Validate data against form
            validate_sample_against_form(sample_converter.get_form_format(),
                                         validate_dict, forms)

        # 7. Update study state, data and ulpoad on DB
        message = f"Added {len(sample_uuids)} samples (replace = {replace})"
        update_study(study, study_converter, payload, message, user)
        return {"message": message, "uuids": sample_uuids}, 201