Views:

You can extend LUSID's data model by adding additional information onto entities in the form of properties

Every property in LUSID has a definition, which captures information about the nature of the property. Part of the definition has a concept of ‘lifetime', which can either be time-variant or perpetual, and indicates whether the value is expected to change over time or be valid 'forever'.

Note: If you do not explicitly set a lifetime, it defaults to perpetual. For background information on bitemporality and LUSID, see this article.

Perpetual properties

A perpetual property has a value that is considered to be permanent in LUSID, for example a person's place of birth. 

When you set a perpetual property value, it is applied with the current AsAt date and is effective from the beginning of time until the end of time. For example, to set John Smith’s place of birth, you might make the following request:

URL: POST /api/persons/corporate/username/john_smith/properties
Request body:


  "properties": { 
    "person/info/placeOfBirth": [ 
      { 
        "key": "Person/info/placeOfBirth", 
        "value": { 
          "labelValue": "London" 
        } 
      } 
    ] 
  } 

The response would be as follows:


  "displayName": "JohnSmith", 
  "identifiers": { 
    "person/corporate/username": { 
      "key": "Person/corporate/username", 
      "value": { 
        "labelValue": "john_smith" 
      } 
    } 
  }, 
  "properties": { 
    "person/info/placeOfBirth": [ 
      { 
        "key": "Person/info/placeOfBirth", 
        "value": { 
          "labelValue": "London" 
        }, 
        "effectiveFrom": "0001-01-01T00:00:00.0000000+00:00", 
        "effectiveUntil": "9999-12-31T23:59:59.9999999+00:00" 
      } 
    ] 
   }, 
  "version": { 
    "effectiveFrom": "2021-08-03T00:00:00.0000000+00:00", 
    "asAtDate": "1"  // Integer value used for illustrative purposes; the actual system time uses the 0000-00-00T00:00:00.0000000+00:00 format. 
  } 
}

We can represent this visually as follows:

While the property is considered perpetual, it is of course possible to enter the wrong information. LUSID allows you to correct bad data by overwriting any perpetual property value. A full audit history is maintained, with past values available by requesting the property with an AsAt datetime prior to the correction. The new value is stored with the AsAt datetime of the correction, which we could represent visually as follows:

Time-variant properties

A time-variant property has a value that is considered likely to change in LUSID over time, for example a person's address. A time-variant property is therefore associated with an effective date range.

The effective date range is described by effectiveFrom and effectiveUntil datetimes. If no effectiveUntil date is provided then the value will be applied until the effectiveFrom date of the next value in the timeline (which is the end of time if there are no subsequent values). 

Consider the following sequence of events. In the first request, we'll set John Smith's address to be 1 Main Street, with an effectiveFrom date of 1 January 2019 until the end of time. 

First request: AsAt=1
URL: POST /api/persons/corporate/username/john_smith/properties
Request body:


  "properties": { 
    "person/info/address": [ 
      { 
        "key": "Person/info/address", 
        "value": { 
          "labelValue": "1 Main Street" 
        }, 
        "effectiveFrom": "2019-01-01T00:00:00.00Z" 
      } 
    ] 
  } 

In the second request, we'll update John Smith's address to be 2 High Street, with an effectiveFrom date of 1 January 2020 until the end of time. The previous value of 1 Main Street is automatically updated so that it is now effectiveUntil the 1 January 2020.

Second request: AsAt=2
URL: POST /api/persons/corporate/username/john_smith/properties
Request body:


  "properties": { 
    "person/info/address": [ 
      { 
        "key": "Person/info/address", 
        "value": { 
          "labelValue": "2 High Street" 
        }, 
        "effectiveFrom": "2020-01-01T00:00:00.00Z" 
      } 
    ] 
  } 

We subsequently learn that instead of moving to 2 High Street on 1 January 2020, John Smith actually moved to 3 Station Road, staying there for one year. In the third request, we'll change the property value to 3 Station Road with an effectiveFrom date of 1 January 2020, and specify an explicit effectiveUntil date of 1 January 2021. This is now the 'second value'. The previous second value of 2 High Street becomes the 'third value'; its effectiveFrom date is automatically updated to 1 January 2021.

Second request: AsAt=3
URL: POST /api/persons/corporate/username/john_smith/properties
Request body:


  "properties": { 
    "person/info/address": [ 
      { 
        "key": "Person/info/address", 
        "value": { 
          "labelValue": "3 Station Road" 
        }, 
        "effectiveFrom": "2020-01-01T00:00:00.00Z" 
        "effectiveUntil": "2021-01-01T00:00:00.00Z" 
      } 
    ] 
  } 

We can represent this visually as follows:

Retrieving property values as a time series

You can specify EffectiveAt and AsAt datetimes when retrieving properties for an entity, but it can be difficult and time-consuming to try to understand the full extent of historic changes.

Certain types of entity therefore have property time series API endpoints that return the full list of values for a particular property. For example, for a Person entity you could use the LUSID GET ​/api​/persons​/{idTypeScope}​/{idTypeCode}​/{code}​/properties​/time-series API endpoint, specifying the person's identifier in the URL and the property key as a query string parameter.

If we retrieve John Smith's time-variant address property, for example, we can see that values are returned firstly in EffectiveAt datetime order, and subsequently in AsAt datetime order if they cover the same period. Values that are no longer valid at the AsAt datetime of the request have the status superseded, and current values have the status prevailing:


  "values": [ 
    { 
      "value": { 
        "labelValue": "1 Main Street" 
      }, 
      "effectiveRange": { 
        "fromDate": "2019-01-01T00:00:00.0000000+00:00", 
        "untilDate": "9999-12-31T23:59:59.9999999+00:00" 
      }, 
      "asAtRange": { 
        "fromDate": "1", 
        "untilDate": "2" 
      }, 
      "status": "superseded" 
    }, 
    { 
      "value": { 
        "labelValue": "1 Main Street" 
      }, 
      "effectiveRange": { 
        "fromDate": "2019-01-01T00:00:00.0000000+00:00", 
        "untilDate": "2020-01-01T00:00:00.0000000+00:00" 
      }, 
      "asAtRange": { 
        "fromDate": "2" 
      }, 
      "status": "prevailing" 
    }, 
    { 
      "value": { 
        "labelValue": "2 High Street" 
      }, 
      "effectiveRange": { 
        "fromDate": "2020-01-01T00:00:00.0000000+00:00", 
        "untilDate": "9999-12-31T23:59:59.9999999+00:00" 
      }, 
      "asAtRange": { 
        "fromDate": "2", 
        "untilDate": "3" 
      }, 
      "status": "superseded" 
    }, 
    { 
      "value": { 
        "labelValue": "3 Station Rd" 
      }, 
      "effectiveRange": { 
        "fromDate": "2020-01-01T00:00:00.0000000+00:00", 
        "untilDate": "2021-01-01T00:00:00.0000000+00:00" 
      }, 
      "asAtRange": { 
        "fromDate": "3" 
      }, 
      "status": "prevailing" 
    }, 
    { 
      "value": { 
        "labelValue": "2 High Street" 
      }, 
      "effectiveRange": { 
        "fromDate": "2021-01-01T00:00:00.0000000+00:00", 
        "untilDate": "9999-12-31T23:59:59.9999999+00:00" 
      }, 
      "asAtRange": { 
        "fromDate": "3" 
      }, 
      "status": "prevailing" 
    } 
  ] 
}

To only retrieve prevailing values, set the API endpoint's filter parameter, for example status eq 'prevailing'.