def mutate(self, info, resource_data=None): # We must merge in existing resource.data if we are updating if R.has('id', resource_data): # New data gets priority, but this is a deep merge. resource_data['data'] = R.merge_deep( Resource.objects.get(id=resource_data['id']).data, R.prop_or({}, 'data', resource_data)) # Modifies defaults value to add .data.graph # We could decide in the future to generate this derived data on the client, but it's easy enough to do here modified_resource_data = enforce_unique_props(resource_fields, resource_data) # Make sure that all props are unique that must be, either by modifying values or erring. update_or_create_values = input_type_parameters_for_update_or_create( resource_fields, modified_resource_data) # Add the sankey data unless we are updating the instance without updating instance.data update_or_create_values_with_sankey_data = R.merge( update_or_create_values, dict(defaults=add_sankey_graph_to_resource_dict( update_or_create_values['defaults']))) if R.has( 'defaults', update_or_create_values) else update_or_create_values resource, created = update_or_create_with_revision( Resource, update_or_create_values_with_sankey_data) return UpsertResource(resource=resource)
def mutate(self, info, group_state_data=None): """ Update or create the group state :param info: :param group_state_data: :return: """ update_or_create_values = input_type_parameters_for_update_or_create(group_state_fields, group_state_data) # We can do update_or_create since we have a unique group_id in addition to the unique id group_state, created = update_or_create_with_revision(GroupState, update_or_create_values) return UpsertGroupState(group_state=group_state)
def mutate(self, info, group_data=None): group_model = Group() data = R.merge( group_data, dict(password=make_password(R.prop('password', group_data), salt='not_random')) if R.prop_or(False, 'password', group_data) else {}) update_or_create_values = input_type_parameters_for_update_or_create( group_fields, data) group, created = update_or_create_with_revision( group_model, update_or_create_values) return UpsertGroup(group=group)
def mutate(self, info, search_location_data=None): deleted_search_location_response = delete_if_marked_for_delete( SearchLocation, UpsertSearchLocation, 'search_location', search_location_data) if deleted_search_location_response: return deleted_search_location_response modified_search_location_data = R.compose( # Make sure that all props are unique that must be, either by modifying values or erring. lambda data: enforce_unique_props(search_location_fields, data), # Remove the many to many values. They are saved separately lambda data: R.omit(['jurisdictions'], data))(search_location_data) update_or_create_values = input_type_parameters_for_update_or_create( search_location_fields, modified_search_location_data) search_location, created = update_or_create_with_revision( SearchLocation, update_or_create_values) # SearchJurisdictions can be created during the creation of search_locations if R.prop_or(False, 'jurisdictions', search_location_data): existing_search_intersections_by_id = R.index_by( R.prop('id'), search_location.jurisdictions.all()) for search_jurisdiction_unsaved in R.prop('intersections', search_location_data): # existing instances have an id search_jursidiction_id = R.prop_or( None, 'id', search_jurisdiction_unsaved) search_jurisdiction, created = update_or_create_with_revision( SearchJurisdiction, R.merge( R.prop(search_jursidiction_id, existing_search_intersections_by_id) if search_jursidiction_id else {}, search_jurisdiction_unsaved)) # Once saved, add it to the search location search_location.jurisdictions.set(search_jurisdiction) return UpsertSearchLocation(search_location=search_location)
def mutate(self, info, jurisdiction_data=None): deleted_jurisdiction_response = delete_if_marked_for_delete( Jurisdiction, UpsertJurisdiction, 'jurisdiction', jurisdiction_data) if deleted_jurisdiction_response: return deleted_jurisdiction_response # Make sure that all props are unique that must be, either by modifying values or erring. modified_jurisdiction_data = enforce_unique_props( jurisdiction_fields, jurisdiction_data) update_or_create_values = input_type_parameters_for_update_or_create( jurisdiction_fields, modified_jurisdiction_data) jurisdiction, created = update_or_create_with_revision( Jurisdiction, update_or_create_values) return UpsertJurisdiction(jurisdiction=jurisdiction)
def mutate(self, info, settings_data=None): # We must merge in existing settings.data if we are updating data if R.has('id', settings_data) and R.has('data', settings_data): # New data gets priority, but this is a deep merge. settings_data['data'] = R.merge_deep( Settings.objects.get(id=settings_data['id']).data, settings_data['data']) # Make sure that all props are unique that must be, either by modifying values or erring. modified_settings_data = enforce_unique_props(settings_fields, settings_data) update_or_create_values = input_type_parameters_for_update_or_create( settings_fields, modified_settings_data) settings, created = update_or_create_with_revision( Settings, update_or_create_values) return UpsertSettings(settings=settings)
def mutate(self, info, foo_data=None): modified_foo_data = R.merge( # Make sure unique fields are enforced, here by incrementing foo.key enforce_unique_props(foo_fields, foo_data), dict( # Force the FeatureCollection geojson into the GEOSGeometryCollection. This is just Geometry geo_collection=ewkt_from_feature_collection( foo_data['geojson']) if R.prop('geojson', foo_data) else {}, # Put the full FeatureCollection geojson into the geojson field. geojson=foo_data['geojson'] if R.prop('geojson', foo_data) else {})) update_or_create_values = input_type_parameters_for_update_or_create( foo_fields, modified_foo_data) foo, created = update_or_create_with_revision(Foo, update_or_create_values) return UpsertFoo(foo=foo)
def mutate(self, info, location_data=None): with transaction.atomic(): deleted_location_response = delete_if_marked_for_delete(Location, UpsertLocation, 'location', location_data) if deleted_location_response: return deleted_location_response # We must merge in existing location.data if we are updating data if R.has('id', location_data) and R.has('data', location_data): # New data gets priority, but this is a deep merge. location_data['data'] = R.merge_deep( Location.objects.get(id=location_data['id']).data, location_data['data'] ) # Make sure that all props are unique that must be, either by modifying values or erring. modified_location_data = enforce_unique_props(location_fields, location_data) update_or_create_values = input_type_parameters_for_update_or_create(location_fields, modified_location_data) location, created = update_or_create_with_revision(Location, update_or_create_values) return UpsertLocation(location=location)
def mutate(self, info, user_state_data=None): """ Update or create the user state :param info: :param user_state_data: :return: """ # Check that all the scope instances in user_state.data exist. We permit deleted instances for now. new_data = R.prop_or({}, 'data', user_state_data) # Copy since Graphene reuses this data copied_new_data = copy.deepcopy(new_data) old_user_state_data = UserState.objects.get( id=user_state_data['id'] ).data if R.prop_or(None, 'id', user_state_data) else None # Inspect the data and find all scope instances within UserState.data # This includes userRegions[*].region, userProject[*].project and within userRegions and userProjects # userSearch.userSearchLocations[*].search_location and whatever the implementing libraries define # in addition updated_new_data = validate_and_mutate_scope_instances( user_state_scope_instances_config, copied_new_data ) # If either userProjects or userRegions are null, it means those scope instances aren't part # of the update, so merge in the old values if R.prop_or(None, 'id', user_state_data) and R.any_satisfy( lambda user_scope_key: not R.prop_or(None, user_scope_key, updated_new_data), ['userProjects', 'userRegions'] ): # The special update case where one userScope collection is null, # indicates that we are only updating one userScope object. The rest # should remain the same and not be removed for user_scope_key in ['userProjects', 'userRegions']: # Database values old_user_scopes_by_id = user_scope_instances_by_id( user_scope_key, old_user_state_data ) # New values with updates applied new_user_scopes_by_id = user_scope_instances_by_id( user_scope_key, updated_new_data ) # Prefer the old over the new, merging all objects but overriding lists # We override lists because a non-null list always replaces the old list in the database updated_new_data[user_scope_key] = R.values(R.merge_deep( old_user_scopes_by_id, new_user_scopes_by_id, MyMerger( # pass in a list of tuples,with the # strategies you are looking to apply # to each type. [ (list, ["override_non_null"]), (dict, ["merge"]) ], # next, choose the fallback strategies, # applied to all other types: ["override"], # finally, choose the strategies in # the case where the types conflict: ["override"] ) )) # Update user_state_data the updated data modified_user_state_data = R.merge(user_state_data, dict(data=updated_new_data)) # id or user.id can be used to identify the existing instance id_props = R.compact_dict( dict( id=R.prop_or(None, 'id', modified_user_state_data), user_id=R.item_str_path_or(None, 'user.id', modified_user_state_data) ) ) def fetch_and_merge(modified_user_state_data, props): existing = UserState.objects.filter(**props) # If the user doesn't have a user state yet if not R.length(existing): return modified_user_state_data return merge_data_fields_on_update( ['data'], R.head(existing), # Merge existing's id in case it wasn't in user_state_data R.merge(modified_user_state_data, R.pick(['id'], existing)) ) modified_data = R.if_else( R.compose(R.length, R.keys), lambda props: fetch_and_merge(modified_user_state_data, props), lambda _: modified_user_state_data )(id_props) update_or_create_values = input_type_parameters_for_update_or_create( user_state_fields, # Make sure that all props are unique that must be, either by modifying values or erring. enforce_unique_props( user_state_fields, modified_data) ) user_state, created = update_or_create_with_revision(UserState, update_or_create_values) return UpsertUserState(user_state=user_state)