##############
RecordInFlight
##############

RecordInFlight represents a single record as it moves through the Valence framework. RecordInFlight holds not just the record properties but also metadata such as errors and warnings associated with the record.

***********
Record Data
***********

We think of each data record as a tree with key-value pairs, with nested subtrees if needed. RecordInFlight internally uses two of these tree structures, one with the original properties that it was first created with, one with the properties as they are manipulated and changed by :ref:`extensions-filters`.

Typically you will interact with the properties tree, unless you specifically are interested in reading a value from what the record looked like originally.

RecordInFlight Data Methods
===========================

.. code-block:: java

	// constructor
	global RecordInFlight(Map<String, Object> originalProperties);

	// constructor
	global RecordInFlight(Map<String, Object> originalProperties, String operation);


	global Boolean hasOriginalProperty(String concisePropertyPath);

	global Boolean hasOriginalProperty(List<String> normalizedPropertyPath);

	global Boolean hasOriginalProperty(String concisePropertyPath, Boolean notNull); // is there a property, and is its value also not null?

	global Boolean hasOriginalProperty(List<String> normalizedPropertyPath, Boolean notNull); // is there a property, and is its value also not null?


	global Boolean hasProperty(String concisePropertyPath);

	global Boolean hasProperty(List<String> normalizedPropertyPath);

	global Boolean hasProperty(String concisePropertyPath, Boolean notNull); // is there a property, and is its value also not null?

	global Boolean hasProperty(List<String> normalizedPropertyPath, Boolean notNull); // is there a property, and is its value also not null?


	global Object getOriginalPropertyValue(String concisePropertyPath); // convenience method for when you know for sure there's only one value to get

	global Object getOriginalPropertyValue(List<String> normalizedPropertyPath); // convenience method for when you know for sure there's only one value to get

	global List<Object> getOriginalPropertyValues(String concisePropertyPath);

	global List<Object> getOriginalPropertyValues(List<String> normalizedPropertyPath);


	global Object getPropertyValue(String concisePropertyPath); // convenience method for when you know for sure there's only one value to get

	global Object getPropertyValue(List<String> normalizedPropertyPath); // convenience method for when you know for sure there's only one value to get

	global List<Object> getPropertyValues(String concisePropertyPath);

	global List<Object> getPropertyValues(List<String> normalizedPropertyPath);


	global void setOriginalPropertyValue(String concisePropertyPath, Object value);

	global void setOriginalPropertyValue(List<String> normalizedPropertyPath, Object value);

	global void setOriginalPropertyValues(String concisePropertyPath, List<Object> values);

	global void setOriginalPropertyValues(List<String> normalizedPropertyPath, List<Object> values);


	global void setPropertyValue(String concisePropertyPath, Object value);

	global void setPropertyValue(List<String> normalizedPropertyPath, Object value);

	global void setPropertyValues(String concisePropertyPath, List<Object> values);

	global void setPropertyValues(List<String> normalizedPropertyPath, List<Object> values);


Working with Record Data
========================

.. code-block:: java

	Map<String,Object> originalProps = new Map<String,Object>{
		'firstName' => 'Tom',
		'lastName' => 'Sinatra',
		'company' => new Map<String, Object> {
			'name' => 'Acme',
			'location' => 'USA'
		}
	};

	// creating a RecordInFlight
	valence.RecordInFlight tom = new valence.RecordInFlight(originalProps);

	// accessing the original properties
	System.assertEquals('Sinatra', tom.getOriginalPropertyValue('lastName'));
	System.assertEquals('Acme', tom.getOriginalPropertyValue('company.name'));

	// accessing properties that are being modified during the Link run
	tom.getPropertyValue('discountCode');
	tom.setPropertyValue('seatPreference', 'Aisle');

*****************************
Reporting Errors and Warnings
*****************************

Any :ref:`Adapter <extensions-adapters>` or :ref:`Filter <extensions-filters>` that touches a RecordInFlight can mark that record as having an issue of some kind. Adding errors and warnings to a record has different outcomes depending on how the Valence user has configured the Link.

.. code-block:: java

    global Boolean hasWarnings();

    global void addWarning(String warning);

    global void addWarning(String warning, Exception e);

    global Boolean hasErrors();

    global void addError(String error);

    global void addError(String error, Exception e);

.. _record-in-flight-ignore:

****************
Ignoring Records
****************

If you would like to skip the processing of certain records you can call the ignore method. This removes the record from further processing, and will also track ignore reasons and counts and surface those in the interface for an admin to see.

.. code-block:: java

    global Boolean isIgnored();

    global void ignore(String reason);

*********
Operation
*********

Every RecordInFlight has an **operation**, which is just a string value that suggests an action to the :doc:`/adapter-interfaces/target-adapter`. The default operation value is "upsert". We recommend every SourceAdapter and TargetAdapter support at a minimum these two operations:

	* upsert
	* delete

You are welcome to create custom operation values as long as the TargetAdapter you are working with knows how to handle them.

.. code-block:: java

	global void setOperation(String operation);

	global String getOperation();

********
Metadata
********

There are a few additional metadata properties that can be set or read to better understand what is happening with this particular RecordInFlight.

.. code-block:: java

	// Our first-party Adapters that work with Salesforce orgs will always populate a Salesforce Id value that you can use if you need it
	global Id getSalesforceId();

	// TargetAdapters should set this value
	global void setSuccess(Boolean newValue);

	// was this RecordInFlight successful in being delivered to its destination
	global Boolean isSuccess();

	// TargetAdapters should set this value
	global void setCreated(Boolean newValue);

	// did this RecordInFlight cause a brand new record to be created (true) or did it update or delete an existing record (false)
	global Boolean isCreated();