mongory 0.7.2-x86_64-linux
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.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +88 -0
- data/.yardopts +7 -0
- data/CHANGELOG.md +364 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/LICENSE.txt +21 -0
- data/README.md +488 -0
- data/Rakefile +107 -0
- data/SUBMODULE_INTEGRATION.md +325 -0
- data/docs/advanced_usage.md +40 -0
- data/docs/clang_bridge.md +69 -0
- data/docs/field_names.md +30 -0
- data/docs/migration.md +30 -0
- data/docs/performance.md +61 -0
- data/examples/README.md +41 -0
- data/examples/benchmark-rails.rb +52 -0
- data/examples/benchmark.rb +184 -0
- data/ext/mongory_ext/extconf.rb +91 -0
- data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/array.h +122 -0
- data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/config.h +161 -0
- data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/error.h +79 -0
- data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/memory_pool.h +95 -0
- data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/table.h +127 -0
- data/ext/mongory_ext/mongory-core/include/mongory-core/foundations/value.h +175 -0
- data/ext/mongory_ext/mongory-core/include/mongory-core/matchers/matcher.h +76 -0
- data/ext/mongory_ext/mongory-core/include/mongory-core.h +12 -0
- data/ext/mongory_ext/mongory-core/src/foundations/array.c +287 -0
- data/ext/mongory_ext/mongory-core/src/foundations/array_private.h +19 -0
- data/ext/mongory_ext/mongory-core/src/foundations/config.c +270 -0
- data/ext/mongory_ext/mongory-core/src/foundations/config_private.h +48 -0
- data/ext/mongory_ext/mongory-core/src/foundations/error.c +38 -0
- data/ext/mongory_ext/mongory-core/src/foundations/memory_pool.c +298 -0
- data/ext/mongory_ext/mongory-core/src/foundations/string_buffer.c +65 -0
- data/ext/mongory_ext/mongory-core/src/foundations/string_buffer.h +49 -0
- data/ext/mongory_ext/mongory-core/src/foundations/table.c +498 -0
- data/ext/mongory_ext/mongory-core/src/foundations/utils.c +210 -0
- data/ext/mongory_ext/mongory-core/src/foundations/utils.h +70 -0
- data/ext/mongory_ext/mongory-core/src/foundations/value.c +500 -0
- data/ext/mongory_ext/mongory-core/src/matchers/array_record_matcher.c +164 -0
- data/ext/mongory_ext/mongory-core/src/matchers/array_record_matcher.h +47 -0
- data/ext/mongory_ext/mongory-core/src/matchers/base_matcher.c +122 -0
- data/ext/mongory_ext/mongory-core/src/matchers/base_matcher.h +100 -0
- data/ext/mongory_ext/mongory-core/src/matchers/compare_matcher.c +217 -0
- data/ext/mongory_ext/mongory-core/src/matchers/compare_matcher.h +83 -0
- data/ext/mongory_ext/mongory-core/src/matchers/composite_matcher.c +573 -0
- data/ext/mongory_ext/mongory-core/src/matchers/composite_matcher.h +125 -0
- data/ext/mongory_ext/mongory-core/src/matchers/existance_matcher.c +147 -0
- data/ext/mongory_ext/mongory-core/src/matchers/existance_matcher.h +48 -0
- data/ext/mongory_ext/mongory-core/src/matchers/external_matcher.c +124 -0
- data/ext/mongory_ext/mongory-core/src/matchers/external_matcher.h +46 -0
- data/ext/mongory_ext/mongory-core/src/matchers/inclusion_matcher.c +126 -0
- data/ext/mongory_ext/mongory-core/src/matchers/inclusion_matcher.h +46 -0
- data/ext/mongory_ext/mongory-core/src/matchers/literal_matcher.c +314 -0
- data/ext/mongory_ext/mongory-core/src/matchers/literal_matcher.h +97 -0
- data/ext/mongory_ext/mongory-core/src/matchers/matcher.c +252 -0
- data/ext/mongory_ext/mongory-core/src/matchers/matcher_explainable.c +79 -0
- data/ext/mongory_ext/mongory-core/src/matchers/matcher_explainable.h +23 -0
- data/ext/mongory_ext/mongory-core/src/matchers/matcher_traversable.c +60 -0
- data/ext/mongory_ext/mongory-core/src/matchers/matcher_traversable.h +23 -0
- data/ext/mongory_ext/mongory_ext.c +683 -0
- data/lib/generators/mongory/install/install_generator.rb +42 -0
- data/lib/generators/mongory/install/templates/initializer.rb.erb +83 -0
- data/lib/generators/mongory/matcher/matcher_generator.rb +56 -0
- data/lib/generators/mongory/matcher/templates/matcher.rb.erb +92 -0
- data/lib/generators/mongory/matcher/templates/matcher_spec.rb.erb +17 -0
- data/lib/mongory/c_query_builder.rb +44 -0
- data/lib/mongory/converters/abstract_converter.rb +111 -0
- data/lib/mongory/converters/condition_converter.rb +64 -0
- data/lib/mongory/converters/converted.rb +81 -0
- data/lib/mongory/converters/data_converter.rb +37 -0
- data/lib/mongory/converters/key_converter.rb +87 -0
- data/lib/mongory/converters/value_converter.rb +52 -0
- data/lib/mongory/converters.rb +8 -0
- data/lib/mongory/matchers/abstract_matcher.rb +219 -0
- data/lib/mongory/matchers/abstract_multi_matcher.rb +124 -0
- data/lib/mongory/matchers/and_matcher.rb +72 -0
- data/lib/mongory/matchers/array_record_matcher.rb +93 -0
- data/lib/mongory/matchers/elem_match_matcher.rb +55 -0
- data/lib/mongory/matchers/eq_matcher.rb +46 -0
- data/lib/mongory/matchers/every_matcher.rb +56 -0
- data/lib/mongory/matchers/exists_matcher.rb +53 -0
- data/lib/mongory/matchers/field_matcher.rb +147 -0
- data/lib/mongory/matchers/gt_matcher.rb +41 -0
- data/lib/mongory/matchers/gte_matcher.rb +41 -0
- data/lib/mongory/matchers/hash_condition_matcher.rb +62 -0
- data/lib/mongory/matchers/in_matcher.rb +68 -0
- data/lib/mongory/matchers/literal_matcher.rb +121 -0
- data/lib/mongory/matchers/lt_matcher.rb +41 -0
- data/lib/mongory/matchers/lte_matcher.rb +41 -0
- data/lib/mongory/matchers/ne_matcher.rb +38 -0
- data/lib/mongory/matchers/nin_matcher.rb +68 -0
- data/lib/mongory/matchers/not_matcher.rb +40 -0
- data/lib/mongory/matchers/or_matcher.rb +68 -0
- data/lib/mongory/matchers/present_matcher.rb +55 -0
- data/lib/mongory/matchers/regex_matcher.rb +80 -0
- data/lib/mongory/matchers/size_matcher.rb +54 -0
- data/lib/mongory/matchers.rb +176 -0
- data/lib/mongory/mongoid.rb +19 -0
- data/lib/mongory/query_builder.rb +257 -0
- data/lib/mongory/query_matcher.rb +93 -0
- data/lib/mongory/query_operator.rb +28 -0
- data/lib/mongory/rails.rb +15 -0
- data/lib/mongory/utils/context.rb +48 -0
- data/lib/mongory/utils/debugger.rb +125 -0
- data/lib/mongory/utils/rails_patch.rb +22 -0
- data/lib/mongory/utils/singleton_builder.rb +31 -0
- data/lib/mongory/utils.rb +76 -0
- data/lib/mongory/version.rb +5 -0
- data/lib/mongory.rb +123 -0
- data/lib/mongory_ext.so +0 -0
- data/mongory.gemspec +50 -0
- data/scripts/build_with_core.sh +292 -0
- data/sig/mongory.rbs +4 -0
- metadata +159 -0
@@ -0,0 +1,125 @@
|
|
1
|
+
#ifndef MONGORY_MATCHER_COMPOSITE_H
|
2
|
+
#define MONGORY_MATCHER_COMPOSITE_H
|
3
|
+
|
4
|
+
/**
|
5
|
+
* @file composite_matcher.h
|
6
|
+
* @brief Defines structures and constructors for composite matchers.
|
7
|
+
* This is an internal header for the matcher module.
|
8
|
+
*
|
9
|
+
* Composite matchers combine other matchers, such as logical AND/OR,
|
10
|
+
* or apply a matcher to elements of an array or fields of a table.
|
11
|
+
*/
|
12
|
+
|
13
|
+
#include "base_matcher.h"
|
14
|
+
#include "mongory-core/foundations/array.h"
|
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
|
+
|
19
|
+
/**
|
20
|
+
* @struct mongory_composite_matcher
|
21
|
+
* @brief Represents a matcher composed of other matchers.
|
22
|
+
*
|
23
|
+
* Typically has a `left` and/or `right` child matcher. The interpretation
|
24
|
+
* of these children depends on the specific composite matcher type (e.g., for
|
25
|
+
* AND/OR, both are used; for $elemMatch, `left` might be the sub-matcher for
|
26
|
+
* elements).
|
27
|
+
*/
|
28
|
+
typedef struct mongory_composite_matcher {
|
29
|
+
mongory_matcher base; /**< Base matcher structure. */
|
30
|
+
mongory_array *children; /**< Children matchers. */
|
31
|
+
} mongory_composite_matcher;
|
32
|
+
|
33
|
+
/** @name Composite Matcher Constructors
|
34
|
+
* Functions to create instances of various composite matchers.
|
35
|
+
* @{
|
36
|
+
*/
|
37
|
+
|
38
|
+
/**
|
39
|
+
* @brief Creates an "AND" ($and) matcher.
|
40
|
+
* Matches if all conditions specified in an array of condition tables are met.
|
41
|
+
* @param pool Memory pool for allocation.
|
42
|
+
* @param condition A `mongory_value` of type `MONGORY_TYPE_ARRAY`, where each
|
43
|
+
* element is a `MONGORY_TYPE_TABLE` representing a sub-condition.
|
44
|
+
* @return A new `$and` matcher, or NULL on failure or if condition is invalid.
|
45
|
+
*/
|
46
|
+
mongory_matcher *mongory_matcher_and_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx);
|
47
|
+
|
48
|
+
/**
|
49
|
+
* @brief Creates an "OR" ($or) matcher.
|
50
|
+
* Matches if any condition specified in an array of condition tables is met.
|
51
|
+
* @param pool Memory pool for allocation.
|
52
|
+
* @param condition A `mongory_value` of type `MONGORY_TYPE_ARRAY`, where each
|
53
|
+
* element is a `MONGORY_TYPE_TABLE` representing a sub-condition.
|
54
|
+
* @return A new `$or` matcher, or NULL on failure or if condition is invalid.
|
55
|
+
*/
|
56
|
+
mongory_matcher *mongory_matcher_or_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx);
|
57
|
+
|
58
|
+
/**
|
59
|
+
* @brief Creates an "element match" ($elemMatch) matcher.
|
60
|
+
* Matches an array field if at least one element in the array matches the given
|
61
|
+
* condition table.
|
62
|
+
* @param pool Memory pool for allocation.
|
63
|
+
* @param condition A `mongory_value` of type `MONGORY_TYPE_TABLE` representing
|
64
|
+
* the condition to apply to array elements.
|
65
|
+
* @return A new `$elemMatch` matcher, or NULL on failure.
|
66
|
+
*/
|
67
|
+
mongory_matcher *mongory_matcher_elem_match_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx);
|
68
|
+
|
69
|
+
/**
|
70
|
+
* @brief Creates an "every element matches" ($every) matcher.
|
71
|
+
* Matches an array field if ALL elements in the array match the given condition
|
72
|
+
* table. (Note: This is a common pattern, though MongoDB's $all has more
|
73
|
+
* complex behavior. This $every is simpler.)
|
74
|
+
* @param pool Memory pool for allocation.
|
75
|
+
* @param condition A `mongory_value` of type `MONGORY_TYPE_TABLE` representing
|
76
|
+
* the condition to apply to array elements.
|
77
|
+
* @return A new `$every` matcher, or NULL on failure.
|
78
|
+
*/
|
79
|
+
mongory_matcher *mongory_matcher_every_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx);
|
80
|
+
|
81
|
+
/**
|
82
|
+
* @brief Creates a "table condition" matcher.
|
83
|
+
* This is a core matcher that parses a condition table (similar to a MongoDB
|
84
|
+
* query document) and builds a tree of sub-matchers based on its keys and
|
85
|
+
* values. Field names imply field matchers, and `$`-prefixed keys imply
|
86
|
+
* operator matchers. These are implicitly ANDed together.
|
87
|
+
* @param pool Memory pool for allocation.
|
88
|
+
* @param condition A `mongory_value` of type `MONGORY_TYPE_TABLE`.
|
89
|
+
* @return A new table condition matcher, or NULL on failure/invalid condition.
|
90
|
+
*/
|
91
|
+
mongory_matcher *mongory_matcher_table_cond_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx);
|
92
|
+
/** @} */
|
93
|
+
|
94
|
+
/**
|
95
|
+
* @brief Allocates and initializes a base `mongory_composite_matcher`
|
96
|
+
* structure.
|
97
|
+
*
|
98
|
+
* Sets up the base `mongory_matcher` fields within the composite structure.
|
99
|
+
* Child matchers (`left`, `right`) and the specific `match` function must be
|
100
|
+
* set by the caller.
|
101
|
+
*
|
102
|
+
* @param pool Memory pool for allocation.
|
103
|
+
* @param condition The condition associated with this composite matcher (can be
|
104
|
+
* NULL if the condition is implicitly defined by children).
|
105
|
+
* @return mongory_composite_matcher* Pointer to the new composite matcher
|
106
|
+
* structure, or NULL on failure.
|
107
|
+
*/
|
108
|
+
mongory_composite_matcher *mongory_matcher_composite_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx);
|
109
|
+
|
110
|
+
/**
|
111
|
+
* @brief The actual match logic for an OR operation on a composite matcher.
|
112
|
+
*
|
113
|
+
* This function is typically assigned to the `match` field of an OR composite
|
114
|
+
* matcher. It checks if either the `left` or `right` child matcher matches the
|
115
|
+
* given value.
|
116
|
+
*
|
117
|
+
* @param matcher A pointer to the `mongory_matcher` (which is expected to be a
|
118
|
+
* `mongory_composite_matcher` for OR).
|
119
|
+
* @param value The `mongory_value` to evaluate.
|
120
|
+
* @return bool True if `left->match()` or `right->match()` returns true, false
|
121
|
+
* otherwise. Returns false if children are NULL or if their match calls fail.
|
122
|
+
*/
|
123
|
+
bool mongory_matcher_or_match(mongory_matcher *matcher, mongory_value *value);
|
124
|
+
|
125
|
+
#endif /* MONGORY_MATCHER_COMPOSITE_H */
|
@@ -0,0 +1,147 @@
|
|
1
|
+
/**
|
2
|
+
* @file existance_matcher.c
|
3
|
+
* @brief Implements $exists and $present matchers.
|
4
|
+
* This is an internal implementation file for the matcher module.
|
5
|
+
*/
|
6
|
+
#include "existance_matcher.h"
|
7
|
+
#include "base_matcher.h" // For mongory_matcher_base_new
|
8
|
+
#include "mongory-core/foundations/array.h" // For value->data.a->count
|
9
|
+
#include "mongory-core/foundations/error.h" // For mongory_error types
|
10
|
+
#include "mongory-core/foundations/table.h" // For value->data.t->count
|
11
|
+
#include "mongory-core/foundations/value.h" // For mongory_value types
|
12
|
+
#include <mongory-core.h> // General include
|
13
|
+
#include "../foundations/utils.h"
|
14
|
+
|
15
|
+
/**
|
16
|
+
* @brief Validates that the condition for an existence/presence matcher is a
|
17
|
+
* boolean.
|
18
|
+
* @param condition The `mongory_value` condition to validate.
|
19
|
+
* @return True if `condition` is not NULL and is of type `MONGORY_TYPE_BOOL`,
|
20
|
+
* false otherwise.
|
21
|
+
*/
|
22
|
+
static bool mongory_matcher_validate_bool_condition(mongory_value *condition) {
|
23
|
+
if (condition == NULL) {
|
24
|
+
return false; // Condition itself must exist.
|
25
|
+
}
|
26
|
+
if (condition->type != MONGORY_TYPE_BOOL) {
|
27
|
+
return false; // Condition must be a boolean value.
|
28
|
+
}
|
29
|
+
return true;
|
30
|
+
}
|
31
|
+
|
32
|
+
/**
|
33
|
+
* @brief Match function for the $exists matcher.
|
34
|
+
*
|
35
|
+
* Compares the existence of the input `value` (i.e., `value != NULL`)
|
36
|
+
* with the boolean `matcher->condition->data.b`.
|
37
|
+
* - If `condition` is true, matches if `value` is not NULL.
|
38
|
+
* - If `condition` is false, matches if `value` is NULL.
|
39
|
+
*
|
40
|
+
* @param matcher The $exists matcher instance. Its condition must be boolean.
|
41
|
+
* @param value The value whose existence is being checked. This is typically
|
42
|
+
* the result of a field lookup.
|
43
|
+
* @return True if the existence matches the condition, false otherwise.
|
44
|
+
*/
|
45
|
+
static inline bool mongory_matcher_exists_match(mongory_matcher *matcher, mongory_value *value) {
|
46
|
+
// The condition for $exists is a boolean (e.g., field: {$exists: true})
|
47
|
+
bool condition_expects_existence = matcher->condition->data.b;
|
48
|
+
bool actual_value_exists = (value != NULL);
|
49
|
+
|
50
|
+
return condition_expects_existence == actual_value_exists;
|
51
|
+
}
|
52
|
+
|
53
|
+
mongory_matcher *mongory_matcher_exists_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx) {
|
54
|
+
if (!mongory_matcher_validate_bool_condition(condition)) {
|
55
|
+
pool->error = MG_ALLOC_PTR(pool, mongory_error);
|
56
|
+
if (pool->error) {
|
57
|
+
pool->error->type = MONGORY_ERROR_INVALID_ARGUMENT;
|
58
|
+
pool->error->message = "$exists condition must be a boolean value.";
|
59
|
+
}
|
60
|
+
return NULL;
|
61
|
+
}
|
62
|
+
mongory_matcher *matcher = mongory_matcher_base_new(pool, condition, extern_ctx);
|
63
|
+
if (!matcher) {
|
64
|
+
return NULL;
|
65
|
+
}
|
66
|
+
matcher->match = mongory_matcher_exists_match;
|
67
|
+
matcher->original_match = mongory_matcher_exists_match;
|
68
|
+
matcher->name = mongory_string_cpy(pool, "Exists");
|
69
|
+
matcher->priority = 2.0;
|
70
|
+
return matcher;
|
71
|
+
}
|
72
|
+
|
73
|
+
/**
|
74
|
+
* @brief Match function for the $present matcher.
|
75
|
+
*
|
76
|
+
* Determines if a `value` is "present" based on its type and content,
|
77
|
+
* and compares this with the boolean `matcher->condition->data.b`.
|
78
|
+
* - NULL value: Present if condition is false.
|
79
|
+
* - Array: Present if non-empty and condition is true.
|
80
|
+
* - Table: Present if non-empty and condition is true.
|
81
|
+
* - String: Present if non-NULL, non-empty, and condition is true.
|
82
|
+
* - MONGORY_TYPE_NULL: Not present (matches if condition is false).
|
83
|
+
* - Boolean: Present if its value matches the condition.
|
84
|
+
* - Other non-NULL types: Considered present if condition is true.
|
85
|
+
*
|
86
|
+
* @param matcher The $present matcher. Its condition must be boolean.
|
87
|
+
* @param value The value to check for presence.
|
88
|
+
* @return True if the presence status matches the condition, false otherwise.
|
89
|
+
*/
|
90
|
+
static inline bool mongory_matcher_present_match(mongory_matcher *matcher, mongory_value *value) {
|
91
|
+
bool condition_expects_presence = matcher->condition->data.b;
|
92
|
+
|
93
|
+
if (value == NULL) {
|
94
|
+
// A NULL value (field does not exist) is "present" if condition_expects_presence is false.
|
95
|
+
return !condition_expects_presence;
|
96
|
+
}
|
97
|
+
|
98
|
+
bool actual_value_is_present;
|
99
|
+
switch (value->type) {
|
100
|
+
case MONGORY_TYPE_ARRAY:
|
101
|
+
actual_value_is_present = (value->data.a != NULL && value->data.a->count > 0);
|
102
|
+
break;
|
103
|
+
case MONGORY_TYPE_TABLE:
|
104
|
+
actual_value_is_present = (value->data.t != NULL && value->data.t->count > 0);
|
105
|
+
break;
|
106
|
+
case MONGORY_TYPE_STRING:
|
107
|
+
actual_value_is_present = (value->data.s != NULL && *(value->data.s) != '\0');
|
108
|
+
break;
|
109
|
+
case MONGORY_TYPE_NULL:
|
110
|
+
actual_value_is_present = false; // An explicit BSON-style Null is not "present".
|
111
|
+
break;
|
112
|
+
case MONGORY_TYPE_BOOL:
|
113
|
+
// For a boolean value, "present" means its own value matches the condition.
|
114
|
+
// e.g. {$present: true} on a true boolean is true.
|
115
|
+
// {$present: false} on a true boolean is false.
|
116
|
+
// {$present: true} on a false boolean is false.
|
117
|
+
// {$present: false} on a false boolean is true.
|
118
|
+
return value->data.b == condition_expects_presence;
|
119
|
+
default:
|
120
|
+
// For other types (int, double, pointer, regex, unsupported), if they are
|
121
|
+
// not NULL (checked above), they are considered "present".
|
122
|
+
actual_value_is_present = true;
|
123
|
+
break;
|
124
|
+
}
|
125
|
+
|
126
|
+
return condition_expects_presence == actual_value_is_present;
|
127
|
+
}
|
128
|
+
|
129
|
+
mongory_matcher *mongory_matcher_present_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx) {
|
130
|
+
if (!mongory_matcher_validate_bool_condition(condition)) {
|
131
|
+
pool->error = MG_ALLOC_PTR(pool, mongory_error);
|
132
|
+
if (pool->error) {
|
133
|
+
pool->error->type = MONGORY_ERROR_INVALID_ARGUMENT;
|
134
|
+
pool->error->message = "$present condition must be a boolean value.";
|
135
|
+
}
|
136
|
+
return NULL;
|
137
|
+
}
|
138
|
+
mongory_matcher *matcher = mongory_matcher_base_new(pool, condition, extern_ctx);
|
139
|
+
if (!matcher) {
|
140
|
+
return NULL;
|
141
|
+
}
|
142
|
+
matcher->match = mongory_matcher_present_match;
|
143
|
+
matcher->original_match = mongory_matcher_present_match;
|
144
|
+
matcher->name = mongory_string_cpy(pool, "Present");
|
145
|
+
matcher->priority = 2.0;
|
146
|
+
return matcher;
|
147
|
+
}
|
@@ -0,0 +1,48 @@
|
|
1
|
+
#ifndef MONGORY_MATCHER_EXISTANCE_H
|
2
|
+
#define MONGORY_MATCHER_EXISTANCE_H
|
3
|
+
|
4
|
+
/**
|
5
|
+
* @file existance_matcher.h
|
6
|
+
* @brief Defines constructors for existence and presence matchers ($exists,
|
7
|
+
* $present). This is an internal header for the matcher module.
|
8
|
+
*/
|
9
|
+
|
10
|
+
#include "base_matcher.h"
|
11
|
+
#include "mongory-core/foundations/memory_pool.h"
|
12
|
+
#include "mongory-core/foundations/value.h"
|
13
|
+
#include "mongory-core/matchers/matcher.h" // For mongory_matcher structure
|
14
|
+
|
15
|
+
/**
|
16
|
+
* @brief Creates an "exists" ($exists) matcher.
|
17
|
+
*
|
18
|
+
* This matcher checks for the existence of a field (i.e., if a value is
|
19
|
+
* non-NULL when retrieved from a table or array). The `condition` for this
|
20
|
+
* matcher must be a boolean `mongory_value`.
|
21
|
+
* - If `condition` is true, it matches if the field exists (value is not NULL).
|
22
|
+
* - If `condition` is false, it matches if the field does not exist (value is
|
23
|
+
* NULL).
|
24
|
+
*
|
25
|
+
* @param pool Memory pool for allocation.
|
26
|
+
* @param condition A `mongory_value` of type `MONGORY_TYPE_BOOL`.
|
27
|
+
* @return A new `$exists` matcher, or NULL on failure or invalid condition.
|
28
|
+
*/
|
29
|
+
mongory_matcher *mongory_matcher_exists_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx);
|
30
|
+
|
31
|
+
/**
|
32
|
+
* @brief Creates a "present" ($present) matcher.
|
33
|
+
*
|
34
|
+
* This matcher provides a more nuanced check than `$exists`. It considers a
|
35
|
+
* value "present" based on its type and content (e.g., non-empty array/table,
|
36
|
+
* non-empty string). The `condition` for this matcher must be a boolean
|
37
|
+
* `mongory_value`.
|
38
|
+
* - If `condition` is true, it matches if the value is considered "present".
|
39
|
+
* - If `condition` is false, it matches if the value is not "present" (e.g.,
|
40
|
+
* NULL, empty array/table/string).
|
41
|
+
*
|
42
|
+
* @param pool Memory pool for allocation.
|
43
|
+
* @param condition A `mongory_value` of type `MONGORY_TYPE_BOOL`.
|
44
|
+
* @return A new `$present` matcher, or NULL on failure or invalid condition.
|
45
|
+
*/
|
46
|
+
mongory_matcher *mongory_matcher_present_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx);
|
47
|
+
|
48
|
+
#endif /* MONGORY_MATCHER_EXISTANCE_H */
|
@@ -0,0 +1,124 @@
|
|
1
|
+
/**
|
2
|
+
* @file external_matcher.c
|
3
|
+
* @brief Implements the $regex matcher.
|
4
|
+
* This is an internal implementation file for the matcher module.
|
5
|
+
*/
|
6
|
+
#include "external_matcher.h"
|
7
|
+
#include "../foundations/config_private.h" // For mongory_internal_regex_adapter
|
8
|
+
#include "base_matcher.h" // For mongory_matcher_base_new
|
9
|
+
#include "mongory-core/foundations/config.h"
|
10
|
+
#include "../foundations/utils.h" // For mongory_string_cpy
|
11
|
+
#include "mongory-core/foundations/error.h" // For MONGORY_ERROR_INVALID_ARGUMENT
|
12
|
+
#include "mongory-core/foundations/memory_pool.h"
|
13
|
+
#include "mongory-core/foundations/value.h"
|
14
|
+
#include "matcher_explainable.h"
|
15
|
+
#include "matcher_traversable.h"
|
16
|
+
|
17
|
+
/**
|
18
|
+
* @brief Match function for the $regex matcher.
|
19
|
+
*
|
20
|
+
* Checks if the input `value` (which must be a string) matches the regex
|
21
|
+
* pattern stored in `matcher->condition`. The actual regex matching is
|
22
|
+
* performed by the function pointed to by
|
23
|
+
* `mongory_internal_regex_adapter->match_func`.
|
24
|
+
*
|
25
|
+
* @param matcher The $regex matcher instance.
|
26
|
+
* @param value The `mongory_value` to test; must be of type
|
27
|
+
* `MONGORY_TYPE_STRING`.
|
28
|
+
* @return True if the string value matches the regex, false otherwise or if
|
29
|
+
* input is not a string.
|
30
|
+
*/
|
31
|
+
static inline bool mongory_matcher_regex_match(mongory_matcher *matcher, mongory_value *value) {
|
32
|
+
if (!value || value->type != MONGORY_TYPE_STRING) {
|
33
|
+
return false; // Regex matching applies only to strings.
|
34
|
+
}
|
35
|
+
if (!mongory_internal_regex_adapter.match_func) {
|
36
|
+
return false; // Regex adapter or function not configured.
|
37
|
+
}
|
38
|
+
|
39
|
+
// Delegate to the configured regex function.
|
40
|
+
return mongory_internal_regex_adapter.match_func(matcher->pool, matcher->condition, value);
|
41
|
+
}
|
42
|
+
|
43
|
+
/**
|
44
|
+
* @brief Validates that the condition for a $regex matcher is valid.
|
45
|
+
* The condition must be non-NULL and either a `MONGORY_TYPE_STRING` (pattern)
|
46
|
+
* or `MONGORY_TYPE_REGEX` (pre-compiled regex object).
|
47
|
+
* @param condition The `mongory_value` condition to validate.
|
48
|
+
* @return True if the condition is valid for a regex matcher, false otherwise.
|
49
|
+
*/
|
50
|
+
static inline bool mongory_matcher_regex_condition_validate(mongory_value *condition) {
|
51
|
+
return condition != NULL && (condition->type == MONGORY_TYPE_STRING || condition->type == MONGORY_TYPE_REGEX);
|
52
|
+
}
|
53
|
+
|
54
|
+
mongory_matcher *mongory_matcher_regex_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx) {
|
55
|
+
if (!mongory_matcher_regex_condition_validate(condition)) {
|
56
|
+
pool->error = MG_ALLOC_PTR(pool, mongory_error);
|
57
|
+
if (pool->error) {
|
58
|
+
pool->error->type = MONGORY_ERROR_INVALID_ARGUMENT;
|
59
|
+
pool->error->message = "$regex condition must be a string or a regex object.";
|
60
|
+
}
|
61
|
+
return NULL;
|
62
|
+
}
|
63
|
+
|
64
|
+
mongory_matcher *matcher = mongory_matcher_base_new(pool, condition, extern_ctx);
|
65
|
+
if (!matcher) {
|
66
|
+
return NULL;
|
67
|
+
}
|
68
|
+
matcher->match = mongory_matcher_regex_match;
|
69
|
+
matcher->original_match = mongory_matcher_regex_match;
|
70
|
+
matcher->name = mongory_string_cpy(pool, "Regex");
|
71
|
+
matcher->priority = 20.0;
|
72
|
+
return matcher;
|
73
|
+
}
|
74
|
+
|
75
|
+
typedef struct mongory_custom_matcher {
|
76
|
+
mongory_matcher base;
|
77
|
+
void *external_matcher;
|
78
|
+
} mongory_custom_matcher;
|
79
|
+
|
80
|
+
/**
|
81
|
+
* @brief The match function for a custom matcher.
|
82
|
+
* @param matcher The matcher to match against.
|
83
|
+
* @param value The value to match.
|
84
|
+
* @return True if the value matches the matcher, false otherwise.
|
85
|
+
*/
|
86
|
+
bool mongory_matcher_custom_match(mongory_matcher *matcher, mongory_value *value) {
|
87
|
+
if (mongory_custom_matcher_adapter.match == NULL) {
|
88
|
+
return false; // Custom matcher adapter not initialized.
|
89
|
+
}
|
90
|
+
mongory_custom_matcher *custom_matcher = (mongory_custom_matcher *)matcher;
|
91
|
+
return mongory_custom_matcher_adapter.match(custom_matcher->external_matcher, value);
|
92
|
+
}
|
93
|
+
|
94
|
+
/**
|
95
|
+
* @brief Creates a new custom matcher instance.
|
96
|
+
*
|
97
|
+
* @param pool The memory pool to use for the matcher's allocations.
|
98
|
+
* @param key The key for the custom matcher.
|
99
|
+
* @param condition The `mongory_value` representing the condition for this
|
100
|
+
* matcher.
|
101
|
+
* @return mongory_matcher* A pointer to the newly created custom matcher, or
|
102
|
+
* NULL on failure.
|
103
|
+
*/
|
104
|
+
mongory_matcher *mongory_matcher_custom_new(mongory_memory_pool *pool, char *key, mongory_value *condition, void *extern_ctx) {
|
105
|
+
if (mongory_custom_matcher_adapter.build == NULL)
|
106
|
+
return NULL; // Custom matcher adapter not initialized.
|
107
|
+
mongory_custom_matcher *matcher = MG_ALLOC_PTR(pool, mongory_custom_matcher);
|
108
|
+
if (matcher == NULL)
|
109
|
+
return NULL;
|
110
|
+
mongory_matcher_custom_context *context = mongory_custom_matcher_adapter.build(key, condition, extern_ctx);
|
111
|
+
if (context == NULL)
|
112
|
+
return NULL;
|
113
|
+
matcher->base.pool = pool;
|
114
|
+
matcher->base.condition = condition;
|
115
|
+
matcher->base.name = context->name;
|
116
|
+
matcher->base.match = mongory_matcher_custom_match;
|
117
|
+
matcher->base.original_match = mongory_matcher_custom_match;
|
118
|
+
matcher->base.explain = mongory_matcher_base_explain;
|
119
|
+
matcher->base.traverse = mongory_matcher_leaf_traverse;
|
120
|
+
matcher->base.extern_ctx = extern_ctx;
|
121
|
+
matcher->external_matcher = context->external_matcher;
|
122
|
+
matcher->base.priority = 20.0;
|
123
|
+
return (mongory_matcher *)matcher;
|
124
|
+
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
#ifndef MONGORY_MATCHER_EXTERNAL_H
|
2
|
+
#define MONGORY_MATCHER_EXTERNAL_H
|
3
|
+
|
4
|
+
/**
|
5
|
+
* @file external_matcher.h
|
6
|
+
* @brief Defines the constructor for matchers that are not built-in.
|
7
|
+
* This is an internal header for the matcher module.
|
8
|
+
*/
|
9
|
+
|
10
|
+
#include "base_matcher.h"
|
11
|
+
#include "mongory-core/foundations/memory_pool.h"
|
12
|
+
#include "mongory-core/foundations/value.h"
|
13
|
+
#include "mongory-core/matchers/matcher.h" // For mongory_matcher structure
|
14
|
+
|
15
|
+
/**
|
16
|
+
* @brief Creates a regular expression ($regex) matcher.
|
17
|
+
*
|
18
|
+
* This matcher tests if an input string `mongory_value` matches a given regular
|
19
|
+
* expression. The regular expression itself is provided in the `condition`
|
20
|
+
* value, which can be either a `MONGORY_TYPE_STRING` (the pattern) or a
|
21
|
+
* `MONGORY_TYPE_REGEX` (a pre-compiled regex object, if the underlying regex
|
22
|
+
* engine supports it and it's wrapped). The actual regex matching logic is
|
23
|
+
* delegated to a function provided via `mongory_regex_func_set` (see
|
24
|
+
* `foundations/config.h`).
|
25
|
+
*
|
26
|
+
* @param pool Memory pool for allocation.
|
27
|
+
* @param condition A `mongory_value` representing the regex pattern. This
|
28
|
+
* should be of type `MONGORY_TYPE_STRING` or `MONGORY_TYPE_REGEX`.
|
29
|
+
* @return A new $regex matcher, or NULL on failure or if the condition is
|
30
|
+
* invalid.
|
31
|
+
*/
|
32
|
+
mongory_matcher *mongory_matcher_regex_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx);
|
33
|
+
|
34
|
+
/**
|
35
|
+
* @brief Creates a new custom matcher instance.
|
36
|
+
*
|
37
|
+
* @param pool The memory pool to use for the matcher's allocations.
|
38
|
+
* @param key The key for the custom matcher.
|
39
|
+
* @param condition The `mongory_value` representing the condition for this
|
40
|
+
* matcher.
|
41
|
+
* @return mongory_matcher* A pointer to the newly created custom matcher, or
|
42
|
+
* NULL on failure.
|
43
|
+
*/
|
44
|
+
mongory_matcher *mongory_matcher_custom_new(mongory_memory_pool *pool, char *key, mongory_value *condition, void *extern_ctx);
|
45
|
+
|
46
|
+
#endif /* MONGORY_MATCHER_EXTERNAL_H */
|
@@ -0,0 +1,126 @@
|
|
1
|
+
/**
|
2
|
+
* @file inclusion_matcher.c
|
3
|
+
* @brief Implements $in and $nin matchers for checking value inclusion in an
|
4
|
+
* array. This is an internal implementation file for the matcher module.
|
5
|
+
*/
|
6
|
+
#include "inclusion_matcher.h"
|
7
|
+
#include "base_matcher.h" // For mongory_matcher_base_new
|
8
|
+
#include "../foundations/array_private.h" // For mongory_array_includes
|
9
|
+
#include "mongory-core/foundations/array.h" // For mongory_array operations
|
10
|
+
#include "mongory-core/foundations/error.h" // For mongory_error
|
11
|
+
#include "mongory-core/foundations/value.h" // For mongory_value
|
12
|
+
#include <mongory-core.h> // General include
|
13
|
+
#include "../foundations/utils.h" // For mongory_string_cpy
|
14
|
+
|
15
|
+
/**
|
16
|
+
* @brief Validates that the condition for an inclusion matcher is a valid
|
17
|
+
* array.
|
18
|
+
* @param condition The `mongory_value` condition to validate.
|
19
|
+
* @return True if `condition` is not NULL, is of type `MONGORY_TYPE_ARRAY`,
|
20
|
+
* and its internal array data `condition->data.a` is not NULL. False otherwise.
|
21
|
+
*/
|
22
|
+
static inline bool mongory_matcher_validate_array_condition(mongory_value *condition) {
|
23
|
+
if (condition == NULL) {
|
24
|
+
return false; // Condition must exist.
|
25
|
+
}
|
26
|
+
if (condition->type != MONGORY_TYPE_ARRAY) {
|
27
|
+
return false; // Condition must be an array.
|
28
|
+
}
|
29
|
+
if (condition->data.a == NULL) {
|
30
|
+
return false; // The array data within the condition must be valid.
|
31
|
+
}
|
32
|
+
return true;
|
33
|
+
}
|
34
|
+
|
35
|
+
/**
|
36
|
+
* @brief Match function for the $in matcher.
|
37
|
+
*
|
38
|
+
* If `value_to_check` is a scalar, it checks if `value_to_check` is present in
|
39
|
+
* `matcher->condition` (which must be an array).
|
40
|
+
* If `value_to_check` is an array, it checks if any element of `value_to_check`
|
41
|
+
* is present in `matcher->condition` (array intersection).
|
42
|
+
*
|
43
|
+
* @param matcher The $in matcher instance.
|
44
|
+
* @param value_to_check The value to check for inclusion.
|
45
|
+
* @return True if `value_to_check` (or one of its elements) is found in the
|
46
|
+
* condition array, false otherwise.
|
47
|
+
*/
|
48
|
+
static inline bool mongory_matcher_in_match(mongory_matcher *matcher, mongory_value *value_to_check) {
|
49
|
+
if (!value_to_check || !matcher->condition || !matcher->condition->data.a) {
|
50
|
+
// Invalid inputs or condition is not a proper array.
|
51
|
+
return false;
|
52
|
+
}
|
53
|
+
|
54
|
+
mongory_array *condition_array = matcher->condition->data.a;
|
55
|
+
|
56
|
+
if (value_to_check->type != MONGORY_TYPE_ARRAY) {
|
57
|
+
return mongory_array_includes(condition_array, value_to_check);
|
58
|
+
}
|
59
|
+
|
60
|
+
mongory_array *input_array = value_to_check->data.a;
|
61
|
+
if (!input_array) {
|
62
|
+
return false;
|
63
|
+
}
|
64
|
+
|
65
|
+
for (size_t i = 0; i < input_array->count; i++) {
|
66
|
+
mongory_value *input_item = input_array->get(input_array, i);
|
67
|
+
if (mongory_array_includes(condition_array, input_item)) {
|
68
|
+
return true;
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
return false;
|
73
|
+
}
|
74
|
+
|
75
|
+
mongory_matcher *mongory_matcher_in_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx) {
|
76
|
+
if (!mongory_matcher_validate_array_condition(condition)) {
|
77
|
+
pool->error = MG_ALLOC_PTR(pool, mongory_error);
|
78
|
+
if (pool->error) {
|
79
|
+
pool->error->type = MONGORY_ERROR_INVALID_ARGUMENT;
|
80
|
+
pool->error->message = "$in condition must be a valid array.";
|
81
|
+
}
|
82
|
+
return NULL;
|
83
|
+
}
|
84
|
+
mongory_matcher *matcher = mongory_matcher_base_new(pool, condition, extern_ctx);
|
85
|
+
if (!matcher) {
|
86
|
+
return NULL;
|
87
|
+
}
|
88
|
+
matcher->match = mongory_matcher_in_match;
|
89
|
+
matcher->original_match = mongory_matcher_in_match;
|
90
|
+
matcher->name = mongory_string_cpy(pool, "In");
|
91
|
+
matcher->priority = 1.0 + mongory_log((double)condition->data.a->count + 1.0, 1.5);
|
92
|
+
return matcher;
|
93
|
+
}
|
94
|
+
|
95
|
+
/**
|
96
|
+
* @brief Match function for the $nin (not in) matcher.
|
97
|
+
* Simply negates the result of the $in logic.
|
98
|
+
* @param matcher The $nin matcher instance.
|
99
|
+
* @param value The value to check.
|
100
|
+
* @return True if the value is NOT found according to $in logic, false
|
101
|
+
* otherwise.
|
102
|
+
*/
|
103
|
+
static inline bool mongory_matcher_not_in_match(mongory_matcher *matcher, mongory_value *value) {
|
104
|
+
// $nin is true if $in is false.
|
105
|
+
return !mongory_matcher_in_match(matcher, value);
|
106
|
+
}
|
107
|
+
|
108
|
+
mongory_matcher *mongory_matcher_not_in_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx) {
|
109
|
+
if (!mongory_matcher_validate_array_condition(condition)) {
|
110
|
+
pool->error = MG_ALLOC_PTR(pool, mongory_error);
|
111
|
+
if (pool->error) {
|
112
|
+
pool->error->type = MONGORY_ERROR_INVALID_ARGUMENT;
|
113
|
+
pool->error->message = "$nin condition must be a valid array.";
|
114
|
+
}
|
115
|
+
return NULL;
|
116
|
+
}
|
117
|
+
mongory_matcher *matcher = mongory_matcher_base_new(pool, condition, extern_ctx);
|
118
|
+
if (!matcher) {
|
119
|
+
return NULL;
|
120
|
+
}
|
121
|
+
matcher->match = mongory_matcher_not_in_match;
|
122
|
+
matcher->original_match = mongory_matcher_not_in_match;
|
123
|
+
matcher->name = mongory_string_cpy(pool, "Nin");
|
124
|
+
matcher->priority = 1.0 + mongory_log((double)condition->data.a->count + 1.0, 1.5);
|
125
|
+
return matcher;
|
126
|
+
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
#ifndef MONGORY_MATCHER_INCLUSION_H
|
2
|
+
#define MONGORY_MATCHER_INCLUSION_H
|
3
|
+
|
4
|
+
/**
|
5
|
+
* @file inclusion_matcher.h
|
6
|
+
* @brief Defines constructors for inclusion matchers ($in, $nin).
|
7
|
+
* This is an internal header for the matcher module.
|
8
|
+
*
|
9
|
+
* These matchers check if a value is present or not present in a given array
|
10
|
+
* of values.
|
11
|
+
*/
|
12
|
+
|
13
|
+
#include "base_matcher.h"
|
14
|
+
#include "mongory-core/foundations/memory_pool.h"
|
15
|
+
#include "mongory-core/foundations/value.h"
|
16
|
+
#include "mongory-core/matchers/matcher.h" // For mongory_matcher structure
|
17
|
+
|
18
|
+
/**
|
19
|
+
* @brief Creates an "in" ($in) matcher.
|
20
|
+
*
|
21
|
+
* Matches if the input value is equal to any of the values in the `condition`
|
22
|
+
* array. If the input value itself is an array, it matches if any element of
|
23
|
+
* the input array is found in the `condition` array (set intersection).
|
24
|
+
*
|
25
|
+
* @param pool Memory pool for allocation.
|
26
|
+
* @param condition A `mongory_value` of type `MONGORY_TYPE_ARRAY` containing
|
27
|
+
* the set of values to check against.
|
28
|
+
* @return A new `$in` matcher, or NULL on failure or invalid condition.
|
29
|
+
*/
|
30
|
+
mongory_matcher *mongory_matcher_in_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx);
|
31
|
+
|
32
|
+
/**
|
33
|
+
* @brief Creates a "not in" ($nin) matcher.
|
34
|
+
*
|
35
|
+
* Matches if the input value is not equal to any of the values in the
|
36
|
+
* `condition` array. If the input value itself is an array, it matches if no
|
37
|
+
* element of the input array is found in the `condition` array.
|
38
|
+
*
|
39
|
+
* @param pool Memory pool for allocation.
|
40
|
+
* @param condition A `mongory_value` of type `MONGORY_TYPE_ARRAY` containing
|
41
|
+
* the set of values to check against.
|
42
|
+
* @return A new `$nin` matcher, or NULL on failure or invalid condition.
|
43
|
+
*/
|
44
|
+
mongory_matcher *mongory_matcher_not_in_new(mongory_memory_pool *pool, mongory_value *condition, void *extern_ctx);
|
45
|
+
|
46
|
+
#endif /* MONGORY_MATCHER_INCLUSION_H */
|