Create FRIM 7.2.1 relationship view from FRIM 5.5.1.3

The following is a quick guide to creating a FRIM 7.2.1 view of a FRIM 5.5.1.3 RELATIONSHIP table, which could be used for migration purposes

Overview

Given a FRIM 5.5.1.3 Relationship table Schema with data

ID OBJECTTYPES_ID OBJECTID REV FULLOBJECT–
3 7 70d1386b-8290-4ec4-ad86-0316b7e4f24d 0 {"firstId":"managed/credential/04973da5-c618-4498-bf93-ef9eaddcae88","firstPropertyName":"userName","secondId":"managed/user/c5a3e54f-bb4b-4932-b814-9cdce75a3147","secondPropertyName":"credential","properties":{},"_id":"70d1386b-8290-4ec4-ad86-0316b7e4f24d","_rev":"0"}

we need to translate it to the FRIM 7.2.1 RELATIONSHIP Table Schema

ID OJECTTYPES_ID OBJECTID REV FULLOBJECT FIRSTRESOURCECOLLECTION FIRSTRESOURCEID FIRSTPROPERTYNAME SECONDRESOURCECOLLECTION SECONDRESOURCEID SECONDPROPERTYNAME
3 70d1386b-8290-4ec4-ad86-0316b7e4f24d 10 0 {"firstResourceCollection":"managed/credential","firstResourceId":"04973da5-c618-4498-bf93-ef9eaddcae88","firstPropertyName":"userName","secondResourceCollection":"managed/user","secondResourceId":"c5a3e54f-bb4b-4932-b814-9cdce75a3147","secondPropertyName":"credential","properties":null,"_id":"70d1386b-8290-4ec4-ad86-0316b7e4f24d","_rev":0} managed/credential 04973da5-c618-4498-bf93-ef9eaddcae88 userName managed/user c5a3e54f-bb4b-4932-b814-9cdce75a3147 credential

During a normal migration the following script is run

/*
 * Copyright 2018 ForgeRock AS. All Rights Reserved
 *
 * Use of this code requires a commercial software license with ForgeRock AS.
 * or with one of its affiliates. All use shall be exclusively subject
 * to such license between the licensee and ForgeRock AS.
 */

var pagedResultsCookie = null;
/** Sets the initial query params. */
var params = {
    '_queryFilter': 'true',
    '_pageSize': 1000
};

do {
    var relationships = openidm.query('repo/relationships', params);
    if (pagedResultsCookie != null) {
        params._pagedResultsCookie = pagedResultsCookie;
    }
    /** update the cookie with the new one from the query. */
    pagedResultsCookie = relationships.pagedResultsCookie;

    relationships.result.forEach(function(r) {
        openidm.update("repo/relationships/" + r._id, r._rev, {
            "_id": r._id,
            "_rev": r._rev,
            "firstResourceId": org.forgerock.json.resource.ResourcePath.valueOf(r.firstId).leaf(),
            "firstResourceCollection": org.forgerock.json.resource.ResourcePath.valueOf(r.firstId).parent().toString(),
            "firstPropertyName": r.firstPropertyName,
            "secondResourceId": org.forgerock.json.resource.ResourcePath.valueOf(r.secondId).leaf(),
            "secondResourceCollection": org.forgerock.json.resource.ResourcePath.valueOf(r.secondId).parent().toString(),
            "secondPropertyName": r.secondPropertyName,
            "properties": r.properties
        });
    });
} while (pagedResultsCookie !== null);

In essence this loops through all the existing 5.5.1.3 relatonships and converts them into the 7.2.1 format.

We can emulate this functionality through creating a view that translates the data in a similair way, and for this it is necessary to have a function funcResourcePath that converts a Managed Object Path into its component parts of parent and leaf. This function will require a object that contains these values so that they can be returned and used in the view. Finally this object can be used in the view.

Create Object

We need to create an object that contains the parent and leaf data. Since a Managed Object is identified by a UUID we can set the leaf value to be a VARCHAR2 of length 36. For the parent this could be very large, but for this we are going to set it to a length of 255 characters.

create or replace type resourcePath as object
    ( parent VARCHAR2(255),
      leaf VARCHAR2(36)
    )

Create Function

given a string managed/credential/04973da5-c618-4498-bf93-ef9eaddcae88 it will convert into resourcepath object

parent leaf
managed/credential 04973da5-c618-4498-bf93-ef9eaddcae88

We use the regexp_substr function to help us use a regular expression to find the 2 groups parent and leaf values. It may not be the most efficient and tuning will be required to find the best way to make this efficient for daily usage. the regular expression is (.*)\/(.*) which will split a MO string into the 2 component parts. Finally the parent and leaf values are returned in a resourcePath object.

create or replace function funcResourcePath
   (p_path IN VARCHAR2)
   RETURN resourcePath
IS
   v_file resourcePath;
   parent varchar2(255);
   leaf varchar2(36);
