|
| 1 | +# Changelog |
| 2 | + |
| 3 | +All notable changes to this project will be documented in this file. |
| 4 | + |
| 5 | +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), |
| 6 | +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). |
| 7 | + |
| 8 | +## [1.0.0] - 2025-08-XX |
| 9 | + |
| 10 | +### Added |
| 11 | + |
| 12 | +#### Core Language Features |
| 13 | +- **Comparison Operators**: Full support for `>`, `<`, `>=`, `<=`, `=`, `!=` with proper type handling |
| 14 | +- **Logical Operators**: Case-insensitive `AND`/`and`, `OR`/`or`, `NOT`/`not` with correct precedence |
| 15 | +- **Data Types**: |
| 16 | + - Numbers (integers): `42`, `-17` |
| 17 | + - Strings (double-quoted): `"hello"`, `"world"` |
| 18 | + - Booleans: `true`, `false` |
| 19 | + - Date literals: `#2024-01-15#` (ISO 8601 format) |
| 20 | + - DateTime literals: `#2024-01-15T10:30:00Z#` (ISO 8601 with timezone) |
| 21 | + - List literals: `[1, 2, 3]`, `["admin", "manager"]` |
| 22 | + - Identifiers: `score`, `user_name`, `is_active` |
| 23 | + |
| 24 | +#### Advanced Operations |
| 25 | +- **Membership Operators**: |
| 26 | + - `in` for element-in-collection testing (`role in ["admin", "manager"]`) |
| 27 | + - `contains` for collection-contains-element testing (`[1, 2, 3] contains 2`) |
| 28 | +- **Parenthesized Expressions**: Full support with proper precedence handling |
| 29 | +- **Plain Boolean Expressions**: Support for bare identifiers (`active`, `expired`) without explicit `= true` |
| 30 | + |
| 31 | +#### Function System |
| 32 | +- **Built-in System Functions**: |
| 33 | + - **String functions**: `len(string)`, `upper(string)`, `lower(string)`, `trim(string)` |
| 34 | + - **Numeric functions**: `abs(number)`, `max(a, b)`, `min(a, b)` |
| 35 | + - **Date functions**: `year(date)`, `month(date)`, `day(date)` |
| 36 | +- **Custom Function Registration**: Register anonymous functions with `Predicator.register_function/3` |
| 37 | +- **Function Registry**: ETS-based registry with automatic arity validation and error handling |
| 38 | +- **Context-Aware Functions**: Functions receive evaluation context for dynamic behavior |
| 39 | + |
| 40 | +#### Architecture & Performance |
| 41 | +- **Multi-Stage Compilation Pipeline**: Expression → Lexer → Parser → Compiler → Instructions → Evaluator |
| 42 | +- **Compile-Once, Evaluate-Many**: Pre-compile expressions for repeated evaluation |
| 43 | +- **Stack-Based Evaluator**: Efficient instruction execution with minimal overhead |
| 44 | +- **Comprehensive Error Handling**: Detailed error messages with line/column positioning |
| 45 | + |
| 46 | +#### Developer Experience |
| 47 | +- **String Decompilation**: Convert AST back to readable expressions with formatting options |
| 48 | +- **Multiple Evaluation APIs**: |
| 49 | + - `evaluate/2` - Returns `{:ok, result}` or `{:error, message}` |
| 50 | + - `evaluate!/2` - Returns result directly or raises exception |
| 51 | + - `compile/1` - Pre-compile expressions to instructions |
| 52 | + - `parse/1` - Parse expressions to AST for inspection |
| 53 | +- **Formatting Options**: Configurable spacing (`:normal`, `:compact`, `:verbose`) and parentheses (`:minimal`, `:explicit`, `:none`) |
| 54 | + |
| 55 | +#### Code Organization |
| 56 | +- **Modular Architecture**: Clean separation of concerns across lexer, parser, compiler, evaluator |
| 57 | +- **Organized File Structure**: |
| 58 | + - `lib/predicator/functions/` - Function system components |
| 59 | + - `lib/predicator/visitors/` - AST transformation modules |
| 60 | +- **Comprehensive Testing**: 616 tests with 66 doctests, achieving >90% code coverage |
| 61 | + |
| 62 | +### Technical Details |
| 63 | + |
| 64 | +#### Grammar |
| 65 | +The language supports a complete expression grammar with proper operator precedence: |
| 66 | +```ebnf |
| 67 | +expression → logical_or |
| 68 | +logical_or → logical_and ( ("OR" | "or") logical_and )* |
| 69 | +logical_and → logical_not ( ("AND" | "and") logical_not )* |
| 70 | +logical_not → ("NOT" | "not") logical_not | comparison |
| 71 | +comparison → primary ( ( ">" | "<" | ">=" | "<=" | "=" | "!=" | "in" | "contains" ) primary )? |
| 72 | +primary → NUMBER | STRING | BOOLEAN | DATE | DATETIME | IDENTIFIER | list | function_call | "(" expression ")" |
| 73 | +function_call → IDENTIFIER "(" ( expression ( "," expression )* )? ")" |
| 74 | +list → "[" ( expression ( "," expression )* )? "]" |
| 75 | +``` |
| 76 | + |
| 77 | +#### Security |
| 78 | +- **No Dynamic Code Execution**: All expressions compiled to safe instruction sequences |
| 79 | +- **Input Validation**: Comprehensive validation at lexer and parser levels |
| 80 | +- **Type Safety**: Strong typing throughout compilation and evaluation pipeline |
| 81 | +- **Sandboxed Evaluation**: No access to system functions or arbitrary code execution |
| 82 | + |
| 83 | +#### Performance |
| 84 | +- **Efficient Tokenization**: Single-pass lexer with position tracking |
| 85 | +- **Recursive Descent Parser**: Clean, maintainable parsing with excellent error recovery |
| 86 | +- **Optimized Instruction Set**: Minimal instruction overhead for fast evaluation |
| 87 | +- **Memory Efficient**: Low allocation during expression evaluation |
| 88 | + |
| 89 | +### Dependencies |
| 90 | +- **Runtime**: Zero external dependencies for core functionality |
| 91 | +- **Development**: Credo, Dialyzer, ExCoveralls for code quality and testing |
| 92 | +- **Minimum Elixir**: ~> 1.11 |
| 93 | + |
| 94 | +### Breaking Changes |
| 95 | + |
| 96 | +**⚠️ COMPLETE LIBRARY REWRITE ⚠️** |
| 97 | + |
| 98 | +Version 1.0.0 is a **complete rewrite** of the Predicator library with entirely new: |
| 99 | +- API design and function signatures |
| 100 | +- Expression syntax and grammar |
| 101 | +- Internal architecture and data structures |
| 102 | +- Feature set and capabilities |
| 103 | + |
| 104 | +### Migration Guide |
| 105 | + |
| 106 | +**Migration from versions < 1.0.0 has NOT been tested and is NOT guaranteed to work.** |
| 107 | + |
| 108 | +If you are upgrading from a pre-1.0.0 version: |
| 109 | +1. **Treat this as a new library adoption**, not an upgrade |
| 110 | +2. **Review all documentation** - APIs have completely changed |
| 111 | +3. **Test thoroughly** in development environments |
| 112 | +4. **Expect to rewrite** all integration code |
| 113 | +5. **Plan for significant refactoring** of existing expressions |
| 114 | + |
| 115 | +Future 1.x.x versions will maintain backwards compatibility and include proper migration guides. |
| 116 | + |
| 117 | +--- |
| 118 | + |
| 119 | +## Legacy Versions (Pre-1.0.0) |
| 120 | + |
| 121 | +The following versions are part of the original Predicator implementation, which has been completely rewritten for 1.0.0: |
| 122 | + |
| 123 | +## [0.9.2] |
| 124 | + |
| 125 | +### Documentation |
| 126 | +- Adds additional information to README |
| 127 | +- Adds documentation to functions in Predicator |
| 128 | + |
| 129 | +### Enhancements |
| 130 | +- Adds `compile!`, `evaluate`, `evaluate!`, `evaluate_instructions`, `evaluate_instructions!` functions to Predicator |
| 131 | +- Adds `Ecto.PredicatorInstructions` Ecto type |
| 132 | + |
| 133 | +## [0.9.1] |
| 134 | + |
| 135 | +### Documentation |
| 136 | +- Moves project from [predicator/predicator_elixir](https://github.com/predicator/predicator_elixir) to [riddler/predicator](https://github.com/riddler/predicator/tree/master/impl/ex) |
| 137 | + |
| 138 | +## [0.9.0] |
| 139 | + |
| 140 | +### Breaking Changes |
| 141 | +- Evaluates `compare` instead of `comparator` to be compatible with ruby predicator lib |
| 142 | + |
| 143 | +## [0.8.1] |
| 144 | + |
| 145 | +### Enhancements |
| 146 | +- Adds leex and parsing for `and` and `or` |
| 147 | +- Adds leex and parsing for `!` and boolean |
| 148 | + |
| 149 | +## [0.8.0] |
| 150 | + |
| 151 | +### Added |
| 152 | +- **Predicator.matches?/3** accepts evaluator options |
| 153 | + |
| 154 | +### Enhancements |
| 155 | +- Adds leex and parsing for `isblank` and `ispresent` |
| 156 | +- Supports escaped double quote strings |
| 157 | + |
| 158 | +### Fixed |
| 159 | +- `in` and `notin` accept list of strings |
| 160 | + |
| 161 | +## [0.7.3] |
| 162 | + |
| 163 | +### Enhancements |
| 164 | +- Adds leex and parsing for `in`, `notin`, `between`, `startswith`, `endswith` instructions |
| 165 | + |
| 166 | +## [0.7.1] |
| 167 | + |
| 168 | +### Added |
| 169 | +- Adds `between` instruction for eval on dates |
| 170 | + |
| 171 | +## [0.7.0] |
| 172 | + |
| 173 | +### Added |
| 174 | +- Adds 2 new comparison predicates for `starts_with` & `ends_with` |
| 175 | + |
| 176 | +## [0.6.0] |
| 177 | + |
| 178 | +### Added |
| 179 | +- Adds 3 new evaluatable predicates for `to_date`, `date_ago`, and `date_from_now` |
| 180 | + |
| 181 | +## [0.5.0] |
| 182 | + |
| 183 | +### Changed |
| 184 | +- Evaluator now reads new coercion instructions `to_int`, `to_str`, & `to_bool` |
| 185 | + |
| 186 | +## [0.4.0] |
| 187 | + |
| 188 | +### Added |
| 189 | +- Adds 4 new functions to the `Predicator` module: `eval/3`, `leex_string/1`, `parsed_lexed/1`, & `leex_and_parse/1` |
| 190 | + |
| 191 | +## [0.3.0] |
| 192 | + |
| 193 | +### Enhancements |
| 194 | +- Adds options to **Predicator.Evaluator.execute/3** as a keyword list to define if the context map is a string keyed list `[map_type: :string]` or atom keyed for the default `[map_type: :atom]` |
| 195 | + |
| 196 | +--- |
| 197 | + |
| 198 | +For detailed information about upcoming features and development roadmap, see the project README. |
0 commit comments