diff --git a/.gitignore b/.gitignore index 722d5e7..1cabfcc 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ +.DS_Store .vscode +.antlr diff --git a/README.md b/README.md index 22c1f0a..085ddae 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Approved proposals have both specification and testing rules approved by Transpo | RCP | Name | Version | Date | | :-- | :-- | :-- | :-- | | [**RCP-010**](web-api-add-edit.md) | **Web API Add/Edit** | **1.0.0** | **Dec 2023** | -| [**RCP-019**](https://github.com/RESOStandards/transport/blob/4ff4cbc67cf39fe321956f7437ced718de766341/web-api-validation-expression.md) | **Web API Validation Expressions** | **1.0.0** | **Dec 2023** | +| [**RCP-019**](./proposals/rcp-019-web-api-validation-expression.md) | **Web API Validation Expressions** | **1.0.0** | **Dec 2023** | | [**RCP-027**](https://github.com/RESOStandards/transport/blob/45-migrate-rcp-027-from-confluence/entity-events.md) | **EntityEvent Resource and Replication** | **1.0.0** | **Dec 2023** | | [**RCP-028**](https://github.com/RESOStandards/transport/blob/46-migrate-rcp-028-from-confluence/web-hooks-push.md) | **Push Replication with EntityEvent and Web Hooks** | **1.0.0** | **Dec 2023** | | [**RCP-039**](https://github.com/RESOStandards/transport/blob/22-web-api-core-210-specification/web-api-core.md) | **Web API Core** | **2.1.0** | **Sept 2022** | diff --git a/proposals/rcp-019-web-api-validation-expression.md b/proposals/rcp-019-web-api-validation-expression.md new file mode 100644 index 0000000..bb10ac2 --- /dev/null +++ b/proposals/rcp-019-web-api-validation-expression.md @@ -0,0 +1,368 @@ +# RESO Validation Expressions + +| **RCP** | 019 | +| :--- | :--- | +| **Version** | **1.0.0** | +| **Authors** | [Joshua Darnell](mailto:josh@kurotek.com)
[Paul Stusiak](mailto:pstusiak@falcontechnologies.com) | +| **Specification** | [**LINK TO RCP**](./web-api-validation-expression.md) | +| **Status** | **APPROVED** | +| **Status Date** | December 2023 | +| **Dependencies** | [Data Dictionary 1.7+](./data-dictionary.md)
[Validation Expression Grammar](#) | +| **Related Links** | [DD Wiki 1.7](https://ddwiki.reso.org/display/DDW17/RESO+Data+Dictionary+1.7)
[Data Dictionary Spreadsheet](https://docs.google.com/spreadsheets/d/1_59Iqr7AQ51rEFa7p0ND-YhJjEru8gY-D_HM1yy5c6w/edit?usp=sharing) | + +

+ +# RESO End User License Agreement (EULA) + +This End User License Agreement (the "EULA") is entered into by and between the Real Estate Standards Organization ("RESO") and the person or entity ("End User") that is downloading or otherwise obtaining the product associated with this EULA ("RESO Product"). This EULA governs End Users use of the RESO Product and End User agrees to the terms of this EULA by downloading or otherwise obtaining or using the RESO Product. + +
+ +# Table of Contents +- [Introduction](#introduction) +- [Section 1: Purpose](#section-1-purpose) +- [Section 2: Specification](#section-2-specification) +- [Section 3: Certification](#section-3-certification) +- [Section 4: Contributors](#section-4-contributors) +- [Section 5: References](#section-5-references) +- [Section 6: Appendices](#section-6-appendices) +- [Section 7: License](#section-7-license) + +
+ +# Introduction +Business rules are an important, but challenging, topic and come in many forms. There are validation rules (like requiring list price being greater than 0) and process rules (such as requiring a contract date when a listing is sold). There are also display rules, such as additional elements being shown and/or required based on the current state of a record. + +These rules come into play whenever a record is created, updated, or deleted. Display rules can also apply to readonly access to that data in an API or UI. + +The goal of this specification is to provide a machine-executable business rules grammar, as well as a transport mechanism to convey rules. Another goal is that the rules themselves be human friendly. + +Executable business rules also provide a way to document a system's rules in a way that's both vendor and technology agnostic. + +
+ +# Section 1: Purpose +The ability to express and exchange machine-executable business rules has several uses. For example, providing immediate feedback to users when adding a record to a system from their own frontend of choice, without calling back to a vendor system for validation. They can also be used in back-office systems so they can push records back to an MLS or other system for publication (disconnected edit). + +The RESO Web API is built on OData, which does not provide machine-executable rules at this time. However, this is something RETS previously offered. + +After much discussion and several onsite meetings during 2016-2018, the community felt the best direction was to carry the work done in RETS forward to the RESO Web API. It had a few issues that needed to be addressed, as well as a need for a transport mechanism, but the grammar presented in this specification should mostly have backwards compatibility with what had come before for those who might have implemented it. + +While there is still more work to do, such as the addition of a scope resolution operator to support rules for expanded data elements and new functions and special operations, it will be addressed in a future version. + +
+ +# Section 2: Specification +This specification consists of the following: +* [Rules grammar](#section-212-validation-expression-bnf) expressed in [BNF](https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form) +* [Rules Resource](https://ddwiki.reso.org/display/DDW17/Rules+Resource) to provide transport of business rules + + +## Section 2.1: Validation Expression Language + +The [RESO Validation Expression Grammar](./artifacts/grammars/RCP-019/rcp019.g4) is used in conjunction with a data structure of `FieldName`, `RuleAction`, `RuleExpression` tuples to provide an ordered list of instructions that can be used to convey business rules in a system independent way. + +These rules are intended to be written from the perspective of the business object being upserted, such as a listing record in the Property Resource, and would be run as-needed before the client sends the record back to the system using the [RESO Add/Edit](./web-api-add-edit.md) specification. + +For a client running the rules locally, making a change to the StandardStatus field would trigger rules relevant for that field (along with any related rules). + +Expressions a given upsert process MUST be evaluated in the order that they appear in the [RuleOrder](https://ddwiki.reso.org/display/DDW17/RuleOrder+Field) field. + +While all rules may be executed each time data changes, clients SHOULD try and optimize execution so that only rules related to a given change are fired rather than all of them. There are a number of techniques that can be used to accomplish this, such as [instruction scheduling](https://en.wikipedia.org/wiki/Instruction_scheduling) or the [Rete algorithm](https://en.wikipedia.org/wiki/Rete_algorithm). + +Rule optimization is beyond the scope of this document, but it's helpful that there are existing techniques to address it. + +### Section 2.1.1: Actions + +The following actions are defined by this specification: + +| Keyword | Type | Purpose | +| ------- | ------- | ------- | +| **ACCEPT** | `BOOLEAN` | If the expression is true, the field value is considered accepted without further testing. Immediately following SET expressions MUST be executed. If the expression is false, following validation expressions MUST be executed. If the expression is ERROR (evaluation failed) in client, the client SHOULD act as if the field was accepted, allowing the server to make the final decision. | +| **REJECT** | `BOOLEAN` | If the expression is true, the field value is considered rejected without further testing. Subsequent SET expressions MUST NOT be evaluated. If the expression is false, following validation expressions MUST be executed. If the expression is ERROR, evaluation failed in client, the client SHOULD act as if the field was accepted, allowing the server to make the final decision. | +| **WARNING** | `BOOLEAN` | If the expression is true, the client should show a warning message to the user, and if the warning is okayed by the user, include a Warning-Response in the UPDATE request. If the user does not okay the warning, the field is considered rejected and following SET validation expressions MUST NOT be evaluated.

If the expression is false, the following validation expressions MUST be evaluated. | +| **SET** | `TYPEOF(Exp)` | The following expression is evaluated and the result stored in the designated field. | +| **SET_DEFAULT** | `TYPEOF(Exp)` | This expression MUST be executed ONLY when a NEW record is created. Supersedes the default value as indicated in the Update Metadata. | +| **SET_REQUIRED** | `BOOLEAN` | Expressions of this type are designed to evaluate an expression and set the field that the rule is applied on to Required if the expression returns true and to Non Required if the expression returns false. | +| **SET_READ_ONLY** | `BOOLEAN` | Expressions of this type are designed to evaluate an expression and set the field that the rule is being applied on to Read Only if the expression returns true and to updatable if the expression returns false.

The client application is expected to lock the value of the field the rule is being executed on to the value at the time the SET_REQUIRED expression is evaluated. | +| **RESTRICT_PICKLIST** | `LIST(CHAR)` | Expressions of this type are designed to return one or more lookup values that are to be removed from the lookup list that is defined for the field the rule is being executed on. This is always the entire set of values to remove from the lookup.

In other words, if this returns a blank list or `.EMPTY.`, the entire set of lookup values is to be displayed.

The value of this expression MUST be a `LIST`, rather than `Exp`.

All members of the list MUST be of the same data type as that of the field the rule is being executed on. | +| **SET_PICKLIST** | `LIST(CHAR)` | Expressions of this type are designed to return one or more lookup values that are to be used in the lookup list defined for the field the rule is being executed on.

The value of this expression MUST be a `LIST`, rather than `Exp`.

Every member of the list MUST exist in the lookup list as defined in the metadata for the field the rule is being executed on. | +| **SET_DISPLAY** | `BOOLEAN` | Expressions of this type are designed to allow a client to make fields visible or invisible based on the evaluation of an expression. The result of this expression has no effect on whether a field is READ ONLY or not. | + +### Section 2.1.2: Validation Expressions + +There are two files that define the Validation Expressions grammar: +* [ANTLR 4 grammar](./artifacts/grammars/RCP-019/rcp019.g4) - Contains [non-terminal symbols](https://en.wikipedia.org/wiki/Terminal_and_nonterminal_symbols#Nonterminal_symbols) +* [ANTLR 4 lexer](./artifacts/grammars//RCP-019/rcp019Lexer.g4) - Contains [terminal symbols](https://en.wikipedia.org/wiki/Terminal_and_nonterminal_symbols#Terminal_symbols) + +#### Basic Examples + +##### Arithmetic Operators +`3 + 5` + +`1 * 3 + 2 - 5` + +##### FIELD_NAME +To get current value of any field, use the Data Dictionary name: `ListPrice` + +##### Bracketed FIELD_NAMEs +Supported for backwards compatibility with RETS: +`[ListPrice]` + +##### Simple Comparisons +`ListPrice > 0` + +##### Access the Last Value of a Field +`LAST Status != 'Sold'` + +##### Field Change Detection +Returns true if ListPrice has changed. + +`ListPrice != LAST ListPrice` + +##### Function Calls +`foo()` +`foo('bar', 'baz', 42)` + +_Functions MUST NOT use any FIELD_NAMEs or reserved words._ + +##### Lists of Expressions +`(ListPrice, Status, 3+5, LAST Status, (1, 2, 3))` + +##### Complex Expressions with Grouping +`ListPrice > 5.01 .AND. (1, 2, 3) .CONTAINS. 3 .OR. (Status .IN. ('Active', 'Pending') .AND. .MEMBER_MLS_SECURITY_CLASS. != 'Admin')` + +##### Which parses differently than +`ListPrice > 5.01 .AND. (1, 2, 3) .CONTAINS. 3 .OR. Status .IN. ('Active', 'Pending') .AND. .MEMBER_MLS_SECURITY_CLASS. != 'Admin'` + +##### Collection Support +This proposal adds support for `LIST()` and `SET()`. + +These functions take 0 or more items. + +| Expression | Result | Comments | +| :--- | :--- | :--- | +|`LIST(1, 2, 2, 3)`|`LIST(1, 2, 2, 3`| Duplicate items are _preserved_| +|`SET(1, 2, 2, 3)`|`SET(1, 2, 3)`| Duplicate items are _removed_| + +
+ +##### List and Set Difference, Intersection, and Union +This proposal also adds support for the following collection operators: +* `DIFFERENCE()` +* `INTERSECTION()` +* `UNION()` + +Which are intended to produce types in the following manner: + * Operations on _homogeneous_ collections of `LIST()` or `SET()` should + return `LIST()` or `SET()`, respectively. + * Example: `UNION(LIST('a', 'b', 3+5), LIST(6))` should return `LIST('a', 'b', 6, 8)` + * Operations on _heterogenous_ collections of `LIST()` or `SET()` should return `LIST()` + * Example: `DIFFERENCE(LIST(1, 2, 3), SET(3))` should return `LIST(1, 2)` + +These special functions require _at least two_ arguments of type `LIST()` or `SET()`: + + | Expression | Result | Comments | + | :--- | :--- | :--- | + | `DIFFERENCE(LIST(1, 2, 3), LIST(1, 2))` | `LIST(3)` |Collection operators require two or more `LIST()` or `SET()` arguments.| + | `UNION(LIST(1, 2), SET(3))` | `LIST(1, 2, 3)` | Arguments of type `LIST()` are converted to `SET()` | + | `INTERSECTION(SET(DIFFERENCE(LIST(1, 2, 3), SET(1))), SET(2))` | `SET(2)` |Since the return type of `collection` operators is `SET()` or `LIST()`, they can be composed + +## Section 2.2: Rules Resource +The Validation Expression grammar itself is not enough to compute rules. Additional information is needed. + +The [Rules Resource](https://ddwiki.reso.org/display/DDW17/Rules+Resource) has been created in Data Dictionary 1.7+ to transport business rules. + +At a minimum, these consist of the following: +* Field: A standard or local field to effect with the outcome of _expression_ +* Action: One of the Actions in [Section 2.1.1](#section-211-actions) +* Expression: The Validation Expression using the grammar [defined in Section 2.1.2](#section-212-validation-expressions) + +### Example: Update PurchaseContractDate when Listing is Closed + +| Field | Action | Expression | +| --------------------------- | -------- | ---------- | +| **PurchaseContractDate** | `SET` | `IIF(LAST StandardStatus != 'Closed' .AND. StandardStatus = 'Closed', #2023-12-04#, NULL)` + +It's also important that each rule contains human-friendly messages describing the outcome, when appropriate. + +## Section 2.3: Rule Ordering +Rule ordering is important. Dependent rules MUST be executed in the order appropriate for their dependencies. + +Consider the basic operations: + +``` +a = 1 +b = 1 + a +c = a + b +``` + +If `a = 1` isn't executed first, then the second instruction will throw an error and the output won't be available to the assignment of `c`. + +However, if we had another expression `d = 0`, it could be executed in any order since there are no dependencies on any of the other items. + +The Rule Resource includes a [`RuleOrder`](https://ddwiki.reso.org/display/DDW17/RuleOrder+Field) property so ordering may be preserved. + +## Section 2.4: Rule Versioning +Sometimes it might be necessary to communicate that a given rule has changed. + +The Rules Resource providers the [Rule Version](https://ddwiki.reso.org/display/DDW17/RuleVersion+Field) for these scenarios. + +## Section 2.5: Filtering by FieldName and RuleAction +Consider the case where a client is interested in rules that might reject changes to ListPrice. + +These can be retrieved using the following request to the Rules Resource: + +**REQUEST** +``` +GET /Rules?$select=RuleKey,FieldName,RuleAction,RuleExpression,RuleWarningText,RuleVersion&$filter=FieldName eq 'ListPrice' and RuleAction eq 'REJECT' +``` + +**RESPONSE** +```json +{ + "@odata.context": "/Rules?$select=RuleKey,FieldName,RuleAction,RuleExpression,RuleWarningText,RuleVersion&$filter=FieldName eq 'ListPrice' and RuleAction eq 'REJECT'", + "value": [{ + "RuleKey": "abc123", + "FieldName": "ListPrice", + "RuleAction:": "REJECT", + "RuleExpression": "ListPrice GT LAST ListPrice * 2", + "RuleWarningText": "ListPrice was greater than two times the original list price. Are you sure?", + "RuleVersion": "1.234" + }] +} +``` + +
+ +# Section 3: Certification +Testing rules consists of the following steps: +* Retrieve rules from the [Rules Resource](https://ddwiki.reso.org/display/DDW17/Rules+Resource) or having them provided in [RESO Common Format](./reso-common-format.md), and validating they're in the correct format +* Parse the [Validation Expression grammar](./artifacts/grammars/RCP-019/rcp019.g4) to make sure it's correct + * Will generate a parser from the grammar and host it as a service + * Add more human-friendly error messages +* Make local changes to a record and validate both success and failure scenarios + * Those being tested will provide several tests for both scenarios, along with the expected output + * Testing tools will run the rule set and ensure the output matches +* Test that client can send record to test server with validation rules failing with initial values, then succeeding with known-good values, and the record being upserted correctly in that system (Optional) + +Certification tools will be developed so a user can perform all these steps in an interactive manner through both a CLI or UI. + +

+ +# Section 4: Contributors +This document was rewritten from the original by [Joshua Darnell](mailto:josh@kurotek.com), and originally written by Joshua Darnell and [Paul Stusiak](mailto:pstusiak@falcontechnologies.com). + +Thanks to the following contributors for their help with this project: + +Parts of this proposal are based on the RETS Validation Expression language as expressed in RETS 1.9 and RCP 61. Thanks to Libor Viktorin, Mark Sleeman, Sergio Del Rio, and Paul Stusiak for that work. Thanks to Rob Larson for his collaboration on the Rules Resource proposal. + +

+ +# Section 5: References + +Please see the following references for more information regarding topics covered in this document: +* [Rules Resource [DD WIki]](https://ddwiki.reso.org/display/DDW17/Rules+Resource) +* [Original RCP-019 Proposal [Confluence - Login Required]](https://reso.atlassian.net/wiki/spaces/RESOWebAPIRCP/pages/2250178749/RCP+-+WEBAPI-019+Validation+Expression+in+the+WebAPI) +* [PDF of original RCP-019 Proposal](https://github.com/RESOStandards/reso-transport-specifications/files/8384860/RESOWebAPIRCP-RCP-WEBAPI-019ValidationExpressionintheWebAPI-300322-2353.pdf) +* [RESO Validation Expression Grammar](./artifacts/grammars/RCP-019/rcp019.g4) +* [RESO Common Format](./reso-common-format.md) +* [Formal Grammar [Wikipedia]](https://en.wikipedia.org/wiki/Formal_grammar) +* [Backus-Naur form (BNF) [Wikipedia]](https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form) +* [ANTLR 4 Documentation](https://www.antlr.org/) + + +

+ +# Section 6: Appendices + +## 6.1: List of Functions + +| Function | Parameter Types | Type | Comments | +| -------- | --------------- | ---- | -------- | +| `BOOL` | { `BOOLEAN`, `CHAR` } | `BOOLEAN` | | +| `CHAR` | { `Exp`, `TYPEOF(Exp) NE FLOAT` } | `CHAR` | | +| `CHARF` | `FLOAT`, `INT` | `CHAR` | The `CHARF` function converts a Float number, and in the second parameter specifies how many decimal digits MUST appear after the point. | +| `TIME` | { `TIME`, `CHAR`, `DATE` } | `TIME` | | +| `DATE` | { `TIME`, `CHAR` } | `DATE` | | +| `INT` | { `INT`, `FLOAT`, `BOOL`, `CHAR` } | `INT` | | +| `FLOAT` | { `INT`, `FLOAT`, `BOOL`, `CHAR` } | `FLOAT` | | +| `SUBSTR` | `CHAR`, `INT`, `INT` | `CHAR` | The `SUBSTR` function returns a substring of its first parameter. Second parameter is a starting position of the substring, third parameter is the ending position of the substring. Positions are 1-based. | +| `STRLEN` | `CHAR` | `INT` | The `STRLEN` function returns the length if its parameter. | +| `LOWER` | `CHAR` | `CHAR` | The `LOWER` function returns its parameter lower-cased. | +| `UPPER` | `CHAR` | `CHAR` | The `UPPER` function returns its parameter upper-cased. | +| `IIF` | `BOOLEAN`, `Exp`, `Exp` | `TYPEOF (Exp)` | The `IIF` function returns the value of its second parameter if the first parameter evaluates to true, or the value of its third parameter otherwise. Types of second and third parameter must be same, and it is the type of the result. These parameters are also known as `CondExp`, `TrueExp`, and `FalseExp`, respectively. | +| `YEAR` | `TIME` | `INT` | | +| `MONTH` | `TIME` | `INT` | | +| `DAY` | `TIME` | `INT` | | +| `WEEKDAY` | `TIME` | `INT` | | +| `TYPEOF` | `Exp` | `CHAR` | The input parameter, `Exp`, can be any valid expression in the grammar. This function will return a `CHAR` representation of the given expression's type, one of: { `BOOLEAN`, `CHAR`, `FLOAT`, `INT`, `TIME` } | +| `MATCH` | `CHAR`, `Exp` | `BOOLEAN` | Takes a Regular Expression regex as a `CHAR` and an expression `Exp`, and returns True if expression matches regex and False otherwise. | + +
+ +**Notes** +1. The `BOOL`, `CHAR`, `TIME`, `DATE`, `INT` and `FLOAT` functions are used just to change a type of expression. Note that any of these functions may fail (return an ERROR value) if the parameter can not be converted to the appropriate type. + +2. In conversion from `BOOLEAN` to `INT` or `FLOAT`, `.TRUE.` is converted to "1" and `.FALSE.` is converted to "0". Casting `FLOAT` to `INT` discards the fractional part. + +3. When converting to `CHAR`, `BOOL` values are represented as "0" and "1", `TIME` and `DATE` values are represented using ISO 8601 format, `INT` values are represented with no leading zeros. + +4. When converting from `CHAR` to `BOOL`, values "0", "1", "YES", "NO", "TRUE" and "FALSE" (no matter what the case) MUST be understood. + +5. When converting from `CHAR` to `TIME`, any ISO 8601 compliant format must be understood. Leading and trailing `#` MUST be removed before conversion. + +6. When converting from `CHAR` to `INT` or `FLOAT`, usual formats MUST be understood. Scientific format (with exponent) MUST NOT be understood. `FLOAT` numbers with empty integral part ( .5, -.4) MUST be understood as long as there is at least one digit after the decimal point. + +7. The `YEAR`, `MONTH`, `DAY` and `WEEKDAY` parse the date part of `TIME` value. They return values ranging from 1 to the appropriate maximum. `WEEKDAY` returns 1 for Sunday, 2 for Monday etc. + +8. Other functions may be defined later (`HOUR` and `MINUTE` are first candidates). If a server uses a function the client does not recognize, the client MUST evaluate it as ERROR. + +9. A Validation Expression may have Operations applied to the parameters. The Operators may be applied on certain types that determine the result type. The input types and resulting output type is defined in the Validation Expression List of Operators Table (below). + +
+ +## 6.2: List of Operators + +| Operator | Left Operand | Right Operand | Result | Meaning | +| -------- | ------------ | ------------- | ------ | ------- | +| `.MOD.` | `INT` | `INT` | `INT` | Arithmetic MODULO operation | +| `/`, `*` | `INT` | `INT` | `INT` | Integer division and multiplication | +| `/`, `*` | `INT` | `FLOAT` | `FLOAT` | Division and multiplication | +| `/`, `*` | `FLOAT` | `INT` | `FLOAT` | Division and multiplication | +| `/`, `*` | `FLOAT` | `FLOAT` | `FLOAT` | Division and multiplication | +| `+`, `-` | `FLOAT` | `FLOAT` | `FLOAT` | Addition and subtraction | +| `+`, `-` | `FLOAT` | `FLOAT` | `FLOAT` | Addition and subtraction | +| `+`, `-` | `FLOAT` | `FLOAT` | `FLOAT` | Addition and subtraction | +| `+`, `-` | `FLOAT` | `FLOAT` | `FLOAT` | Addition and subtraction | +| `+` | `FLOAT` | `TIME` | `TIME` | Time shift | +| `+` | `TIME` | `FLOAT` | `TIME` | Time shift | +| `-` | `TIME` | `FLOAT` | `TIME` | Time shift | +| `-` | `TIME` | `TIME` | `FLOAT` | Time shift | +| `\|\|` | `CHAR` | `CHAR` | `CHAR` | String concatenation | +| `.CONTAINS.` | `CHAR` | `CHAR` | `BOOLEAN` | String containment. The operation is TRUE if the left operand contains the right operand as a substring anywhere within it. | +| `.IN.` | Any | List of operands, all of the same type as the left operand | `BOOLEAN` | List inclusion. The operation is TRUE if the left operand is equal to any member of the list. | +| `.AND.` | `BOOLEAN` | `BOOLEAN` | `BOOLEAN` | A Boolean operator that takes two Boolean operands, and whose value is TRUE if and only if both of its operands are TRUE. | +| `.OR.` | `BOOLEAN` | `BOOLEAN` | `BOOLEAN` | A Boolean operator that takes two Boolean operands, and whose value is TRUE if either of its operands is TRUE. | +| `.NOT.` | `BOOLEAN` | `BOOLEAN` | `BOOLEAN` | A Boolean operator that takes a single Boolean operand and returns its inverse. | +| `=`, `!=` | Any | Same as left | `BOOLEAN` | Equality | +| `<`, `>`, `<=` , `>=` | `INT`, `FLOAT` | `INT`, `FLOAT` | `BOOLEAN` | Numeric comparison | +| `<`, `>`, `<=`, `>=` | `TIME` | `TIME` | `BOOLEAN` | Date and time comparison | +| `<`, `>`, `<=`, `>=` | `BOOLEAN` | `BOOLEAN` | `BOOLEAN` | Boolean comparison (TRUE > FALSE) | + +
+ +**Notes** +1. Arithmetic operations between dates use number of days as the `FLOAT` parameter (or result); e.g. 0.25 represents a time span of 6 hours. + +2. Any operation with an ERROR argument MUST evaluate to ERROR. An EMPTY value may be compared (=,!=) against any value. + +3. Appropriate casting functions (`BOOL`, `CHAR`, `TIME`, `INT`, `FLOAT`) MUST be applied to the parameters. If a function or an operator is applied to a data type different than shown in the above tables, the expression MUST evaluate to ERROR. + + +

+ +# Section 7: License +This document is covered by the [RESO EULA](https://www.reso.org/eula/). + +Please [contact RESO](mailto:info@reso.org) if you have any questions. \ No newline at end of file diff --git a/web-api-validation-expression.md b/web-api-validation-expression.md deleted file mode 100644 index c81c969..0000000 --- a/web-api-validation-expression.md +++ /dev/null @@ -1,13 +0,0 @@ -# RESO Validation Expressions - -| **RCP** | 19 | -| :--- | :--- | -| **Version** | 1.0.0 | -| **Authors** | [Joshua Darnell](https://github.com/darnjo) ([RESO](mailto:josh@reso.org))
Paul Stusiak ([Falcon Technologies](mailto:pstusiak@falcontechnologies.com)) | -| **Specification** | [**LINK TO RCP**](./web-api-validation-expression.md) | -| **Status** | **APPROVED** | -| **Date Approved** | December 2023 | -| **Dependencies** | [Validation Expression grammar](https://github.com/darnjo/rcp019)
[Data Dictionary 1.7+](./data-dictionary.md)
[Web API 2.0.0+](./web-api-core.md)
| -| **Related Links** | [DD Wiki 1.7](https://ddwiki.reso.org/display/DDW17/RESO+Data+Dictionary+1.7)
[Data Dictionary Spreadsheet](https://docs.google.com/spreadsheets/d/1_59Iqr7AQ51rEFa7p0ND-YhJjEru8gY-D_HM1yy5c6w/edit?usp=sharing)
| - -[**See Revised Proposal**](https://github.com/RESOStandards/transport/pull/111)