Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support function object types in Ocl #132

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open

Conversation

zentron
Copy link
Contributor

@zentron zentron commented Jan 2, 2023

Similar to HCL support for Functions and Function Calls

Usage

OCL Syntax

In OCL itself it is represented in the same way that a function would be called in most programing languages.

somebinarydata = base64decode("SGVsbG8=")

All functions are uniquely named and support none or many arguments which can themselves be of any parseable ocl expression type.

multiplier = sum(4, 5)  // Multiple Numbers
nowDate = date()        // Zero arguments

When building a custom function, be mindful that unlike how HCL may be used in places like Terraform, functions in OCL should where possible be reversable. That is, once an object is deserialized with a function, it should ideally be serialized back into a format with the same value. This may require only supporting being mapped to certain object types, or by relying on additional context from the serialization process. From a technical standpoint you may not want or need to support this, but it should be kept in mind.

Defining a Custom Function

By default, only the Base64DecodeFunctionCall is included out-of-the box however .

  1. Implement the IFunctionCall interface.
    This interface defines two methods:

    • object? ToValue(IEnumerable<object?> arguments) - Called during deserialization when converting from the OCL representation to a single property value. The function may contain none or many arguments.
    • IEnumerable<object?> ToOclFunctionCall(object propertyValue) - Called during serialization and allows for a single object value to be represented by the function call as being defined with non or many arguments.
  2. Pass an instance of this custom function class into the OclSerializer via the OclSerializerOptions (e.g).

As an example see the Base64DecodeFunctionCall class

public class Base64DecodeFunctionCall : IFunctionCall
    {
        public string Name => "base64decode";

        public object? ToValue(IEnumerable<object?> arguments)
        {
            var val = arguments.FirstOrDefault();
            if (val == null)
            {
                return null;
            }

            if (val is not string valString)
            {
                throw new OclException($"The {Name} OCL function expects a single double argument. Unable to parse value");
            }
            return Convert.FromBase64String(valString);
        }

        public IEnumerable<object?> ToOclFunctionCall(object propertyValue)
        {
            if (propertyValue is Byte[] bytes)
            {
                var fahrenheit = Convert.ToBase64String(bytes);
                return new object?[] { fahrenheit };
            }

            throw new InvalidOperationException($"The {Name} OCL function currently only supports byte arrays");
        }
    }

OclFunctionAttribute

To allow for two-way conversion of properties, a new OclFunction attribute exists that allows for annotating properties that, when serialized, should take place through a function.

An example from the included tests

class TestObject
        {
            [OclFunction("base64decode")]
            public byte[] WithFunctionAttribute { get; set; } = Array.Empty<byte>();
            
            public byte[] WithoutFunctionAttribute { get; set; } = Array.Empty<byte>();
        }

results in a serialized OCL document with two properties

with_function_attribute = base64decode("SGVsbG8=")
without_function_attribute = [72, 101, 108, 108, 111]

@zentron zentron marked this pull request as ready for review September 20, 2023 05:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant