mongory 0.7.3-aarch64-linux-musl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of mongory might be problematic. Click here for more details.

Files changed (115) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +88 -0
  4. data/.yardopts +7 -0
  5. data/CHANGELOG.md +364 -0
  6. data/CODE_OF_CONDUCT.md +84 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +488 -0
  9. data/Rakefile +107 -0
  10. data/SUBMODULE_INTEGRATION.md +325 -0
  11. data/docs/advanced_usage.md +40 -0
  12. data/docs/clang_bridge.md +69 -0
  13. data/docs/field_names.md +30 -0
  14. data/docs/migration.md +30 -0
  15. data/docs/performance.md +61 -0
  16. data/examples/README.md +41 -0
  17. data/examples/benchmark-rails.rb +52 -0
  18. data/examples/benchmark.rb +184 -0
  19. data/ext/mongory_ext/extconf.rb +91 -0
  20. data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/array.h +122 -0
  21. data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/config.h +161 -0
  22. data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/error.h +79 -0
  23. data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/memory_pool.h +95 -0
  24. data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/table.h +127 -0
  25. data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/value.h +175 -0
  26. data/ext/mongory_ext/mongory-core/include/mongory-core/matchers/matcher.h +76 -0
  27. data/ext/mongory_ext/mongory-core/include/mongory-core.h +12 -0
  28. data/ext/mongory_ext/mongory-core/src/foundations/array.c +287 -0
  29. data/ext/mongory_ext/mongory-core/src/foundations/array_private.h +19 -0
  30. data/ext/mongory_ext/mongory-core/src/foundations/config.c +270 -0
  31. data/ext/mongory_ext/mongory-core/src/foundations/config_private.h +48 -0
  32. data/ext/mongory_ext/mongory-core/src/foundations/error.c +38 -0
  33. data/ext/mongory_ext/mongory-core/src/foundations/memory_pool.c +298 -0
  34. data/ext/mongory_ext/mongory-core/src/foundations/string_buffer.c +65 -0
  35. data/ext/mongory_ext/mongory-core/src/foundations/string_buffer.h +49 -0
  36. data/ext/mongory_ext/mongory-core/src/foundations/table.c +498 -0
  37. data/ext/mongory_ext/mongory-core/src/foundations/utils.c +210 -0
  38. data/ext/mongory_ext/mongory-core/src/foundations/utils.h +70 -0
  39. data/ext/mongory_ext/mongory-core/src/foundations/value.c +500 -0
  40. data/ext/mongory_ext/mongory-core/src/matchers/array_record_matcher.c +164 -0
  41. data/ext/mongory_ext/mongory-core/src/matchers/array_record_matcher.h +47 -0
  42. data/ext/mongory_ext/mongory-core/src/matchers/base_matcher.c +122 -0
  43. data/ext/mongory_ext/mongory-core/src/matchers/base_matcher.h +100 -0
  44. data/ext/mongory_ext/mongory-core/src/matchers/compare_matcher.c +217 -0
  45. data/ext/mongory_ext/mongory-core/src/matchers/compare_matcher.h +83 -0
  46. data/ext/mongory_ext/mongory-core/src/matchers/composite_matcher.c +573 -0
  47. data/ext/mongory_ext/mongory-core/src/matchers/composite_matcher.h +125 -0
  48. data/ext/mongory_ext/mongory-core/src/matchers/existance_matcher.c +147 -0
  49. data/ext/mongory_ext/mongory-core/src/matchers/existance_matcher.h +48 -0
  50. data/ext/mongory_ext/mongory-core/src/matchers/external_matcher.c +124 -0
  51. data/ext/mongory_ext/mongory-core/src/matchers/external_matcher.h +46 -0
  52. data/ext/mongory_ext/mongory-core/src/matchers/inclusion_matcher.c +126 -0
  53. data/ext/mongory_ext/mongory-core/src/matchers/inclusion_matcher.h +46 -0
  54. data/ext/mongory_ext/mongory-core/src/matchers/literal_matcher.c +314 -0
  55. data/ext/mongory_ext/mongory-core/src/matchers/literal_matcher.h +97 -0
  56. data/ext/mongory_ext/mongory-core/src/matchers/matcher.c +252 -0
  57. data/ext/mongory_ext/mongory-core/src/matchers/matcher_explainable.c +79 -0
  58. data/ext/mongory_ext/mongory-core/src/matchers/matcher_explainable.h +23 -0
  59. data/ext/mongory_ext/mongory-core/src/matchers/matcher_traversable.c +60 -0
  60. data/ext/mongory_ext/mongory-core/src/matchers/matcher_traversable.h +23 -0
  61. data/ext/mongory_ext/mongory_ext.c +683 -0
  62. data/lib/generators/mongory/install/install_generator.rb +42 -0
  63. data/lib/generators/mongory/install/templates/initializer.rb.erb +83 -0
  64. data/lib/generators/mongory/matcher/matcher_generator.rb +56 -0
  65. data/lib/generators/mongory/matcher/templates/matcher.rb.erb +92 -0
  66. data/lib/generators/mongory/matcher/templates/matcher_spec.rb.erb +17 -0
  67. data/lib/mongory/c_query_builder.rb +44 -0
  68. data/lib/mongory/converters/abstract_converter.rb +111 -0
  69. data/lib/mongory/converters/condition_converter.rb +64 -0
  70. data/lib/mongory/converters/converted.rb +81 -0
  71. data/lib/mongory/converters/data_converter.rb +37 -0
  72. data/lib/mongory/converters/key_converter.rb +87 -0
  73. data/lib/mongory/converters/value_converter.rb +52 -0
  74. data/lib/mongory/converters.rb +8 -0
  75. data/lib/mongory/matchers/abstract_matcher.rb +219 -0
  76. data/lib/mongory/matchers/abstract_multi_matcher.rb +124 -0
  77. data/lib/mongory/matchers/and_matcher.rb +72 -0
  78. data/lib/mongory/matchers/array_record_matcher.rb +93 -0
  79. data/lib/mongory/matchers/elem_match_matcher.rb +55 -0
  80. data/lib/mongory/matchers/eq_matcher.rb +46 -0
  81. data/lib/mongory/matchers/every_matcher.rb +56 -0
  82. data/lib/mongory/matchers/exists_matcher.rb +53 -0
  83. data/lib/mongory/matchers/field_matcher.rb +147 -0
  84. data/lib/mongory/matchers/gt_matcher.rb +41 -0
  85. data/lib/mongory/matchers/gte_matcher.rb +41 -0
  86. data/lib/mongory/matchers/hash_condition_matcher.rb +62 -0
  87. data/lib/mongory/matchers/in_matcher.rb +68 -0
  88. data/lib/mongory/matchers/literal_matcher.rb +121 -0
  89. data/lib/mongory/matchers/lt_matcher.rb +41 -0
  90. data/lib/mongory/matchers/lte_matcher.rb +41 -0
  91. data/lib/mongory/matchers/ne_matcher.rb +38 -0
  92. data/lib/mongory/matchers/nin_matcher.rb +68 -0
  93. data/lib/mongory/matchers/not_matcher.rb +40 -0
  94. data/lib/mongory/matchers/or_matcher.rb +68 -0
  95. data/lib/mongory/matchers/present_matcher.rb +55 -0
  96. data/lib/mongory/matchers/regex_matcher.rb +80 -0
  97. data/lib/mongory/matchers/size_matcher.rb +54 -0
  98. data/lib/mongory/matchers.rb +176 -0
  99. data/lib/mongory/mongoid.rb +19 -0
  100. data/lib/mongory/query_builder.rb +257 -0
  101. data/lib/mongory/query_matcher.rb +93 -0
  102. data/lib/mongory/query_operator.rb +28 -0
  103. data/lib/mongory/rails.rb +15 -0
  104. data/lib/mongory/utils/context.rb +48 -0
  105. data/lib/mongory/utils/debugger.rb +125 -0
  106. data/lib/mongory/utils/rails_patch.rb +22 -0
  107. data/lib/mongory/utils/singleton_builder.rb +31 -0
  108. data/lib/mongory/utils.rb +76 -0
  109. data/lib/mongory/version.rb +5 -0
  110. data/lib/mongory.rb +123 -0
  111. data/lib/mongory_ext.so +0 -0
  112. data/mongory.gemspec +62 -0
  113. data/scripts/build_with_core.sh +292 -0
  114. data/sig/mongory.rbs +4 -0
  115. metadata +159 -0
