Cybersecurity
DevOps Cloud
IT Operations Cloud
In part 1 we reviewed what ModScript is. Let's start looking at some examples:
In Use Case 1, the ModScript will run in the Post Transition context of an item's Close transition. The item might be selected in a multi-relational field on a separate item, and if all items in that multi-relational field are closed, we'll transition the container item. This is similar to what can be done with the SBM Sub-Tasks feature, but we'll do it via scripting because there could be some extra logical detail that Sub-Tasks couldn't check for but scripting could (and it gives us a showcase for ModScript features). The full application can be found here: Container.zip. This script uses the algorithms "drop_while()" and "any_of()", to see more information on algorithms, see Part 5. This script also uses "from_json()", to see more about ChaiScript's JSON utility functions, see Part 4.
// set up some constants for use later in the script add_global_const( "USR_CONTAINER", "CONTAINER_TBL_NAME" ); add_global_const( "RELATED_ITEMS", "CONTAINER_FIELD" ); // Get the container application table id and add it as a global global CONTAINER_TBL = Ext.TableId(CONTAINER_TBL_NAME); // define a function that trims commas and returns the new string def TrimCommas( s ) { /* ChaiScript engine automatically returns whatever occurs on the last line of a function. We could add a "return" statement here if desired for clarity. This may be a little hard to follow, but we call drop_while on our string to remove the starting commas, then the return value is reversed, we do drop_while again to trim the back, then reverse again. These "fun" statements are anonymous functions known as lambdas */ reverse( drop_while( reverse( drop_while( s, fun(x){ return x == ','; } ) ), fun(x) { x == ','; })); } // Find the multi-relational field var relational = Ext.CreateAppRecord( Ext.TableId("TS_FIELDS"), FieldTypeConstants.MULTIPLE_RELATIONAL ); relational.ReadByColumnAndColumn("TABLEID", CONTAINER_TBL, "DBNAME", CONTAINER_FIELD ); // Create a list, as it is possible that our item is in more than one container item var containerList = Ext.CreateAppRecordList( CONTAINER_TBL ); /* Yes, ModScript has multi-line comments! Read the list of items that contain this item. Use SQL binding by passing a Vector of Pair objects, each with a data type and a value. Vectors can be created on the fly using [ ... ] syntax */ containerList.ReadWithWhere( "TS_ID in (select TS_SOURCERECORDID from TS_USAGES where TS_FIELDID=? and TS_RELATEDRECORDID=?)", [ Pair(DBTypeConstants.INTEGER, relational.GetId()), Pair(DBTypeConstants.INTEGER, Shell.Item().GetId()) ] ); // loop through the resulting list, using the "for each" syntax (just a ":") for( containerItem : containerList ) { // for each item, read the contents of the relational field, check the items, // transition if necessary // Get the field value from the containing item. GetFieldValue() returns a Variant, // so use to_string() to get it as a string. // In 11.4, we have GetFieldValueString(), GetFieldValueInt(), etc, for getting field // values as the desired type. var fieldVal = containerItem.GetFieldValue(CONTAINER_FIELD).to_string(); // remove the current item from the comma-separated list of items var regex = Regex(); regex.Compile( ",${Shell.Item().GetId()}," ); fieldVal = regex.ReplaceAll( fieldVal, "," ); // trim outside commas off of list fieldVal = TrimCommas( fieldVal ); // turn comma separated list into Vector of values. // ChaiScript can do this with "from_json" if we use array syntax [ ... ] // ChaiScript has in-string processing, use ${ ... } inside a string and the stuff // inside the braces will be processed by the engine and put inline in the string. var itemIDs = ("[${fieldVal}]").from_json(); // Loop through those other contained items to see if they are inactive too. // We could do another for-each loop here, but let's use an algorithm instead. if ( !any_of( itemIDs, fun( itemID ) { // return true if item is active var contained = Ext.CreateProjectBasedRecord( CONTAINER_TBL ); return contained.Read(itemID) && contained.GetFieldValue( "ACTIVEINACTIVE" ) == 0; } ) ){ // no items found that are active, we need to transition this container item containerItem.QuickTransition( "CONTAINER.CLOSE", true ); } }