BEGIN
    leaf := regexp_substr(p_path, '(.*)\/(.*)',1,1,NULL,2);
    parent := regexp_substr(p_path, '(.*)\/(.*)',1,1,NULL,1);
    v_file := resourcePath(parent,leaf);
    RETURN
       v_file;
END;

Ceate View

Since FRM 5.5.1.3 stores the data needed in a JSON string in a CLOB we need to be able to convert that CLOB into a JSON_TABLE and then use that table to extract the necessary values for the FRIM 7.2.1 RELATONSHIP table.

       JSON_TABLE(fullobject, '$'
         COLUMNS (FIRSTID            VARCHAR2(100 CHAR) PATH '$.firstId',
                  FIRSTPROPERTYNAME  VARCHAR2(50 CHAR)  PATH '$.firstPropertyName',
                  SECONDID           VARCHAR2(100 CHAR) PATH '$.secondId',
                  SECONDPROPERTYNAME VARCHAR2(50 CHAR)  PATH '$.secondPropertyName',
                  PROPS              VARCHAR2(50 CHAR)  PATH '$.properties',
                  META_ID            VARCHAR2(50 CHAR)  PATH '$._id',
                  META_REV           VARCHAR2(50 CHAR)  PATH '$._rev'
         )) jt;

This pivots the data so that we can read it in a select statement.

Next we need to be able to create a new FULLOBJECT value and for that we can use the JSON_OBJECT function

       JSON_OBJECT('firstResourceCollection'  VALUE funcResourcePath(jt.FIRSTID).parent,
                   'firstResourceId'          VALUE funcResourcePath(jt.FIRSTID).leaf,
                   'firstPropertyName'        VALUE jt.FIRSTPROPERTYNAME,
                   'secondResourceCollection' VALUE funcResourcePath(jt.SECONDID).parent,
                   'secondResourceId'         VALUE funcResourcePath(jt.SECONDID).leaf,
                   'secondPropertyName'       VALUE jt.SECONDPROPERTYNAME,
                   'properties'               VALUE jt.PROPS,
                   '_id'                      VALUE jt.META_ID,
                   '_rev'                     VALUE jt.META_REV
         FORMAT JSON) as FULLOBJECT

Here we are converting the 5.5.1.3 data into FRIM 7.2.1 data and use the funcResourcePath to get the parent and leaf values.

Putting it all together we get

CREATE OR REPLACE VIEW relationships_  v AS
SELECT r.objectid as OBJECTID,
       '10' as OBJECTTYPES_ID,
       jt.meta_rev as REV,
       JSON_OBJECT('firstResourceCollection'  VALUE funcResourcePath(jt.FIRSTID).parent,
                   'firstResourceId'          VALUE funcResourcePath(jt.FIRSTID).leaf,
                   'firstPropertyName'        VALUE jt.FIRSTPROPERTYNAME,
                   'secondResourceCollection' VALUE funcResourcePath(jt.SECONDID).parent,
                   'secondResourceId'         VALUE funcResourcePath(jt.SECONDID).leaf,
                   'secondPropertyName'       VALUE jt.SECONDPROPERTYNAME,
                   'properties'               VALUE jt.PROPS,
                   '_id'                      VALUE jt.META_ID,
                   '_rev'                     VALUE jt.META_REV
         FORMAT JSON) as FULLOBJECT,
      funcResourcePath(jt.FIRSTID).parent as FIRSTRESOURCECOLLECTION,
      funcResourcePath(jt.FIRSTID).leaf as FIRSTRESOURCEID,
      jt.FIRSTPROPERTYNAME as FIRSTPROPERTYNAME,
      funcResourcePath(jt.SECONDID).parent as SECONDRESOURCECOLLECTION,
      funcResourcePath(jt.SECONDID).leaf as SECONDRESOURCEID,
      jt.SECONDPROPERTYNAME as SECONDPROPERTYNAME
FROM relationships r,
       JSON_TABLE(fullobject, '$'
         COLUMNS (FIRSTID            VARCHAR2(100 CHAR) PATH '$.firstId',
                  FIRSTPROPERTYNAME  VARCHAR2(50 CHAR)  PATH '$.firstPropertyName',
                  SECONDID           VARCHAR2(100 CHAR) PATH '$.secondId',
                  SECONDPROPERTYNAME VARCHAR2(50 CHAR)  PATH '$.secondPropertyName',
                  PROPS              VARCHAR2(50 CHAR)  PATH '$.properties',
                  META_ID            VARCHAR2(50 CHAR)  PATH '$._id',
                  META_REV           VARCHAR2(50 CHAR)  PATH '$._rev'
         )) jt;

Next steps would be to convert into a MATERIALISED_VIEW and overlay the exisiting FRIM .1.4 RELATIONSHIPS table to provide a real time translation from the FRIM 5.5.1.3 instance to the FRIM 7.2.1

That is another topic to explore

Loading Google+ Comments ...