bsonsearch 2.1.2__cp314-cp314-musllinux_1_2_x86_64.whl
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 bsonsearch might be problematic. Click here for more details.
- bsonsearch/__init__.py +191 -0
- bsonsearch/matcher_ext/matcher_module.c +551 -0
- bsonsearch/matcher_module.cpython-314-x86_64-linux-musl.so +0 -0
- bsonsearch-2.1.2.dist-info/METADATA +9 -0
- bsonsearch-2.1.2.dist-info/RECORD +14 -0
- bsonsearch-2.1.2.dist-info/WHEEL +5 -0
- bsonsearch-2.1.2.dist-info/licenses/LICENSE +21 -0
- bsonsearch-2.1.2.dist-info/top_level.txt +1 -0
- bsonsearch.libs/libbson2-aa5f0313.so.2.1.2 +0 -0
- bsonsearch.libs/libbsonsearch-b4c2d01c.so +0 -0
- bsonsearch.libs/libcmph-7e8d51a6.so.0.0.0 +0 -0
- bsonsearch.libs/libdiscodb-6058085b.so +0 -0
- bsonsearch.libs/libduktape-2bef3d5d.so.207.20700 +0 -0
- bsonsearch.libs/libpcre-77987b86.so.1.2.13 +0 -0
bsonsearch/__init__.py
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"""
|
|
2
|
+
wrapper for bsonsearch
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .matcher_module import Matcher, Document, Utils
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
import yara
|
|
10
|
+
import io
|
|
11
|
+
import bson
|
|
12
|
+
|
|
13
|
+
def YARA_DICT(compiled_rule):
|
|
14
|
+
compiled_binary_rule = io.BytesIO()
|
|
15
|
+
compiled_rule.save(file=compiled_binary_rule)
|
|
16
|
+
return {"$yara":bson.Binary(compiled_binary_rule.getvalue())}
|
|
17
|
+
|
|
18
|
+
def YARA_LOAD(fn):
|
|
19
|
+
compiled_rule = yara.load(fn)
|
|
20
|
+
return YARA_DICT(compiled_rule)
|
|
21
|
+
|
|
22
|
+
def YARA_COMPILE(fn):
|
|
23
|
+
compiled_rule = yara.compile(fn)
|
|
24
|
+
return YARA_DICT(compiled_rule)
|
|
25
|
+
|
|
26
|
+
def YARA_COMPILE_STR(source):
|
|
27
|
+
compiled_rule = yara.compile(source=source)
|
|
28
|
+
return YARA_DICT(compiled_rule)
|
|
29
|
+
|
|
30
|
+
def YARA_SOURCE_STR(source):
|
|
31
|
+
assert isinstance(source, bytes)
|
|
32
|
+
return {"$yara": {"source": source}}
|
|
33
|
+
|
|
34
|
+
except ImportError:
|
|
35
|
+
yara = None
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
import discodb
|
|
40
|
+
import bson
|
|
41
|
+
DISCO_VALUE_ONLY = "$valueonly"
|
|
42
|
+
DISCO_KEY_EXISTS = "$keyexists"
|
|
43
|
+
DISCO_VALUE_IS = "$valueis"
|
|
44
|
+
DISCO_CNF_QUERY = "$Q"
|
|
45
|
+
DISCO_DDB_FILE = "$ddb"
|
|
46
|
+
|
|
47
|
+
def DISCO_VALUE_IS_CONFIG(**kwargs):
|
|
48
|
+
spec = {
|
|
49
|
+
kwargs["ns"]: {
|
|
50
|
+
"$module": {
|
|
51
|
+
"name": "disco",
|
|
52
|
+
"config": {
|
|
53
|
+
DISCO_VALUE_IS: kwargs['value'],
|
|
54
|
+
DISCO_DDB_FILE: kwargs["ddb"]
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return spec
|
|
60
|
+
|
|
61
|
+
def DISCO_VALUE_ONLY_CONFIG(**kwargs):
|
|
62
|
+
spec = {
|
|
63
|
+
kwargs["ns"]: {
|
|
64
|
+
"$module": {
|
|
65
|
+
"name": "disco",
|
|
66
|
+
"config": {
|
|
67
|
+
DISCO_VALUE_ONLY: kwargs['value'],
|
|
68
|
+
DISCO_DDB_FILE: kwargs["ddb"]
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return spec
|
|
74
|
+
|
|
75
|
+
def DISCO_KEY_EXISTS_CONFIG(**kwargs):
|
|
76
|
+
spec = {
|
|
77
|
+
kwargs["ns"]: {
|
|
78
|
+
"$module": {
|
|
79
|
+
"name": "disco",
|
|
80
|
+
"config": {
|
|
81
|
+
DISCO_KEY_EXISTS: 0,
|
|
82
|
+
DISCO_DDB_FILE: kwargs["ddb"]
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return spec
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def DISCO_QUERY_CONFIG(**kwargs):
|
|
91
|
+
config = bson.son.SON()
|
|
92
|
+
config['$ddb'] = kwargs["ddb"]
|
|
93
|
+
config[DISCO_CNF_QUERY] = discodb.Q.parse(kwargs["cnf"]).deploy()
|
|
94
|
+
config['precache'] = kwargs.get("precache", False)
|
|
95
|
+
spec = {
|
|
96
|
+
kwargs["ns"]: {
|
|
97
|
+
"$module": {
|
|
98
|
+
"name": "disco",
|
|
99
|
+
"config": config
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return spec
|
|
104
|
+
|
|
105
|
+
def DISCODB_CNF_TO_DICT(cnf_string):
|
|
106
|
+
return discodb.Q.parse(cnf_string).deploy()
|
|
107
|
+
except ImportError:
|
|
108
|
+
discodb = None
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
import IPy
|
|
113
|
+
import struct
|
|
114
|
+
from bson.binary import Binary
|
|
115
|
+
def pack_ip(ip_string):
|
|
116
|
+
'''
|
|
117
|
+
|
|
118
|
+
:param ip_string: String representation of ipv4 or ipv6 address ("127.0.0.1" or "::1"
|
|
119
|
+
:return: Binary encapsulated and packed 16 byte integer
|
|
120
|
+
'''
|
|
121
|
+
ip = IPy.IP(ip_string)
|
|
122
|
+
ip_int = ip.int()
|
|
123
|
+
ip_bin = Binary(struct.pack(">QQ", ip_int/(2**64), ip_int%(2**64)), 0x80+ip.version())
|
|
124
|
+
return ip_bin
|
|
125
|
+
|
|
126
|
+
def ip_inrange_query(namespace, ip_string, netmask):
|
|
127
|
+
"""
|
|
128
|
+
builds the $inIPRange
|
|
129
|
+
:param namespace:
|
|
130
|
+
:param ip_string:
|
|
131
|
+
:param netmask:
|
|
132
|
+
:return:
|
|
133
|
+
"""
|
|
134
|
+
assert namespace
|
|
135
|
+
ip_bin = pack_ip(ip_string)
|
|
136
|
+
nm_bin = pack_ip(netmask)
|
|
137
|
+
assert ip_bin.subtype == nm_bin.subtype
|
|
138
|
+
return {namespace: {"$inIPrange": [ip_bin, nm_bin]}}
|
|
139
|
+
|
|
140
|
+
def ip_inrangeset_query(namespace, list_of_ip_netmask_tuples):
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
:param namespace:
|
|
144
|
+
:param list_of_ip_netmask_tuples: [(ip1,mask1), (ip2,mask2)...]
|
|
145
|
+
:return:dict
|
|
146
|
+
"""
|
|
147
|
+
setlist = []
|
|
148
|
+
assert namespace
|
|
149
|
+
for ip_string, netmask in list_of_ip_netmask_tuples:
|
|
150
|
+
ip_bin = pack_ip(ip_string)
|
|
151
|
+
nm_bin = pack_ip(netmask)
|
|
152
|
+
setlist.append([ip_bin, nm_bin])
|
|
153
|
+
assert ip_bin.subtype == nm_bin.subtype
|
|
154
|
+
return {namespace: {"$inIPrangeset": setlist}}
|
|
155
|
+
except ImportError:
|
|
156
|
+
pack_ip = None
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
# list_of_tuples = unroll("", [], highly_embedded_dict)
|
|
161
|
+
def unroll(current_key, output_map, entry, keys_to_append=None):
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
:param current_key:
|
|
165
|
+
:param output_map:
|
|
166
|
+
:param entry:
|
|
167
|
+
:param keys_to_append:
|
|
168
|
+
:return:
|
|
169
|
+
"""
|
|
170
|
+
def unroll_dict(current_key, output_map, entry, keys_to_append=None):
|
|
171
|
+
for key, value in entry.items():
|
|
172
|
+
unroll(".".join([current_key, key]).lstrip("."),
|
|
173
|
+
output_map,
|
|
174
|
+
value,
|
|
175
|
+
keys_to_append=keys_to_append)
|
|
176
|
+
|
|
177
|
+
def unroll_list(current_key, output_map, entry, keys_to_append=None):
|
|
178
|
+
for item in entry:
|
|
179
|
+
unroll(current_key,
|
|
180
|
+
output_map,
|
|
181
|
+
item,
|
|
182
|
+
keys_to_append=keys_to_append)
|
|
183
|
+
|
|
184
|
+
if isinstance(entry, dict):
|
|
185
|
+
unroll_dict(current_key, output_map, entry, keys_to_append=keys_to_append)
|
|
186
|
+
elif isinstance(entry, list):
|
|
187
|
+
unroll_list(current_key, output_map, entry, keys_to_append=keys_to_append)
|
|
188
|
+
else: # not iterable
|
|
189
|
+
if not keys_to_append or current_key in keys_to_append:
|
|
190
|
+
output_map.append((current_key, entry))
|
|
191
|
+
return output_map
|
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
#define WITH_MODULES
|
|
2
|
+
|
|
3
|
+
//The modules we know to be enabled from the build
|
|
4
|
+
#define WITH_DUKJS
|
|
5
|
+
#define WITH_DISCO
|
|
6
|
+
#define WITH_MATH
|
|
7
|
+
|
|
8
|
+
#define WITH_UTILS
|
|
9
|
+
#define WITH_PROJECTION
|
|
10
|
+
#define ALLOW_FILESYSTEM
|
|
11
|
+
#define WITH_CONDITIONAL
|
|
12
|
+
|
|
13
|
+
#define PY_SSIZE_T_CLEAN
|
|
14
|
+
#include <Python.h>
|
|
15
|
+
#include "bsoncompare.h"
|
|
16
|
+
#include "mongoc-matcher-private.h"
|
|
17
|
+
#include "matcher-module-duk.h"
|
|
18
|
+
|
|
19
|
+
typedef struct {
|
|
20
|
+
PyObject_HEAD
|
|
21
|
+
Py_ssize_t value;
|
|
22
|
+
} Utils;
|
|
23
|
+
|
|
24
|
+
typedef struct {
|
|
25
|
+
PyObject_HEAD
|
|
26
|
+
mongoc_matcher_t *matcher;
|
|
27
|
+
const char *json;
|
|
28
|
+
Py_ssize_t value;
|
|
29
|
+
} Matcher;
|
|
30
|
+
|
|
31
|
+
typedef struct {
|
|
32
|
+
PyObject_HEAD
|
|
33
|
+
bson_t *document;
|
|
34
|
+
const char *json;
|
|
35
|
+
Py_ssize_t value;
|
|
36
|
+
} Document;
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
// ---- UTILS FUNCTIONS ----
|
|
40
|
+
static PyObject *
|
|
41
|
+
Utils_startup(Utils *self, PyObject *args, PyObject *kwds)
|
|
42
|
+
{
|
|
43
|
+
int result = bsonsearch_startup();
|
|
44
|
+
return PyLong_FromLong(result);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
static PyObject *
|
|
48
|
+
Utils_shutdown(Utils *self, PyObject *args, PyObject *kwds)
|
|
49
|
+
{
|
|
50
|
+
int result = bsonsearch_shutdown();
|
|
51
|
+
return PyLong_FromLong(result);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
static PyObject *
|
|
55
|
+
Utils_regex_destroy(Utils *self, PyObject *args, PyObject *kwds)
|
|
56
|
+
{
|
|
57
|
+
int result = regex_destroy();
|
|
58
|
+
return PyLong_FromLong(result);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
static PyObject *
|
|
62
|
+
Utils_to_bson(Utils *self, PyObject *args, PyObject *kwds)
|
|
63
|
+
{
|
|
64
|
+
const char * json = NULL;
|
|
65
|
+
Py_ssize_t json_len;
|
|
66
|
+
if (!PyArg_ParseTuple(args, "s#", &json, &json_len)) {
|
|
67
|
+
return NULL;
|
|
68
|
+
}
|
|
69
|
+
bson_t *bson_object = generate_doc_from_json((const uint8_t*)json, json_len);
|
|
70
|
+
const uint8_t *doc_bson = bson_get_data(bson_object);
|
|
71
|
+
|
|
72
|
+
PyObject * result = Py_BuildValue("y#", doc_bson, bson_object->len);
|
|
73
|
+
bson_destroy(bson_object);
|
|
74
|
+
bson_free((void *)doc_bson);
|
|
75
|
+
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
static PyObject *
|
|
80
|
+
Utils_haversine_distance(Utils *self, PyObject *args, PyObject *kwds)
|
|
81
|
+
{
|
|
82
|
+
double lon1;
|
|
83
|
+
double lat1;
|
|
84
|
+
double lon2;
|
|
85
|
+
double lat2;
|
|
86
|
+
if (!PyArg_ParseTuple(args, "dddd", &lon1, &lat1, &lon2, &lat2)) {
|
|
87
|
+
return NULL; // Error occurred, exception already set
|
|
88
|
+
}
|
|
89
|
+
double result = bsonsearch_haversine_distance(
|
|
90
|
+
lon1, lat1, lon2, lat2
|
|
91
|
+
);
|
|
92
|
+
return PyFloat_FromDouble(result);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
static PyObject *
|
|
97
|
+
Utils_haversine_distance_degrees(Utils *self, PyObject *args, PyObject *kwds)
|
|
98
|
+
{
|
|
99
|
+
double lon1;
|
|
100
|
+
double lat1;
|
|
101
|
+
double lon2;
|
|
102
|
+
double lat2;
|
|
103
|
+
if (!PyArg_ParseTuple(args, "dddd", &lon1, &lat1, &lon2, &lat2)) {
|
|
104
|
+
return NULL; // Error occurred, exception already set
|
|
105
|
+
}
|
|
106
|
+
double result = bsonsearch_haversine_distance_degrees(
|
|
107
|
+
lon1, lat1, lon2, lat2
|
|
108
|
+
);
|
|
109
|
+
return PyFloat_FromDouble(result);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
static PyObject *
|
|
113
|
+
Utils_crossarc_degrees(Utils *self, PyObject *args, PyObject *kwds)
|
|
114
|
+
{
|
|
115
|
+
double lon1;
|
|
116
|
+
double lat1;
|
|
117
|
+
double lon2;
|
|
118
|
+
double lat2;
|
|
119
|
+
double lon3;
|
|
120
|
+
double lat3;
|
|
121
|
+
if (!PyArg_ParseTuple(args, "dddddd", &lon1, &lat1, &lon2, &lat2, &lon3, &lat3)) {
|
|
122
|
+
return NULL; // Error occurred, exception already set
|
|
123
|
+
}
|
|
124
|
+
double result = bsonsearch_get_crossarc_degrees(
|
|
125
|
+
lon1, lat1, lon2, lat2, lon3, lat3
|
|
126
|
+
);
|
|
127
|
+
return PyFloat_FromDouble(result);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
static PyObject *
|
|
131
|
+
Utils_get_value(Utils *self, PyObject *Py_UNUSED(ignored))
|
|
132
|
+
{
|
|
133
|
+
return PyLong_FromLong(self->value);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Method definitions for Matcher
|
|
137
|
+
static PyMethodDef Utils_methods[] = {
|
|
138
|
+
{"get_value", (PyCFunction)Utils_get_value, METH_NOARGS, "Return the value of the Document instance."},
|
|
139
|
+
{"regex_destroy", (PyCFunction)Utils_regex_destroy, METH_VARARGS, "Frees internal regex cache"},
|
|
140
|
+
{"startup", (PyCFunction)Utils_startup, METH_VARARGS, "Prep the module internally"},
|
|
141
|
+
{"shutdown", (PyCFunction)Utils_shutdown, METH_VARARGS, "Cleanup the module internally"},
|
|
142
|
+
{"to_bson", (PyCFunction)Utils_to_bson, METH_VARARGS, "convert a json document to bson document"},
|
|
143
|
+
{"haversine_distance", (PyCFunction)Utils_haversine_distance, METH_VARARGS, "Haversine distance using radians"},
|
|
144
|
+
{"haversine_distance_degrees", (PyCFunction)Utils_haversine_distance_degrees, METH_VARARGS, "Haversine distance using degrees"},
|
|
145
|
+
{"crossarc_degrees", (PyCFunction)Utils_crossarc_degrees, METH_VARARGS, "Crossarc"},
|
|
146
|
+
{NULL} /* Sentinel */
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
// Matcher_new: Constructor (allocates and initializes the C struct)
|
|
150
|
+
static PyObject *
|
|
151
|
+
Utils_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|
152
|
+
{
|
|
153
|
+
Utils *self;
|
|
154
|
+
self = (Utils *)type->tp_alloc(type, 0);
|
|
155
|
+
if (self != NULL) {
|
|
156
|
+
self->value = 0; // Default value
|
|
157
|
+
}
|
|
158
|
+
return (PyObject *)self;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Matcher_init: Initializer (sets instance attributes)
|
|
162
|
+
static int
|
|
163
|
+
Utils_init(Utils *self, PyObject *args, PyObject *kwds)
|
|
164
|
+
{
|
|
165
|
+
return 0;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Matcher_dealloc: Destructor (frees resources)
|
|
169
|
+
static void
|
|
170
|
+
Utils_dealloc(Document *self)
|
|
171
|
+
{
|
|
172
|
+
Py_TYPE(self)->tp_free((PyObject *)self);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
// 6. Create the PyTypeObject
|
|
177
|
+
static PyTypeObject UtilsClassType = {
|
|
178
|
+
PyVarObject_HEAD_INIT(NULL, 0)
|
|
179
|
+
.tp_name = "bsonsearch.matcher_module.Utils",
|
|
180
|
+
.tp_doc = "matchermodule",
|
|
181
|
+
.tp_basicsize = sizeof(Utils),
|
|
182
|
+
.tp_itemsize = 0,
|
|
183
|
+
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
|
184
|
+
.tp_new = Utils_new, // Use the custom tp_new
|
|
185
|
+
.tp_init = (initproc)Utils_init,
|
|
186
|
+
.tp_dealloc = (destructor)Utils_dealloc,
|
|
187
|
+
.tp_methods = Utils_methods,
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
// ---- Document FUNCTIONS ----
|
|
191
|
+
|
|
192
|
+
static PyObject *
|
|
193
|
+
Document_get_value(Document *self, PyObject *Py_UNUSED(ignored))
|
|
194
|
+
{
|
|
195
|
+
return PyLong_FromLong(self->value);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
static PyObject *
|
|
199
|
+
Document_as_bson(Document *self, PyObject *Py_UNUSED(ignored))
|
|
200
|
+
{
|
|
201
|
+
const uint8_t *doc_bson = bson_get_data(self->document);
|
|
202
|
+
PyObject * result = Py_BuildValue("y#", doc_bson, self->document->len);
|
|
203
|
+
return result;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
static PyObject *
|
|
207
|
+
Document_as_json(Document *self, PyObject *Py_UNUSED(ignored))
|
|
208
|
+
{
|
|
209
|
+
Py_ssize_t len;
|
|
210
|
+
char * str = bson_as_legacy_extended_json(self->document, &len);
|
|
211
|
+
PyObject * result = Py_BuildValue("s#", str, len);
|
|
212
|
+
bson_free(str);
|
|
213
|
+
return result;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
static PyObject *
|
|
217
|
+
Document_as_canonical_json(Document *self, PyObject *Py_UNUSED(ignored))
|
|
218
|
+
{
|
|
219
|
+
Py_ssize_t len;
|
|
220
|
+
char * str = bson_as_canonical_extended_json(self->document, &len);
|
|
221
|
+
PyObject * result = Py_BuildValue("s#", str, len);
|
|
222
|
+
bson_free(str);
|
|
223
|
+
return result;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Method definitions for Matcher
|
|
227
|
+
static PyMethodDef Document_methods[] = {
|
|
228
|
+
{"get_value", (PyCFunction)Document_get_value, METH_NOARGS, "Return the value of the Document instance."},
|
|
229
|
+
{"as_bson", (PyCFunction)Document_as_bson, METH_NOARGS, "Return the BSON bytes"},
|
|
230
|
+
{"as_json", (PyCFunction)Document_as_json, METH_NOARGS, "Return the JSON string"},
|
|
231
|
+
{"as_canonical_json", (PyCFunction)Document_as_canonical_json, METH_NOARGS, "Return the canonical JSON string"},
|
|
232
|
+
{NULL} /* Sentinel */
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
// Matcher_new: Constructor (allocates and initializes the C struct)
|
|
236
|
+
static PyObject *
|
|
237
|
+
Document_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|
238
|
+
{
|
|
239
|
+
Document *self;
|
|
240
|
+
self = (Document *)type->tp_alloc(type, 0);
|
|
241
|
+
if (self != NULL) {
|
|
242
|
+
self->value = 0; // Default value
|
|
243
|
+
}
|
|
244
|
+
return (PyObject *)self;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Matcher_init: Initializer (sets instance attributes)
|
|
248
|
+
static int
|
|
249
|
+
Document_init(Document *self, PyObject *args, PyObject *kwds)
|
|
250
|
+
{
|
|
251
|
+
PyObject* input_obj;
|
|
252
|
+
if (!PyArg_ParseTuple(args, "O", &input_obj)) {
|
|
253
|
+
return 0; // Error handling done by PyArg_ParseTuple
|
|
254
|
+
}
|
|
255
|
+
if (PyUnicode_Check(input_obj)) {
|
|
256
|
+
char* buffer = PyUnicode_AsUTF8AndSize(input_obj, &self->value);
|
|
257
|
+
if (buffer == NULL) {
|
|
258
|
+
PyErr_SetString(PyExc_TypeError, "Expected a JSON string");
|
|
259
|
+
return -1; // Error
|
|
260
|
+
}
|
|
261
|
+
self->document = generate_doc_from_json((const uint8_t *)buffer, (uint32_t)self->value);
|
|
262
|
+
if (self->document == NULL) {
|
|
263
|
+
PyErr_SetString(PyExc_TypeError, "Expected valid JSON string");
|
|
264
|
+
return -1;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
} else if (PyBytes_Check(input_obj)) {
|
|
268
|
+
Py_ssize_t length;
|
|
269
|
+
char* buffer = NULL;
|
|
270
|
+
PyBytes_AsStringAndSize(input_obj, &buffer, &length);
|
|
271
|
+
self->document = bson_new_from_data((const uint8_t*)buffer, (uint32_t)length);
|
|
272
|
+
if (self->document == NULL) {
|
|
273
|
+
PyErr_SetString(PyExc_TypeError, "Expected a valid BSON document");
|
|
274
|
+
return -1;
|
|
275
|
+
}
|
|
276
|
+
} else {
|
|
277
|
+
PyErr_SetString(PyExc_TypeError, "Expected string or bytes");
|
|
278
|
+
return -1;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return 0;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Matcher_dealloc: Destructor (frees resources)
|
|
285
|
+
static void
|
|
286
|
+
Document_dealloc(Document *self)
|
|
287
|
+
{
|
|
288
|
+
doc_destroy(self->document);
|
|
289
|
+
Py_TYPE(self)->tp_free((PyObject *)self);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
// 6. Create the PyTypeObject
|
|
294
|
+
static PyTypeObject DocumentClassType = {
|
|
295
|
+
PyVarObject_HEAD_INIT(NULL, 0)
|
|
296
|
+
.tp_name = "bsonsearch.matcher_module.Document",
|
|
297
|
+
.tp_doc = "matchermodule",
|
|
298
|
+
.tp_basicsize = sizeof(Matcher),
|
|
299
|
+
.tp_itemsize = 0,
|
|
300
|
+
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
|
301
|
+
.tp_new = Document_new, // Use the custom tp_new
|
|
302
|
+
.tp_init = (initproc)Document_init,
|
|
303
|
+
.tp_dealloc = (destructor)Document_dealloc,
|
|
304
|
+
.tp_methods = Document_methods,
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
// ---- MATCHER FUNCTIONS ----
|
|
311
|
+
static PyObject *
|
|
312
|
+
Matcher_get_value(Matcher *self, PyObject *Py_UNUSED(ignored))
|
|
313
|
+
{
|
|
314
|
+
return PyLong_FromLong(self->value);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
static PyObject *
|
|
318
|
+
Matcher_match_json(Matcher *self, PyObject *args, PyObject *kwds)
|
|
319
|
+
{
|
|
320
|
+
const char *c_string_ptr;
|
|
321
|
+
Py_ssize_t c_string_len;
|
|
322
|
+
if (!PyArg_ParseTuple(args, "s#", &c_string_ptr, &c_string_len)) {
|
|
323
|
+
return NULL;
|
|
324
|
+
}
|
|
325
|
+
bson_t *doc = generate_doc_from_json((const uint8_t*)c_string_ptr, c_string_len);
|
|
326
|
+
if (!doc) {
|
|
327
|
+
return NULL;
|
|
328
|
+
}
|
|
329
|
+
long result = matcher_compare_doc(self->matcher, doc);
|
|
330
|
+
doc_destroy(doc);
|
|
331
|
+
return PyBool_FromLong(result);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
static PyObject *
|
|
335
|
+
Matcher_match_doc(Matcher *self, PyObject *args, PyObject *kwds)
|
|
336
|
+
{
|
|
337
|
+
PyObject *my_obj;
|
|
338
|
+
if (!PyArg_ParseTuple(args, "O!", &DocumentClassType, &my_obj)) {
|
|
339
|
+
return NULL; // PyArg_ParseTuple handles the error
|
|
340
|
+
}
|
|
341
|
+
Document *document = (Document *)my_obj;
|
|
342
|
+
long result = matcher_compare_doc(self->matcher, document->document);
|
|
343
|
+
return PyBool_FromLong(result);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
static PyObject *
|
|
347
|
+
Matcher_project_json(Matcher *self, PyObject *args, PyObject *kwds)
|
|
348
|
+
{
|
|
349
|
+
PyObject *my_obj;
|
|
350
|
+
if (!PyArg_ParseTuple(args, "O!", &DocumentClassType, &my_obj)) {
|
|
351
|
+
return NULL; // PyArg_ParseTuple handles the error
|
|
352
|
+
}
|
|
353
|
+
Document *document = (Document *)my_obj;
|
|
354
|
+
char *result = bsonsearch_project_json(self->matcher, document->document);
|
|
355
|
+
PyObject *returnable = Py_BuildValue("s", result);
|
|
356
|
+
bson_free(result);
|
|
357
|
+
return returnable;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
static PyObject *
|
|
361
|
+
Matcher_project_canonical_json(Matcher *self, PyObject *args, PyObject *kwds)
|
|
362
|
+
{
|
|
363
|
+
PyObject *my_obj;
|
|
364
|
+
if (!PyArg_ParseTuple(args, "O!", &DocumentClassType, &my_obj)) {
|
|
365
|
+
return NULL; // PyArg_ParseTuple handles the error
|
|
366
|
+
}
|
|
367
|
+
Document *document = (Document *)my_obj;
|
|
368
|
+
char *result = bsonsearch_project_canonical_json(self->matcher, document->document);
|
|
369
|
+
PyObject *returnable = Py_BuildValue("s", result);
|
|
370
|
+
bson_free(result);
|
|
371
|
+
return returnable;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
static PyObject *
|
|
375
|
+
Matcher_project_bson(Matcher *self, PyObject *args, PyObject *kwds)
|
|
376
|
+
{
|
|
377
|
+
PyObject *my_obj;
|
|
378
|
+
if (!PyArg_ParseTuple(args, "O!", &DocumentClassType, &my_obj)) {
|
|
379
|
+
return NULL; // PyArg_ParseTuple handles the error
|
|
380
|
+
}
|
|
381
|
+
Document *document = (Document *)my_obj;
|
|
382
|
+
bson_t *projected = bsonsearch_project_bson(self->matcher, document->document);
|
|
383
|
+
const uint8_t *doc_bson = bson_get_data(projected);
|
|
384
|
+
PyObject *returnable = Py_BuildValue("y#", doc_bson, projected->len);
|
|
385
|
+
bson_destroy(projected);
|
|
386
|
+
return returnable;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
static PyObject *
|
|
390
|
+
Matcher_as_bson(Matcher *self, PyObject *Py_UNUSED(ignored))
|
|
391
|
+
{
|
|
392
|
+
const uint8_t *doc_bson = bson_get_data(&self->matcher->query);
|
|
393
|
+
PyObject * result = Py_BuildValue("y#", doc_bson, self->matcher->query.len);
|
|
394
|
+
return result;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
static PyObject *
|
|
398
|
+
Matcher_as_json(Matcher *self, PyObject *Py_UNUSED(ignored))
|
|
399
|
+
{
|
|
400
|
+
Py_ssize_t len;
|
|
401
|
+
char * str = bson_as_legacy_extended_json(&self->matcher->query, &len);
|
|
402
|
+
PyObject * result = Py_BuildValue("s#", str, len);
|
|
403
|
+
bson_free(str);
|
|
404
|
+
return result;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
static PyObject *
|
|
408
|
+
Matcher_as_canonical_json(Matcher *self, PyObject *Py_UNUSED(ignored))
|
|
409
|
+
{
|
|
410
|
+
Py_ssize_t len;
|
|
411
|
+
char * str = bson_as_canonical_extended_json(&self->matcher->query, &len);
|
|
412
|
+
PyObject * result = Py_BuildValue("s#", str, len);
|
|
413
|
+
bson_free(str);
|
|
414
|
+
return result;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// Method definitions for Matcher
|
|
418
|
+
static PyMethodDef Matcher_methods[] = {
|
|
419
|
+
{"get_value", (PyCFunction)Matcher_get_value, METH_NOARGS, "Return the value of the Matcher instance."},
|
|
420
|
+
{"as_bson", (PyCFunction)Matcher_as_bson, METH_NOARGS, "gets the BSON representation of the matcher."},
|
|
421
|
+
{"as_json", (PyCFunction)Matcher_as_json, METH_NOARGS, "gets the JSON representation of the matcher."},
|
|
422
|
+
{"as_canonical_json", (PyCFunction)Matcher_as_canonical_json, METH_NOARGS, "gets the canonical JSON representation of the matcher."},
|
|
423
|
+
{"match_json", (PyCFunction)Matcher_match_json, METH_VARARGS, "Returns whether the doc matches the spec"},
|
|
424
|
+
{"match_doc", (PyCFunction)Matcher_match_doc, METH_VARARGS, "Returns whether the doc matches the spec"},
|
|
425
|
+
{"project_json", (PyCFunction)Matcher_project_json, METH_VARARGS, "projects data into a json document"},
|
|
426
|
+
{"project_canonical_json", (PyCFunction)Matcher_project_canonical_json, METH_VARARGS, "projects data into a canonical json document"},
|
|
427
|
+
{"project_bson", (PyCFunction)Matcher_project_bson, METH_VARARGS, "projects data into a bson document"},
|
|
428
|
+
{NULL} /* Sentinel */
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
// Matcher_new: Constructor (allocates and initializes the C struct)
|
|
432
|
+
static PyObject *
|
|
433
|
+
Matcher_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|
434
|
+
{
|
|
435
|
+
Matcher *self;
|
|
436
|
+
self = (Matcher *)type->tp_alloc(type, 0);
|
|
437
|
+
if (self != NULL) {
|
|
438
|
+
self->value = 0; // Default value
|
|
439
|
+
}
|
|
440
|
+
return (PyObject *)self;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// Matcher_init: Initializer (sets instance attributes)
|
|
444
|
+
static int
|
|
445
|
+
Matcher_init(Matcher *self, PyObject *args, PyObject *kwds)
|
|
446
|
+
{
|
|
447
|
+
PyObject* input_obj;
|
|
448
|
+
if (!PyArg_ParseTuple(args, "O", &input_obj)) {
|
|
449
|
+
return 0; // Error handling done by PyArg_ParseTuple
|
|
450
|
+
}
|
|
451
|
+
if (PyUnicode_Check(input_obj)) {
|
|
452
|
+
self->json = PyUnicode_AsUTF8AndSize(input_obj, &self->value);
|
|
453
|
+
if (self->json == NULL) {
|
|
454
|
+
PyErr_SetString(PyExc_TypeError, "Expected a JSON string");
|
|
455
|
+
return 0; // Error
|
|
456
|
+
}
|
|
457
|
+
self->matcher = generate_matcher_from_json((const uint8_t *)self->json, (uint32_t)self->value);
|
|
458
|
+
if (self->matcher == NULL) {
|
|
459
|
+
return -2;
|
|
460
|
+
}
|
|
461
|
+
} else if (PyBytes_Check(input_obj)) {
|
|
462
|
+
Py_ssize_t length;
|
|
463
|
+
char* buffer = NULL;
|
|
464
|
+
PyBytes_AsStringAndSize(input_obj, &buffer, &length);
|
|
465
|
+
self->matcher = generate_matcher((const uint8_t*)buffer, (uint32_t)length);
|
|
466
|
+
if (self->matcher == NULL) {
|
|
467
|
+
PyErr_SetString(PyExc_TypeError, "Expected a valid BSON document");
|
|
468
|
+
return 0;
|
|
469
|
+
}
|
|
470
|
+
} else {
|
|
471
|
+
PyErr_SetString(PyExc_TypeError, "Expected string or bytes");
|
|
472
|
+
return -1;
|
|
473
|
+
}
|
|
474
|
+
return 0;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// Matcher_dealloc: Destructor (frees resources)
|
|
478
|
+
static void
|
|
479
|
+
Matcher_dealloc(Matcher *self)
|
|
480
|
+
{
|
|
481
|
+
matcher_destroy(self->matcher);
|
|
482
|
+
Py_TYPE(self)->tp_free((PyObject *)self);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
// 6. Create the PyTypeObject
|
|
487
|
+
static PyTypeObject MatcherClassType = {
|
|
488
|
+
PyVarObject_HEAD_INIT(NULL, 0)
|
|
489
|
+
.tp_name = "bsonsearch.matcher_module.Matcher",
|
|
490
|
+
.tp_doc = "matchermodule",
|
|
491
|
+
.tp_basicsize = sizeof(Matcher),
|
|
492
|
+
.tp_itemsize = 0,
|
|
493
|
+
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
|
494
|
+
.tp_new = Matcher_new, // Use the custom tp_new
|
|
495
|
+
.tp_init = (initproc)Matcher_init,
|
|
496
|
+
.tp_dealloc = (destructor)Matcher_dealloc,
|
|
497
|
+
.tp_methods = Matcher_methods,
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
// ---- Module FUNCTIONS (unlikely to need editing below here) ----
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
static struct PyModuleDef matcher_module_def = {
|
|
506
|
+
PyModuleDef_HEAD_INIT,
|
|
507
|
+
.m_name = "bsonsearch.matcher_module",
|
|
508
|
+
.m_doc = "The module.",
|
|
509
|
+
.m_size = -1
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
// Module initialization function
|
|
514
|
+
PyMODINIT_FUNC
|
|
515
|
+
PyInit_matcher_module(void)
|
|
516
|
+
{
|
|
517
|
+
PyObject *m;
|
|
518
|
+
|
|
519
|
+
if (PyType_Ready(&MatcherClassType) < 0)
|
|
520
|
+
return NULL;
|
|
521
|
+
|
|
522
|
+
if (PyType_Ready(&DocumentClassType) < 0)
|
|
523
|
+
return NULL;
|
|
524
|
+
|
|
525
|
+
if (PyType_Ready(&UtilsClassType) < 0)
|
|
526
|
+
return NULL;
|
|
527
|
+
|
|
528
|
+
m = PyModule_Create(&matcher_module_def);
|
|
529
|
+
if (m == NULL)
|
|
530
|
+
return NULL;
|
|
531
|
+
|
|
532
|
+
Py_INCREF(&MatcherClassType);
|
|
533
|
+
if (PyModule_AddObject(m, "Matcher", (PyObject *)&MatcherClassType) < 0) {
|
|
534
|
+
Py_DECREF(&MatcherClassType);
|
|
535
|
+
Py_DECREF(m);
|
|
536
|
+
return NULL;
|
|
537
|
+
}
|
|
538
|
+
Py_INCREF(&DocumentClassType);
|
|
539
|
+
if (PyModule_AddObject(m, "Document", (PyObject *)&DocumentClassType) < 0) {
|
|
540
|
+
Py_DECREF(&DocumentClassType);
|
|
541
|
+
Py_DECREF(m);
|
|
542
|
+
return NULL;
|
|
543
|
+
}
|
|
544
|
+
Py_INCREF(&UtilsClassType);
|
|
545
|
+
if (PyModule_AddObject(m, "Utils", (PyObject *)&UtilsClassType) < 0) {
|
|
546
|
+
Py_DECREF(&UtilsClassType);
|
|
547
|
+
Py_DECREF(m);
|
|
548
|
+
return NULL;
|
|
549
|
+
}
|
|
550
|
+
return m;
|
|
551
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
bsonsearch/__init__.py,sha256=HwyXH3os6-2kCbVKL3SUUgz_p38bAaBFpERzgPHzzcc,5376
|
|
2
|
+
bsonsearch/matcher_module.cpython-314-x86_64-linux-musl.so,sha256=D9133WwgqDA29GGxAoPDBiXDOTZDNfrcLpoVYClprUw,67009
|
|
3
|
+
bsonsearch/matcher_ext/matcher_module.c,sha256=j9qCKULhmS7uPzdgl8IjKPhi2dsGQnvhULKcCs3VSfM,16944
|
|
4
|
+
bsonsearch.libs/libbson2-aa5f0313.so.2.1.2,sha256=GF9ATPm6wfV2BMYipABShAog8MnElkFrivv-hG-Nea8,714113
|
|
5
|
+
bsonsearch.libs/libbsonsearch-b4c2d01c.so,sha256=MUzIt1i8OZIiqP1PDMLulrJtdYXBWgpWQh-MHI0UDgs,127761
|
|
6
|
+
bsonsearch.libs/libcmph-7e8d51a6.so.0.0.0,sha256=X66uW52D4bSwB4Bqc2Ifhrsky7GWHGno6mouIu5Us88,449905
|
|
7
|
+
bsonsearch.libs/libdiscodb-6058085b.so,sha256=DyWvStCfFmR9ReAbA4Gg48lh_eFuO3ln8tGxDHo1R2U,63425
|
|
8
|
+
bsonsearch.libs/libduktape-2bef3d5d.so.207.20700,sha256=D9dNIMLGQAoNqk3oURzWJ-VcmN4SmQ175t3WjhbjV14,360249
|
|
9
|
+
bsonsearch.libs/libpcre-77987b86.so.1.2.13,sha256=J4JjEVCh8VwzcR2zw49Xuzvc5gjzQ5H4MFMH7A8KCnc,1529129
|
|
10
|
+
bsonsearch-2.1.2.dist-info/METADATA,sha256=Q0gu93DeoPesbpLa-sHUNiTBlDK4zh26QUAQJssrL8g,209
|
|
11
|
+
bsonsearch-2.1.2.dist-info/WHEEL,sha256=K2_TehZnioJBDmm5baDVfhoCxaclJzJsPrng3hg7WD0,112
|
|
12
|
+
bsonsearch-2.1.2.dist-info/top_level.txt,sha256=yKvan_PZbgnwFJu7aiO90uulDgZEUkdIbqdARreIdAU,11
|
|
13
|
+
bsonsearch-2.1.2.dist-info/RECORD,,
|
|
14
|
+
bsonsearch-2.1.2.dist-info/licenses/LICENSE,sha256=Kn6aS7NZYk5QKVM90hlXPEC32aK9Z4ioFCkLvdGlKP4,1081
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2014-2016 Dan Bauman
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
bsonsearch
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|