@@ -0,0 +1,164 @@
1
+ /**
2
+ * @file array_record_matcher.c
3
+ * @brief Implements a versatile matcher for arrays, handling various condition
4
+ * types. This is an internal implementation file for the matcher module.
5
+ *
6
+ * This matcher can interpret conditions as:
7
+ * - A table: Parsed for operators like $elemMatch or implicit field conditions
8
+ * on array elements.
9
+ * - A regex: Creates an $elemMatch to match array elements against the regex.
10
+ * - A literal: Creates an $elemMatch to check for equality with elements.
11
+ * - Another array: Checks for whole-array equality.
12
+ * It often constructs a composite OR matcher to combine these possibilities.
13
+ */
14
+ #include "array_record_matcher.h"
15
+ #include "../foundations/config_private.h"
16
+ #include "../foundations/utils.h" // For mongory_try_parse_int
17
+ #include "base_matcher.h" // For mongory_matcher_base_new
18
+ #include "compare_matcher.h" // For mongory_matcher_equal_new
19
+ #include "composite_matcher.h" // For mongory_matcher_composite_new, $elemMatch, table_cond_new, or_match
20
+ #include "literal_matcher.h" // Potentially used by table_cond_new
21
+ #include "mongory-core/foundations/table.h"
22
+ #include "mongory-core/foundations/value.h"
23
+ #include <mongory-core.h> // General include
24
+ #include <stdio.h> // For NULL
25
+ #include <string.h> // For strcmp
26
+
27
+ /**
28
+ * @struct mongory_matcher_array_record_parse_table_context
29
+ * @brief Context used when parsing a table condition for array record matching.
30
+ *
31
+ * Helps separate parts of the condition table:
32
+ * - `parsed_table`: For explicit operators (e.g., $size, $all if implemented)
33
+ * or indexed conditions.
34
+ * - `elem_match_table`: For conditions that should apply to individual elements
35
+ * via an implicit or explicit $elemMatch.
36
+ */
37
+ typedef struct mongory_matcher_array_record_parse_table_context {
38
+ mongory_table *parsed_table; /**< Stores operator or indexed conditions. */
39
+ mongory_table *elem_match_table; /**< Stores conditions for element matching. */
40
+ } mongory_matcher_array_record_parse_table_context;
41
+
42
+ /**
43
+ * @brief Callback to parse a condition table for array matching.
44
+ *
45
+ * Iterates through the main condition table:
46
+ * - If `key` is "$elemMatch" and `value` is a table, its contents are added to
47
+ * `context->elem_match_table`.
48
+ * - If `key` starts with '$' (another operator) or is numeric (array index),
49
+ * it's added to `context->parsed_table`.
50
+ * - Otherwise (plain field name), it's considered part of an implicit element
51
+ * match and added to `context->elem_match_table`.
52
+ *
53
+ * @param key Current key in the condition table.
54
+ * @param value Current value for the key.
55
+ * @param acc Pointer to `mongory_matcher_array_record_parse_table_context`.
56
+ * @return Always true to continue.
57
+ */
58
+ static inline bool mongory_matcher_array_record_parse_table_foreach(char *key, mongory_value *value, void *acc) {
59
+ mongory_matcher_array_record_parse_table_context *context = (mongory_matcher_array_record_parse_table_context *)acc;
60
+ mongory_table *parsed_table_for_operators = context->parsed_table;
61
+ mongory_table *table_for_elem_match_conditions = context->elem_match_table;
62
+
63
+ if (strcmp(key, "$elemMatch") == 0 && value->type == MONGORY_TYPE_TABLE && value->data.t != NULL) {
64
+ // Explicit $elemMatch: iterate its sub-table and add to elem_match_table
65
+ mongory_table_merge(table_for_elem_match_conditions, value->data.t);
66
+ } else if (*key == '$' || mongory_try_parse_int(key, NULL)) {
67
+ // Operator (like $size) or numeric index: goes to parsed_table
68
+ parsed_table_for_operators->set(parsed_table_for_operators, key, value);
69
+ } else {
70
+ // Regular field name: implies a condition on elements, goes to
71
+ // elem_match_table
72
+ table_for_elem_match_conditions->set(table_for_elem_match_conditions, key, value);
73
+ }
74
+ return true;
75
+ }
76
+
77
+ /**
78
+ * @brief Parses a table `condition` intended for array matching.
79
+ *
80
+ * Separates the condition into parts for direct array operations (like $size)
81
+ * and parts for matching individual elements (implicit or explicit $elemMatch).
82
+ * If any element-matching conditions are found, they are grouped under an
83
+ * "$elemMatch" key in the returned `parsed_table`.
84
+ *
85
+ * @param condition The `mongory_value` (must be a table) to parse.
86
+ * @return A new `mongory_value` (table) containing the parsed and restructured
87
+ * condition. Returns NULL if input is not a table or on allocation failure.
88
+ */
89
+ static inline mongory_value *mongory_matcher_array_record_parse_table(mongory_value *condition) {
90
+ if (!condition->data.t || !condition->pool) {
91
+ mongory_error *error = MG_ALLOC_PTR(condition->pool, mongory_error);
92
+ if (!error) {
93
+ condition->pool->error = &MONGORY_ALLOC_ERROR;
94
+ return NULL;
95
+ }
96
+ error->type = MONGORY_ERROR_INVALID_TYPE;
97
+ error->message = "Expected condition to be a table, got a non-table value";
98
+ condition->pool->error = error; // TODO: This is a hack, we should use a better error handling mechanism
99
+ return NULL; // Invalid input
100
+ }
101
+ mongory_memory_pool *pool = condition->pool;
102
+ mongory_table *parsed_table = mongory_table_new(pool);
103
+ mongory_table *elem_match_sub_table = mongory_table_new(pool);
104
+
105
+ if (!parsed_table || !elem_match_sub_table) {
106
+ // Cleanup if one allocation succeeded but other failed? Pool should handle.
107
+ return NULL;
108
+ }
109
+
110
+ mongory_matcher_array_record_parse_table_context parse_ctx = {parsed_table, elem_match_sub_table};
111
+ mongory_table *original_condition_table = condition->data.t;
112
+
113
+ original_condition_table->each(original_condition_table, &parse_ctx,
114
+ mongory_matcher_array_record_parse_table_foreach);
115
+
116
+ if (elem_match_sub_table->count > 0) {
117
+ // If there were conditions for element matching, add them as an $elemMatch
118
+ // clause to the main parsed_table.
119
+ parsed_table->set(parsed_table, "$elemMatch", mongory_value_wrap_t(pool, elem_match_sub_table));
120
+ }
121
+ // If elem_match_sub_table is empty, it's not added. The original parsed_table
122
+ // (which might contain $size etc.) is returned.
123
+ return mongory_value_wrap_t(pool, parsed_table);
124
+ }
125
+
126
+ /**
127
+ * @brief Main constructor for `mongory_matcher_array_record_new`.
128
+ *
129
+ * Constructs a two-part matcher (often combined with OR):
130
+ * - `left`: Handles element-wise conditions (like $elemMatch from various
131
+ * condition types).
132
+ * - `right`: Handles whole-array equality if the original `condition` was an
133
+ * array.
134
+ *
135
+ * If `right` is NULL (i.e., original `condition` was not an array), only the
136
+ * `left` matcher is returned. Otherwise, a composite OR matcher is created
137
+ * with `left` and `right` as children.
138
+ *
139
+ * @param pool Memory pool.
140
+ * @param condition The condition to apply to arrays.
141
+ * @return The constructed array_record_matcher, or NULL on failure.
142
+ */
143
+ mongory_matcher *mongory_matcher_array_record_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx) {
144
+ if (!condition)
145
+ return NULL;
146
+ switch (condition->type) {
147
+ case MONGORY_TYPE_TABLE:
148
+ return mongory_matcher_table_cond_new(pool,
149
+ mongory_matcher_array_record_parse_table(condition),
150
+ extern_ctx
151
+ );
152
+ case MONGORY_TYPE_ARRAY:
153
+ return mongory_matcher_or_new(pool, MG_ARRAY_WRAP(pool, 2,
154
+ MG_TABLE_WRAP(pool, 1, "$eq", condition),
155
+ MG_TABLE_WRAP(pool, 1, "$elemMatch",
156
+ MG_TABLE_WRAP(pool, 1, "$eq", condition)
157
+ )
158
+ ), extern_ctx);
159
+ case MONGORY_TYPE_REGEX:
160
+ return mongory_matcher_elem_match_new(pool, MG_TABLE_WRAP(pool, 1, "$regex", condition), extern_ctx);
161
+ default: // Literals (string, int, bool, etc.)
162
+ return mongory_matcher_elem_match_new(pool, MG_TABLE_WRAP(pool, 1, "$eq", condition), extern_ctx);
163
+ }
164
+ }
@@ -0,0 +1,47 @@
1
+ #ifndef MONGORY_MATCHER_ARRAY_RECORD_H
2
+ #define MONGORY_MATCHER_ARRAY_RECORD_H
3
+
4
+ /**
5
+ * @file array_record_matcher.h
6
+ * @brief Defines the constructor for a matcher that handles complex conditions
7
+ * against arrays. This is an internal header for the matcher module.
8
+ *
9
+ * This matcher is more specialized than simple `$elemMatch` or `$every`. It can
10
+ * interpret a condition that might be a direct value to find, a regex to match
11
+ * elements, or a table defining multiple criteria for array elements (similar
12
+ * to an implicit `$elemMatch` with that table). It can also handle checking if
13
+ * an input array is equal to a condition array.
14
+ */
15
+
16
+ #include "base_matcher.h"
17
+ #include "mongory-core/foundations/memory_pool.h"
18
+ #include "mongory-core/foundations/value.h"
19
+ #include "mongory-core/matchers/matcher.h" // For mongory_matcher structure
20
+
21
+ /**
22
+ * @brief Creates an "array record" matcher.
23
+ *
24
+ * This matcher is designed to apply various types of conditions to an input
25
+ * array or its elements. The behavior depends on the `condition`'s type:
26
+ * - If `condition` is a table: It's parsed. Keys like `$elemMatch` are handled
27
+ * specifically. Other field-value pairs in the table are typically wrapped
28
+ * into an implicit `$elemMatch` condition that applies to elements of the
29
+ * target array.
30
+ * - If `condition` is a regex: It effectively creates an `$elemMatch` where
31
+ * each element of the target array is matched against this regex.
32
+ * - If `condition` is a simple literal (string, number, bool): It creates an
33
+ * `$elemMatch` where elements are checked for equality against this literal.
34
+ * - If `condition` itself is an array: It creates a matcher that checks if the
35
+ * target array is equal to this condition array.
36
+ *
37
+ * The resulting matcher might be a composite of several internal matchers (e.g.,
38
+ * an OR between element matching and whole-array equality).
39
+ *
40
+ * @param pool Memory pool for allocation.
41
+ * @param condition A `mongory_value` representing the condition to apply to an
42
+ * array or its elements.
43
+ * @return A new array record matcher, or NULL on failure.
44
+ */
45
+ mongory_matcher *mongory_matcher_array_record_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx);
46
+
47
+ #endif /* MONGORY_MATCHER_ARRAY_RECORD_H */
@@ -0,0 +1,122 @@
1
+ /**
2
+ * @file base_matcher.c
3
+ * @brief Implements the base matcher constructor and related utility functions.
4
+ * This is an internal implementation file for the matcher module.
5
+ */
6
+ #include "base_matcher.h"
7
+ #include "../foundations/string_buffer.h"
8
+ #include <errno.h> // For errno, ERANGE
9
+ #include <limits.h> // For INT_MIN, INT_MAX
10
+ #include <mongory-core.h> // General include, for mongory_matcher types
11
+ #include <stdbool.h>
12
+ #include <stdio.h> // For printf
13
+ #include <stdlib.h> // For strtol
14
+ #include "matcher_explainable.h"
15
+ #include "matcher_traversable.h"
16
+ #include "../foundations/utils.h"
17
+
18
+ /**
19
+ * @brief Allocates and initializes common fields of a `mongory_matcher`.
20
+ *
21
+ * This function serves as a common initializer for all specific matcher types.
22
+ * It allocates memory for the `mongory_matcher` structure itself from the
23
+ * provided `pool`, sets the `pool` and `condition` members.
24
+ * The `matcher->match` function pointer specific to the matcher type must be
25
+ * set by the caller. `original_match` and `trace` in the context are set to
26
+ * NULL.
27
+ *
28
+ * @param pool The memory pool to use for allocation. Must be non-NULL and
29
+ * valid.
30
+ * @param condition The condition value for this matcher.
31
+ * @return mongory_matcher* Pointer to the newly allocated and partially
32
+ * initialized matcher, or NULL if allocation fails.
33
+ */
34
+ mongory_matcher *mongory_matcher_base_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx) {
35
+ if (!pool || !pool->alloc) {
36
+ return NULL; // Invalid memory pool.
37
+ }
38
+ mongory_matcher *matcher = MG_ALLOC_PTR(pool, mongory_matcher);
39
+ if (matcher == NULL) {
40
+ // Allocation failed, pool->alloc might set pool->error.
41
+ pool->error = &MONGORY_ALLOC_ERROR;
42
+ return NULL;
43
+ }
44
+
45
+ // Initialize common fields
46
+ matcher->original_match = NULL;
47
+ matcher->sub_count = 0;
48
+ matcher->pool = pool;
49
+ matcher->condition = condition;
50
+ matcher->name = NULL; // Name is not set by base_new.
51
+ matcher->match = NULL; // Specific match function must be set by derived type.
52
+ matcher->explain = mongory_matcher_base_explain; // Specific explain function must be set by derived type.
53
+ matcher->traverse = mongory_matcher_leaf_traverse;
54
+ matcher->extern_ctx = extern_ctx; // Set the external context.
55
+ matcher->priority = 1.0; // Set the priority to 1.0.
56
+ return matcher;
57
+ }
58
+
59
+ /**
60
+ * @brief The match function for a matcher that always returns true.
61
+ * @param matcher Unused.
62
+ * @param value Unused.
63
+ * @return Always true.
64
+ */
65
+ static inline bool mongory_matcher_always_true_match(mongory_matcher *matcher, mongory_value *value) {
66
+ (void)matcher; // Mark as unused to prevent compiler warnings.
67
+ (void)value; // Mark as unused.
68
+ return true; // This matcher always indicates a match.
69
+ }
70
+
71
+ /**
72
+ * @brief Creates a matcher instance that will always evaluate to true.
73
+ * Useful as a placeholder or for default cases.
74
+ * @param pool Memory pool for allocation.
75
+ * @param condition Condition (typically ignored by this matcher).
76
+ * @return A new `mongory_matcher` or NULL on failure.
77
+ */
78
+ mongory_matcher *mongory_matcher_always_true_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx) {
79
+ mongory_matcher *matcher = mongory_matcher_base_new(pool, condition, extern_ctx);
80
+ if (!matcher) {
81
+ return NULL;
82
+ }
83
+ matcher->match = mongory_matcher_always_true_match;
84
+ matcher->original_match = mongory_matcher_always_true_match;
85
+ matcher->name = mongory_string_cpy(pool, "Always True");
86
+ matcher->explain = mongory_matcher_base_explain;
87
+ // Optionally set original_match as well if it's a strict policy
88
+ // matcher->context.original_match = mongory_matcher_always_true_match;
89
+ return matcher;
90
+ }
91
+
92
+ /**
93
+ * @brief The match function for a matcher that always returns false.
94
+ * @param matcher Unused.
95
+ * @param value Unused.
96
+ * @return Always false.
97
+ */
98
+ static inline bool mongory_matcher_always_false_match(mongory_matcher *matcher, mongory_value *value) {
99
+ (void)matcher; // Mark as unused.
100
+ (void)value; // Mark as unused.
101
+ return false; // This matcher never indicates a match.
102
+ }
103
+
104
+ /**
105
+ * @brief Creates a matcher instance that will always evaluate to false.
106
+ * Useful for conditions that should never match.
107
+ * @param pool Memory pool for allocation.
108
+ * @param condition Condition (typically ignored by this matcher).
109
+ * @return A new `mongory_matcher` or NULL on failure.
110
+ */
111
+ mongory_matcher *mongory_matcher_always_false_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx) {
112
+ mongory_matcher *matcher = mongory_matcher_base_new(pool, condition, extern_ctx);
113
+ if (!matcher) {
114
+ return NULL;
115
+ }
116
+ matcher->match = mongory_matcher_always_false_match;
117
+ matcher->original_match = mongory_matcher_always_false_match;
118
+ matcher->name = mongory_string_cpy(pool, "Always False");
119
+ matcher->explain = mongory_matcher_base_explain;
120
+ // matcher->context.original_match = mongory_matcher_always_false_match;
121
+ return matcher;
122
+ }
@@ -0,0 +1,100 @@
1
+ #ifndef MONGORY_MATCHER_BASE_H
2
+ #define MONGORY_MATCHER_BASE_H
3
+
4
+ /**
5
+ * @file base_matcher.h
6
+ * @brief Defines the base matcher constructor and utility functions for
7
+ * matchers. This is an internal header for the matcher module.
8
+ *
9
+ * This includes a constructor for the fundamental `mongory_matcher` structure,
10
+ * constructors for trivial matchers (always true/false), and a utility
11
+ * for parsing integers from strings.
12
+ */
13
+
14
+ #include "mongory-core/foundations/array.h" // For mongory_array (context trace)
15
+ #include "mongory-core/foundations/memory_pool.h"
16
+ #include "mongory-core/foundations/value.h"
17
+ #include "mongory-core/matchers/matcher.h" // For mongory_matcher structure
18
+ #include "matcher_explainable.h"
19
+ #include "matcher_traversable.h"
20
+ #include <stdbool.h>
21
+
22
+ /**
23
+ * @brief Function pointer type for a matcher's core matching logic.
24
+ *
25
+ * @param matcher A pointer to the `mongory_matcher` instance itself.
26
+ * @param value A pointer to the `mongory_value` to be evaluated against the
27
+ * matcher's condition.
28
+ * @return bool True if the `value` matches the condition, false otherwise.
29
+ */
30
+ typedef bool (*mongory_matcher_match_func)(mongory_matcher *matcher, mongory_value *value);
31
+
32
+ /**
33
+ * @struct mongory_matcher
34
+ * @brief Represents a generic matcher in the Mongory system.
35
+ *
36
+ * Each matcher has a name (optional, for identification), a condition value
37
+ * that defines its criteria, a function pointer to its matching logic,
38
+ * a memory pool for its allocations, and a context.
39
+ */
40
+ struct mongory_matcher {
41
+ char *name; /**< Optional name for the matcher (e.g., "$eq").
42
+ String is typically allocated from the pool. */
43
+ mongory_value *condition; /**< The condition (a `mongory_value`) that this
44
+ matcher evaluates against. */
45
+ mongory_matcher_match_func match; /**< Function pointer to the specific matching
46
+ logic for this matcher type. */
47
+ mongory_memory_pool *pool; /**< The memory pool used for allocations related
48
+ to this matcher instance. */
49
+ mongory_matcher_traverse_func explain; /**< Function pointer to the explanation
50
+ logic for this matcher type. */
51
+ mongory_matcher_match_func original_match; /**< Stores the original match function, potentially for
52
+ restoration or delegation. */
53
+ size_t sub_count; /**< The number of sub-matchers. */
54
+ mongory_matcher_traverse_func traverse; /**< Function pointer to the traversal logic for this matcher type. */
55
+ mongory_array *trace_stack; /**< The trace stack for this matcher. */
56
+ int trace_level; /**< The trace level for this matcher. */
57
+ double priority; /**< The priority for this matcher. */
58
+ void *extern_ctx; /**< External context for the matcher. */
59
+ };
60
+
61
+ /**
62
+ * @brief Creates a new base `mongory_matcher` instance and initializes its
63
+ * common fields.
64
+ *
65
+ * This function allocates a `mongory_matcher` structure from the provided pool
66
+ * and sets its `pool` and `condition` fields. The `match` function and other
67
+ * specific fields must be set by the caller or derived matcher constructors.
68
+ * The context's original_match and trace are initialized to NULL.
69
+ *
70
+ * @param pool The memory pool to use for allocating the matcher.
71
+ * @param condition The `mongory_value` representing the condition for this
72
+ * matcher.
73
+ * @return mongory_matcher* A pointer to the newly allocated base matcher, or
74
+ * NULL on allocation failure.
75
+ */
76
+ mongory_matcher *mongory_matcher_base_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx);
77
+
78
+ /**
79
+ * @brief Creates a new matcher that always evaluates to true.
80
+ *
81
+ * @param pool The memory pool for allocation.
82
+ * @param condition The condition value (often unused by this matcher but stored
83
+ * for consistency).
84
+ * @return mongory_matcher* A pointer to the "always true" matcher, or NULL on
85
+ * failure.
86
+ */
87
+ mongory_matcher *mongory_matcher_always_true_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx);
88
+
89
+ /**
90
+ * @brief Creates a new matcher that always evaluates to false.
91
+ *
92
+ * @param pool The memory pool for allocation.
93
+ * @param condition The condition value (often unused by this matcher but stored
94
+ * for consistency).
95
+ * @return mongory_matcher* A pointer to the "always false" matcher, or NULL on
96
+ * failure.
97
+ */
98
+ mongory_matcher *mongory_matcher_always_false_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx);
99
+
100
+ #endif /* MONGORY_MATCHER_BASE_H */
@@ -0,0 +1,217 @@
1
+ /**
2
+ * @file compare_matcher.c
3
+ * @brief Implements comparison matchers like `$eq`, `$gt`, `$lt`, etc.
4
+ *
5
+ * This file follows a factory pattern. A generic private constructor,
6
+ * `mongory_matcher_compare_new`, is used to create a base matcher.
7
+ * Each specific comparison operator (e.g., `$eq`, `$gt`) has its own public
8
+ * constructor (e.g., `mongory_matcher_equal_new`) that provides a specialized
9
+ * matching function to the generic constructor.
10
+ */
11
+ #include "compare_matcher.h"
12
+ #include "base_matcher.h" // For mongory_matcher_base_new
13
+ #include <mongory-core.h> // For mongory_value, mongory_matcher types
14
+ #include "../foundations/utils.h"
15
+
16
+ /**
17
+ * @brief Generic constructor for comparison matchers.
18
+ *
19
+ * Initializes a base matcher and sets its `match` function and
20
+ * `original_match` context field to the provided `match_func`.
21
+ *
22
+ * @param pool The memory pool for allocation.
23
+ * @param condition The `mongory_value` to be stored as the comparison target.
24
+ * @param match_func The specific comparison logic function (e.g., for equality,
25
+ * greater than).
26
+ * @return mongory_matcher* A pointer to the newly created comparison matcher,
27
+ * or NULL on failure.
28
+ */
29
+ static inline mongory_matcher *mongory_matcher_compare_new(mongory_memory_pool *pool, mongory_value *condition,
30
+ mongory_matcher_match_func match_func, void *extern_ctx) {
31
+ mongory_matcher *matcher = mongory_matcher_base_new(pool, condition, extern_ctx);
32
+ if (matcher == NULL) {
33
+ return NULL; // Base matcher allocation failed.
34
+ }
35
+ matcher->match = match_func;
36
+ matcher->original_match = match_func; // Store original match function
37
+ return matcher;
38
+ }
39
+
40
+ // ============================================================================
41
+ // Static Match Functions
42
+ //
43
+ // These functions contain the actual logic for each comparison operator.
44
+ // They all follow the `mongory_matcher_match_func` signature and are passed
45
+ // to the generic constructor.
46
+ // ============================================================================
47
+
48
+ /**
49
+ * @brief Match function for equality ($eq).
50
+ *
51
+ * Compares the input `value` with the matcher's `condition` using the
52
+ * polymorphic `comp` function of the value.
53
+ *
54
+ * @param matcher The equality matcher instance.
55
+ * @param value The value to check.
56
+ * @return True if `value` is equal to `matcher->condition`; false otherwise or
57
+ * if the types are not comparable.
58
+ */
59
+ static inline bool mongory_matcher_equal_match(mongory_matcher *matcher, mongory_value *value) {
60
+ if (!value || !value->comp || !matcher->condition)
61
+ return false; // Invalid inputs
62
+ int result = value->comp(value, matcher->condition);
63
+ if (result == mongory_value_compare_fail) {
64
+ return false; // Types are not comparable or other comparison error.
65
+ }
66
+ return result == 0; // 0 indicates equality.
67
+ }
68
+
69
+ mongory_matcher *mongory_matcher_equal_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx) {
70
+ mongory_matcher *matcher = mongory_matcher_compare_new(pool, condition, mongory_matcher_equal_match, extern_ctx);
71
+ if (!matcher) {
72
+ return NULL;
73
+ }
74
+ matcher->name = mongory_string_cpy(pool, "Eq");
75
+ matcher->priority = 1.0;
76
+ return matcher;
77
+ }
78
+
79
+ /**
80
+ * @brief Match function for inequality ($ne).
81
+ *
82
+ * This is the logical inverse of the `equal_match` function.
83
+ * If the types are not comparable (comparison fails), it is considered "not
84
+ * equal", so this function returns true in that case.
85
+ *
86
+ * @param matcher The inequality matcher instance.
87
+ * @param value The value to check.
88
+ * @return True if `value` is not equal to `matcher->condition` or if they
89
+ * are not comparable.
90
+ */
91
+ static inline bool mongory_matcher_not_equal_match(mongory_matcher *matcher, mongory_value *value) {
92
+ if (!value || !value->comp || !matcher->condition)
93
+ return true; // Invalid inputs, treat as "not equal"
94
+ int result = value->comp(value, matcher->condition);
95
+ if (result == mongory_value_compare_fail) {
96
+ return true; // Incomparable types are considered "not equal".
97
+ }
98
+ return result != 0; // Non-zero indicates inequality.
99
+ }
100
+
101
+ mongory_matcher *mongory_matcher_not_equal_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx) {
102
+ mongory_matcher *matcher = mongory_matcher_compare_new(pool, condition, mongory_matcher_not_equal_match, extern_ctx);
103
+ if (!matcher) {
104
+ return NULL;
105
+ }
106
+ matcher->name = mongory_string_cpy(pool, "Ne");
107
+ matcher->priority = 1.0;
108
+ return matcher;
109
+ }
110
+
111
+ /**
112
+ * @brief Match function for "greater than" ($gt).
113
+ * @param matcher The $gt matcher instance.
114
+ * @param value The value to check.
115
+ * @return True if `value` is greater than `matcher->condition`, false
116
+ * otherwise or on comparison failure.
117
+ */
118
+ static inline bool mongory_matcher_greater_than_match(mongory_matcher *matcher, mongory_value *value) {
119
+ if (!value || !value->comp || !matcher->condition)
120
+ return false;
121
+ int result = value->comp(value, matcher->condition);
122
+ if (result == mongory_value_compare_fail) {
123
+ return false;
124
+ }
125
+ return result == 1; // 1 indicates value > condition.
126
+ }
127
+
128
+ mongory_matcher *mongory_matcher_greater_than_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx) {
129
+ mongory_matcher *matcher = mongory_matcher_compare_new(pool, condition, mongory_matcher_greater_than_match, extern_ctx);
130
+ if (!matcher) {
131
+ return NULL;
132
+ }
133
+ matcher->name = mongory_string_cpy(pool, "Gt");
134
+ matcher->priority = 2.0;
135
+ return matcher;
136
+ }
137
+
138
+ /**
139
+ * @brief Match function for "less than" ($lt).
140
+ * @param matcher The $lt matcher instance.
141
+ * @param value The value to check.
142
+ * @return True if `value` is less than `matcher->condition`, false otherwise or
143
+ * on comparison failure.
144
+ */
145
+ static inline bool mongory_matcher_less_than_match(mongory_matcher *matcher, mongory_value *value) {
146
+ if (!value || !value->comp || !matcher->condition)
147
+ return false;
148
+ int result = value->comp(value, matcher->condition);
149
+ if (result == mongory_value_compare_fail) {
150
+ return false;
151
+ }
152
+ return result == -1; // -1 indicates value < condition.
153
+ }
154
+
155
+ mongory_matcher *mongory_matcher_less_than_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx) {
156
+ mongory_matcher *matcher = mongory_matcher_compare_new(pool, condition, mongory_matcher_less_than_match, extern_ctx);
157
+ if (!matcher) {
158
+ return NULL;
159
+ }
160
+ matcher->name = mongory_string_cpy(pool, "Lt");
161
+ matcher->priority = 2.0;
162
+ return matcher;
163
+ }
164
+
165
+ /**
166
+ * @brief Match function for "greater than or equal" ($gte).
167
+ * @param matcher The $gte matcher instance.
168
+ * @param value The value to check.
169
+ * @return True if `value` is >= `matcher->condition`, false otherwise or on
170
+ * comparison failure.
171
+ */
172
+ static inline bool mongory_matcher_greater_than_or_equal_match(mongory_matcher *matcher, mongory_value *value) {
173
+ if (!value || !value->comp || !matcher->condition)
174
+ return false;
175
+ int result = value->comp(value, matcher->condition);
176
+ if (result == mongory_value_compare_fail) {
177
+ return false;
178
+ }
179
+ return result >= 0; // 0 or 1 indicates value >= condition.
180
+ }
181
+
182
+ mongory_matcher *mongory_matcher_greater_than_or_equal_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx) {
183
+ mongory_matcher *matcher = mongory_matcher_compare_new(pool, condition, mongory_matcher_greater_than_or_equal_match, extern_ctx);
184
+ if (!matcher) {
185
+ return NULL;
186
+ }
187
+ matcher->name = mongory_string_cpy(pool, "Gte");
188
+ matcher->priority = 2.0;
189
+ return matcher;
190
+ }
191
+
192
+ /**
193
+ * @brief Match function for "less than or equal" ($lte).
194
+ * @param matcher The $lte matcher instance.
195
+ * @param value The value to check.
196
+ * @return True if `value` is <= `matcher->condition`, false otherwise or on
197
+ * comparison failure.
198
+ */
199
+ static inline bool mongory_matcher_less_than_or_equal_match(mongory_matcher *matcher, mongory_value *value) {
200
+ if (!value || !value->comp || !matcher->condition)
201
+ return false;
202
+ int result = value->comp(value, matcher->condition);
203
+ if (result == mongory_value_compare_fail) {
204
+ return false;
205
+ }
206
+ return result <= 0; // 0 or -1 indicates value <= condition.
207
+ }
208
+
209
+ mongory_matcher *mongory_matcher_less_than_or_equal_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx) {
210
+ mongory_matcher *matcher = mongory_matcher_compare_new(pool, condition, mongory_matcher_less_than_or_equal_match, extern_ctx);
211
+ if (!matcher) {
212
+ return NULL;
213
+ }
214
+ matcher->name = mongory_string_cpy(pool, "Lte");
215
+ matcher->priority = 2.0;
216
+ return matcher;
217
+ }