def bulk_delete(self, *filters_or_records): """Shortcut to bulk delete records .. versionadded:: 2.17.0 Args: *filters_or_records (tuple) or (Record): Either a list of Records, or a list of filters. Notes: Requires Swimlane 2.17+ Examples: :: # Bulk delete records by filter app.records.bulk_delete( ('Field_1', 'equals', value1), ('Field_2', 'equals', value2) ) # Bulk delete by record instances record1 = app.records.get(tracking_id='APP-1') record2 = app.records.get(tracking_id='APP-2') record3 = app.records.get(tracking_id='APP-3') app.records.bulk_delete(record1, record2, record3) Returns: :class:`string`: Bulk Modify Job ID """ _type = validate_filters_or_records(filters_or_records) data_dict = {} # build record_id list if _type is Record: record_ids = [] for record in filters_or_records: record_ids.append(record.id) data_dict['recordIds'] = record_ids # build filters else: filters = [] record_stub = record_factory(self._app) for filter_tuples in filters_or_records: field = record_stub.get_field(filter_tuples[0]) filters.append({ "fieldId": field.id, "filterType": filter_tuples[1], "value": field.get_report(filter_tuples[2]) }) data_dict['filters'] = filters return self._swimlane.request('DELETE', "app/{0}/record/batch".format( self._app.id), json=data_dict).text
def bulk_create(self, *records): """Create and validate multiple records in associated app Args: *records (dict): One or more dicts of new record field names and values Notes: Requires Swimlane 2.15+ Validates like :meth:`create`, but only sends a single request to create all provided fields, and does not return the newly created records Any validation failures on any of the records will abort the batch creation, not creating any new records Does not return the newly created records Examples: Create 3 new records with single request :: app.records.bulk_create( {'Field 1': 'value 1', ...}, {'Field 1': 'value 2', ...}, {'Field 1': 'value 3', ...} ) Raises: swimlane.exceptions.UnknownField: If any field in any new record cannot be found swimlane.exceptions.ValidationError: If any field in any new record fails validation TypeError: If no dict of fields was provided, or any provided argument is not a dict """ if not records: raise TypeError('Must provide at least one record') if any(not isinstance(r, dict) for r in records): raise TypeError('New records must be provided as dicts') # Create local records from factory for initial full validation new_records = [] for record_data in records: record = record_factory(self._app, record_data) record.validate() new_records.append(record) self._swimlane.request('post', 'app/{}/record/batch'.format(self._app.id), json=[r._raw for r in new_records])
def create(self, **fields): """Create and return a new record in associated app and return the newly created Record instance Args: **fields: Field names and values to be validated and sent to server with create request Notes: Keyword arguments should be field names with their respective python values Field values are validated before sending create request to server Examples: Create a new record on an app with simple field names :: record = app.records.create( field_a='Some Value', someOtherField=100, ... ) Create a new record on an app with complex field names :: record = app.records.create(**{ 'Field 1': 'Field 1 Value', 'Field 2': 100, ... }) Returns: Record: Newly created Record instance with data as returned from API response Raises: swimlane.exceptions.UnknownField: If any fields are provided that are not available on target app swimlane.exceptions.ValidationError: If any field fails validation before creation """ new_record = record_factory(self._app, fields) new_record.save() return new_record
def filter(self, field_name, operand, value): """Adds a filter to report Notes: All filters are currently AND'ed together Args: field_name (str): Target field name to filter on operand (str): Operand used in comparison. See `swimlane.core.search` for options value: Target value used in comparision """ if operand not in self._FILTER_OPERANDS: raise ValueError('Operand must be one of {}'.format(', '.join( self._FILTER_OPERANDS))) # Use temp Record instance for target app to translate values into expected API format record_stub = record_factory(self._app) field = record_stub.get_field(field_name) self._raw['filters'].append({ "fieldId": field.id, "filterType": operand, "value": field.get_report(value) })
def bulk_modify(self, *filters_or_records, **kwargs): """Shortcut to bulk modify records .. versionadded:: 2.17.0 Args: *filters_or_records (tuple) or (Record): Either a list of Records, or a list of filters. Keyword Args: values (dict): Dictionary of one or more 'field_name': 'new_value' pairs to update Notes: Requires Swimlane 2.17+ Examples: :: # Bulk update records by filter app.records.bulk_modify( # Query filters ('Field_1', 'equals', value1), ('Field_2', 'equals', value2), ... # New values for records values={ "Field_3": value3, "Field_4": value4, ... } ) # Bulk update records record1 = app.records.get(tracking_id='APP-1') record2 = app.records.get(tracking_id='APP-2') record3 = app.records.get(tracking_id='APP-3') app.records.bulk_modify(record1, record2, record3, values={"Field_Name": 'new value'}) Returns: :class:`string`: Bulk Modify Job ID """ values = kwargs.pop('values', None) if kwargs: raise ValueError('Unexpected arguments: {}'.format(kwargs)) if not values: raise ValueError('Must provide "values" as keyword argument') if not isinstance(values, dict): raise ValueError( "values parameter must be dict of {'field_name': 'update_value'} pairs" ) _type = validate_filters_or_records(filters_or_records) request_payload = {} record_stub = record_factory(self._app) # build record_id list if _type is Record: request_payload['recordIds'] = [ record.id for record in filters_or_records ] # build filters else: filters = [] for filter_tuples in filters_or_records: field_name = record_stub.get_field(filter_tuples[0]) filters.append({ "fieldId": field_name.id, "filterType": filter_tuples[1], "value": field_name.get_report(filter_tuples[2]) }) request_payload['filters'] = filters # Ensure all values are wrapped in a bulk modification operation, defaulting to Replace if not provided for # backwards compatibility for field_name in list(values.keys()): modification_operation = values[field_name] if not isinstance(modification_operation, _BulkModificationOperation): values[field_name] = Replace(modification_operation) # build modifications modifications = [] for field_name, modification_operation in values.items(): # Lookup target field modification_field = record_stub.get_field(field_name) if not modification_field.bulk_modify_support: raise ValueError( "Field '{}' of Type '{}', is not supported for bulk modify" .format(field_name, modification_field.__class__.__name__)) modifications.append({ "fieldId": { "value": modification_field.id, "type": "id" }, "value": modification_field.get_bulk_modify( modification_operation.value), "type": modification_operation.type }) request_payload['modifications'] = modifications response = self._swimlane.request('put', "app/{0}/record/batch".format( self._app.id), json=request_payload) # Update records if instances were used to submit bulk modify request after request was successful if _type is Record: for record in filters_or_records: for field_name, modification_operation in six.iteritems( values): record[field_name] = modification_operation.value return response.text
def test_repr(self, mock_record): assert repr(mock_record) == '<Record: RA-7>' assert repr(record_factory(mock_record.app)) == '<Record: RA - New>'
def _get_stub_field(self, field_name): # Use temp Record instance for target app to translate values into expected API format record_stub = record_factory(self._app) return record_stub.get_field(field_name)