New MGP API (#219)
This commit is contained in:
parent
5a8bda2531
commit
2afc1b99f6
@ -1,5 +1,6 @@
|
||||
---
|
||||
Checks: '*,
|
||||
-altera-struct-pack-align,
|
||||
-android-*,
|
||||
-cert-err58-cpp,
|
||||
-cppcoreguidelines-avoid-c-arrays,
|
||||
@ -43,7 +44,6 @@ Checks: '*,
|
||||
-llvmlibc-implementation-in-namespace,
|
||||
-llvmlibc-restrict-system-libc-headers,
|
||||
-misc-non-private-member-variables-in-classes,
|
||||
-misc-unused-parameters,
|
||||
-modernize-avoid-c-arrays,
|
||||
-modernize-concat-nested-namespaces,
|
||||
-modernize-pass-by-value,
|
||||
|
@ -7,9 +7,34 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
#define MGP_NODISCARD [[nodiscard]]
|
||||
#else
|
||||
#define MGP_NODISCARD
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/// @name Error Codes
|
||||
///
|
||||
///@{
|
||||
|
||||
/// All functions return an error code that can be used to figure out whether the API call was successful or not. In
|
||||
/// case of failure, the specific error code can be used to identify the reason of the failure.
|
||||
enum MGP_NODISCARD mgp_error {
|
||||
MGP_ERROR_NO_ERROR = 0,
|
||||
MGP_ERROR_UNKNOWN_ERROR,
|
||||
MGP_ERROR_UNABLE_TO_ALLOCATE,
|
||||
MGP_ERROR_INSUFFICIENT_BUFFER,
|
||||
MGP_ERROR_OUT_OF_RANGE,
|
||||
MGP_ERROR_LOGIC_ERROR,
|
||||
MGP_ERROR_NON_EXISTENT_OBJECT,
|
||||
MGP_ERROR_INVALID_ARGUMENT,
|
||||
MGP_ERROR_KEY_ALREADY_EXISTS,
|
||||
};
|
||||
///@}
|
||||
|
||||
/// @name Memory Allocation
|
||||
///
|
||||
/// These should be preferred compared to plain malloc calls as Memgraph's
|
||||
@ -30,17 +55,17 @@ struct mgp_memory;
|
||||
/// Allocate a block of memory with given size in bytes.
|
||||
/// Unlike malloc, this function is not thread-safe.
|
||||
/// `size_in_bytes` must be greater than 0.
|
||||
/// The returned pointer must be freed with mgp_free.
|
||||
/// NULL is returned if unable to serve the requested allocation.
|
||||
void *mgp_alloc(struct mgp_memory *memory, size_t size_in_bytes);
|
||||
/// The resulting pointer must be freed with mgp_free.
|
||||
/// MGP_ERROR_UNABLE_TO_ALLOCATE is returned if unable to serve the requested allocation.
|
||||
enum mgp_error mgp_alloc(struct mgp_memory *memory, size_t size_in_bytes, void **result);
|
||||
|
||||
/// Allocate an aligned block of memory with given size in bytes.
|
||||
/// Unlike malloc and aligned_alloc, this function is not thread-safe.
|
||||
/// `size_in_bytes` must be greater than 0.
|
||||
/// `alignment` must be a power of 2 value.
|
||||
/// The returned pointer must be freed with mgp_free.
|
||||
/// NULL is returned if unable to serve the requested allocation.
|
||||
void *mgp_aligned_alloc(struct mgp_memory *memory, size_t size_in_bytes, size_t alignment);
|
||||
/// The resulting pointer must be freed with mgp_free.
|
||||
/// MGP_ERROR_UNABLE_TO_ALLOCATE is returned if unable to serve the requested allocation.
|
||||
enum mgp_error mgp_aligned_alloc(struct mgp_memory *memory, size_t size_in_bytes, size_t alignment, void **result);
|
||||
|
||||
/// Deallocate an allocation from mgp_alloc or mgp_aligned_alloc.
|
||||
/// Unlike free, this function is not thread-safe.
|
||||
@ -52,16 +77,16 @@ void mgp_free(struct mgp_memory *memory, void *ptr);
|
||||
/// Allocate a global block of memory with given size in bytes.
|
||||
/// This function can be used to allocate global memory that persists
|
||||
/// beyond a single invocation of mgp_main.
|
||||
/// The returned pointer must be freed with mgp_global_free.
|
||||
/// NULL is returned if unable to serve the requested allocation.
|
||||
void *mgp_global_alloc(size_t size_in_bytes);
|
||||
/// The resulting pointer must be freed with mgp_global_free.
|
||||
/// MGP_ERROR_UNABLE_TO_ALLOCATE is returned if unable to serve the requested allocation.
|
||||
enum mgp_error mgp_global_alloc(size_t size_in_bytes, void **result);
|
||||
|
||||
/// Allocate an aligned global block of memory with given size in bytes.
|
||||
/// This function can be used to allocate global memory that persists
|
||||
/// beyond a single invocation of mgp_main.
|
||||
/// The returned pointer must be freed with mgp_global_free.
|
||||
/// NULL is returned if unable to serve the requested allocation.
|
||||
void *mgp_global_aligned_alloc(size_t size_in_bytes, size_t alignment);
|
||||
/// The resulting pointer must be freed with mgp_global_free.
|
||||
/// MGP_ERROR_UNABLE_TO_ALLOCATE is returned if unable to serve the requested allocation.
|
||||
enum mgp_error mgp_global_aligned_alloc(size_t size_in_bytes, size_t alignment, void **result);
|
||||
|
||||
/// Deallocate an allocation from mgp_global_alloc or mgp_global_aligned_alloc.
|
||||
/// If `ptr` is NULL, this function does nothing.
|
||||
@ -117,147 +142,167 @@ void mgp_value_destroy(struct mgp_value *val);
|
||||
|
||||
/// Construct a value representing `null` in openCypher.
|
||||
/// You need to free the instance through mgp_value_destroy.
|
||||
/// NULL is returned if unable to allocate a mgp_value.
|
||||
struct mgp_value *mgp_value_make_null(struct mgp_memory *memory);
|
||||
/// MGP_ERROR_UNABLE_TO_ALLOCATE is returned if unable to allocate a mgp_value.
|
||||
enum mgp_error mgp_value_make_null(struct mgp_memory *memory, struct mgp_value **result);
|
||||
|
||||
/// Construct a boolean value.
|
||||
/// Non-zero values represent `true`, while zero represents `false`.
|
||||
/// You need to free the instance through mgp_value_destroy.
|
||||
/// NULL is returned if unable to allocate a mgp_value.
|
||||
struct mgp_value *mgp_value_make_bool(int val, struct mgp_memory *memory);
|
||||
/// MGP_ERROR_UNABLE_TO_ALLOCATE is returned if unable to allocate a mgp_value.
|
||||
enum mgp_error mgp_value_make_bool(int val, struct mgp_memory *memory, struct mgp_value **result);
|
||||
|
||||
/// Construct an integer value.
|
||||
/// You need to free the instance through mgp_value_destroy.
|
||||
/// NULL is returned if unable to allocate a mgp_value.
|
||||
struct mgp_value *mgp_value_make_int(int64_t val, struct mgp_memory *memory);
|
||||
/// MGP_ERROR_UNABLE_TO_ALLOCATE is returned if unable to allocate a mgp_value.
|
||||
enum mgp_error mgp_value_make_int(int64_t val, struct mgp_memory *memory, struct mgp_value **result);
|
||||
|
||||
/// Construct a double floating point value.
|
||||
/// You need to free the instance through mgp_value_destroy.
|
||||
/// NULL is returned if unable to allocate a mgp_value.
|
||||
struct mgp_value *mgp_value_make_double(double val, struct mgp_memory *memory);
|
||||
/// MGP_ERROR_UNABLE_TO_ALLOCATE is returned if unable to allocate a mgp_value.
|
||||
enum mgp_error mgp_value_make_double(double val, struct mgp_memory *memory, struct mgp_value **result);
|
||||
|
||||
/// Construct a character string value from a NULL terminated string.
|
||||
/// You need to free the instance through mgp_value_destroy.
|
||||
/// NULL is returned if unable to allocate a mgp_value.
|
||||
struct mgp_value *mgp_value_make_string(const char *val, struct mgp_memory *memory);
|
||||
/// MGP_ERROR_UNABLE_TO_ALLOCATE is returned if unable to allocate a mgp_value.
|
||||
enum mgp_error mgp_value_make_string(const char *val, struct mgp_memory *memory, struct mgp_value **result);
|
||||
|
||||
/// Create a mgp_value storing a mgp_list.
|
||||
/// You need to free the instance through mgp_value_destroy. The ownership of
|
||||
/// the list is given to the created mgp_value and destroying the mgp_value will
|
||||
/// destroy the mgp_list. Therefore, if a mgp_value is successfully created
|
||||
/// you must not call mgp_list_destroy on the given list.
|
||||
/// NULL is returned if unable to allocate a mgp_value.
|
||||
struct mgp_value *mgp_value_make_list(struct mgp_list *val);
|
||||
/// MGP_ERROR_UNABLE_TO_ALLOCATE is returned if unable to allocate a mgp_value.
|
||||
enum mgp_error mgp_value_make_list(struct mgp_list *val, struct mgp_value **result);
|
||||
|
||||
/// Create a mgp_value storing a mgp_map.
|
||||
/// You need to free the instance through mgp_value_destroy. The ownership of
|
||||
/// the map is given to the created mgp_value and destroying the mgp_value will
|
||||
/// destroy the mgp_map. Therefore, if a mgp_value is successfully created
|
||||
/// you must not call mgp_map_destroy on the given map.
|
||||
/// NULL is returned if unable to allocate a mgp_value.
|
||||
struct mgp_value *mgp_value_make_map(struct mgp_map *val);
|
||||
/// MGP_ERROR_UNABLE_TO_ALLOCATE is returned if unable to allocate a mgp_value.
|
||||
enum mgp_error mgp_value_make_map(struct mgp_map *val, struct mgp_value **result);
|
||||
|
||||
/// Create a mgp_value storing a mgp_vertex.
|
||||
/// You need to free the instance through mgp_value_destroy. The ownership of
|
||||
/// the vertex is given to the created mgp_value and destroying the mgp_value
|
||||
/// will destroy the mgp_vertex. Therefore, if a mgp_value is successfully
|
||||
/// created you must not call mgp_vertex_destroy on the given vertex.
|
||||
/// NULL is returned if unable to allocate a mgp_value.
|
||||
struct mgp_value *mgp_value_make_vertex(struct mgp_vertex *val);
|
||||
/// MGP_ERROR_UNABLE_TO_ALLOCATE is returned if unable to allocate a mgp_value.
|
||||
enum mgp_error mgp_value_make_vertex(struct mgp_vertex *val, struct mgp_value **result);
|
||||
|
||||
/// Create a mgp_value storing a mgp_edge.
|
||||
/// You need to free the instance through mgp_value_destroy. The ownership of
|
||||
/// the edge is given to the created mgp_value and destroying the mgp_value will
|
||||
/// destroy the mgp_edge. Therefore, if a mgp_value is successfully created you
|
||||
/// must not call mgp_edge_destroy on the given edge.
|
||||
/// NULL is returned if unable to allocate a mgp_value.
|
||||
struct mgp_value *mgp_value_make_edge(struct mgp_edge *val);
|
||||
/// MGP_ERROR_UNABLE_TO_ALLOCATE is returned if unable to allocate a mgp_value.
|
||||
enum mgp_error mgp_value_make_edge(struct mgp_edge *val, struct mgp_value **result);
|
||||
|
||||
/// Create a mgp_value storing a mgp_path.
|
||||
/// You need to free the instance through mgp_value_destroy. The ownership of
|
||||
/// the path is given to the created mgp_value and destroying the mgp_value will
|
||||
/// destroy the mgp_path. Therefore, if a mgp_value is successfully created you
|
||||
/// must not call mgp_path_destroy on the given path.
|
||||
/// NULL is returned if unable to allocate a mgp_value.
|
||||
struct mgp_value *mgp_value_make_path(struct mgp_path *val);
|
||||
/// MGP_ERROR_UNABLE_TO_ALLOCATE is returned if unable to allocate a mgp_value.
|
||||
enum mgp_error mgp_value_make_path(struct mgp_path *val, struct mgp_value **result);
|
||||
|
||||
/// Return the type of the value contained in mgp_value.
|
||||
enum mgp_value_type mgp_value_get_type(const struct mgp_value *val);
|
||||
/// Get the type of the value contained in mgp_value.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_value_get_type(const struct mgp_value *val, enum mgp_value_type *result);
|
||||
|
||||
/// Return non-zero if the given mgp_value represents `null`.
|
||||
int mgp_value_is_null(const struct mgp_value *val);
|
||||
/// Result is non-zero if the given mgp_value represents `null`.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_value_is_null(const struct mgp_value *val, int *result);
|
||||
|
||||
/// Return non-zero if the given mgp_value stores a boolean.
|
||||
int mgp_value_is_bool(const struct mgp_value *val);
|
||||
/// Result is non-zero if the given mgp_value stores a boolean.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_value_is_bool(const struct mgp_value *val, int *result);
|
||||
|
||||
/// Return non-zero if the given mgp_value stores an integer.
|
||||
int mgp_value_is_int(const struct mgp_value *val);
|
||||
/// Result is non-zero if the given mgp_value stores an integer.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_value_is_int(const struct mgp_value *val, int *result);
|
||||
|
||||
/// Return non-zero if the given mgp_value stores a double floating-point.
|
||||
int mgp_value_is_double(const struct mgp_value *val);
|
||||
/// Result is non-zero if the given mgp_value stores a double floating-point.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_value_is_double(const struct mgp_value *val, int *result);
|
||||
|
||||
/// Return non-zero if the given mgp_value stores a character string.
|
||||
int mgp_value_is_string(const struct mgp_value *val);
|
||||
/// Result is non-zero if the given mgp_value stores a character string.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_value_is_string(const struct mgp_value *val, int *result);
|
||||
|
||||
/// Return non-zero if the given mgp_value stores a list of values.
|
||||
int mgp_value_is_list(const struct mgp_value *val);
|
||||
/// Result is non-zero if the given mgp_value stores a list of values.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_value_is_list(const struct mgp_value *val, int *result);
|
||||
|
||||
/// Return non-zero if the given mgp_value stores a map of values.
|
||||
int mgp_value_is_map(const struct mgp_value *val);
|
||||
/// Result is non-zero if the given mgp_value stores a map of values.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_value_is_map(const struct mgp_value *val, int *result);
|
||||
|
||||
/// Return non-zero if the given mgp_value stores a vertex.
|
||||
int mgp_value_is_vertex(const struct mgp_value *val);
|
||||
/// Result is non-zero if the given mgp_value stores a vertex.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_value_is_vertex(const struct mgp_value *val, int *result);
|
||||
|
||||
/// Return non-zero if the given mgp_value stores an edge.
|
||||
int mgp_value_is_edge(const struct mgp_value *val);
|
||||
/// Result is non-zero if the given mgp_value stores an edge.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_value_is_edge(const struct mgp_value *val, int *result);
|
||||
|
||||
/// Return non-zero if the given mgp_value stores a path.
|
||||
int mgp_value_is_path(const struct mgp_value *val);
|
||||
/// Result is non-zero if the given mgp_value stores a path.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_value_is_path(const struct mgp_value *val, int *result);
|
||||
|
||||
/// Return the contained boolean value.
|
||||
/// Get the contained boolean value.
|
||||
/// Non-zero values represent `true`, while zero represents `false`.
|
||||
/// The result is undefined if mgp_value does not contain the expected type.
|
||||
int mgp_value_get_bool(const struct mgp_value *val);
|
||||
/// Result is undefined if mgp_value does not contain the expected type.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_value_get_bool(const struct mgp_value *val, int *result);
|
||||
|
||||
/// Return the contained integer.
|
||||
/// The result is undefined if mgp_value does not contain the expected type.
|
||||
int64_t mgp_value_get_int(const struct mgp_value *val);
|
||||
/// Get the contained integer.
|
||||
/// Result is undefined if mgp_value does not contain the expected type.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_value_get_int(const struct mgp_value *val, int64_t *result);
|
||||
|
||||
/// Return the contained double floating-point.
|
||||
/// The result is undefined if mgp_value does not contain the expected type.
|
||||
double mgp_value_get_double(const struct mgp_value *val);
|
||||
/// Get the contained double floating-point.
|
||||
/// Result is undefined if mgp_value does not contain the expected type.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_value_get_double(const struct mgp_value *val, double *result);
|
||||
|
||||
/// Return the contained character string.
|
||||
/// The result is undefined if mgp_value does not contain the expected type.
|
||||
const char *mgp_value_get_string(const struct mgp_value *val);
|
||||
/// Get the contained character string.
|
||||
/// Result is undefined if mgp_value does not contain the expected type.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_value_get_string(const struct mgp_value *val, const char **result);
|
||||
|
||||
/// Return the contained list of values.
|
||||
/// The result is undefined if mgp_value does not contain the expected type.
|
||||
const struct mgp_list *mgp_value_get_list(const struct mgp_value *val);
|
||||
/// Get the contained list of values.
|
||||
/// Result is undefined if mgp_value does not contain the expected type.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_value_get_list(const struct mgp_value *val, const struct mgp_list **result);
|
||||
|
||||
/// Return the contained map of values.
|
||||
/// The result is undefined if mgp_value does not contain the expected type.
|
||||
const struct mgp_map *mgp_value_get_map(const struct mgp_value *val);
|
||||
/// Result is undefined if mgp_value does not contain the expected type.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_value_get_map(const struct mgp_value *val, const struct mgp_map **result);
|
||||
|
||||
/// Return the contained vertex.
|
||||
/// The result is undefined if mgp_value does not contain the expected type.
|
||||
const struct mgp_vertex *mgp_value_get_vertex(const struct mgp_value *val);
|
||||
/// Get the contained vertex.
|
||||
/// Result is undefined if mgp_value does not contain the expected type.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_value_get_vertex(const struct mgp_value *val, const struct mgp_vertex **result);
|
||||
|
||||
/// Return the contained edge.
|
||||
/// The result is undefined if mgp_value does not contain the expected type.
|
||||
const struct mgp_edge *mgp_value_get_edge(const struct mgp_value *val);
|
||||
/// Get the contained edge.
|
||||
/// Result is undefined if mgp_value does not contain the expected type.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_value_get_edge(const struct mgp_value *val, const struct mgp_edge **result);
|
||||
|
||||
/// Return the contained path.
|
||||
/// The result is undefined if mgp_value does not contain the expected type.
|
||||
const struct mgp_path *mgp_value_get_path(const struct mgp_value *val);
|
||||
/// Get the contained path.
|
||||
/// Result is undefined if mgp_value does not contain the expected type.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_value_get_path(const struct mgp_value *val, const struct mgp_path **result);
|
||||
|
||||
/// Create an empty list with given capacity.
|
||||
/// You need to free the created instance with mgp_list_destroy.
|
||||
/// The created list will have allocated enough memory for `capacity` elements
|
||||
/// of mgp_value, but it will not contain any elements. Therefore,
|
||||
/// mgp_list_size will return 0.
|
||||
/// NULL is returned if unable to allocate a new list.
|
||||
struct mgp_list *mgp_list_make_empty(size_t capacity, struct mgp_memory *memory);
|
||||
/// MGP_ERROR_UNABLE_TO_ALLOCATE is returned if unable to allocate a mgp_list.
|
||||
enum mgp_error mgp_list_make_empty(size_t capacity, struct mgp_memory *memory, struct mgp_list **result);
|
||||
|
||||
/// Free the memory used by the given mgp_list and contained elements.
|
||||
void mgp_list_destroy(struct mgp_list *list);
|
||||
@ -266,9 +311,9 @@ void mgp_list_destroy(struct mgp_list *list);
|
||||
/// The list copies the given value and therefore does not take ownership of the
|
||||
/// original value. You still need to call mgp_value_destroy to free the
|
||||
/// original value.
|
||||
/// Return non-zero on success, or 0 if there's no capacity or memory to append
|
||||
/// the mgp_value to mgp_list.
|
||||
int mgp_list_append(struct mgp_list *list, const struct mgp_value *val);
|
||||
/// Return MGP_ERROR_INSUFFICIENT_BUFFER if there's no capacity.
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_value.
|
||||
enum mgp_error mgp_list_append(struct mgp_list *list, const struct mgp_value *val);
|
||||
|
||||
/// Append a copy of mgp_value to mgp_list increasing capacity if needed.
|
||||
/// The list copies the given value and therefore does not take ownership of the
|
||||
@ -276,25 +321,27 @@ int mgp_list_append(struct mgp_list *list, const struct mgp_value *val);
|
||||
/// original value.
|
||||
/// In case of a capacity change, the previously contained elements will move in
|
||||
/// memory and any references to them will be invalid.
|
||||
/// Return non-zero on success, or 0 if there's no memory to append the
|
||||
/// mgp_value to mgp_list.
|
||||
int mgp_list_append_extend(struct mgp_list *list, const struct mgp_value *val);
|
||||
/// Return MGP_ERROR_INSUFFICIENT_BUFFER if there's no capacity.
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_value.
|
||||
enum mgp_error mgp_list_append_extend(struct mgp_list *list, const struct mgp_value *val);
|
||||
|
||||
/// Return the number of elements stored in mgp_list.
|
||||
size_t mgp_list_size(const struct mgp_list *list);
|
||||
/// Get the number of elements stored in mgp_list.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_list_size(const struct mgp_list *list, size_t *result);
|
||||
|
||||
/// Return the total number of elements for which there's already allocated
|
||||
/// Get the total number of elements for which there's already allocated
|
||||
/// memory in mgp_list.
|
||||
size_t mgp_list_capacity(const struct mgp_list *list);
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_list_capacity(const struct mgp_list *list, size_t *result);
|
||||
|
||||
/// Return the element in mgp_list at given position.
|
||||
/// NULL is returned if the index is not within mgp_list_size.
|
||||
const struct mgp_value *mgp_list_at(const struct mgp_list *list, size_t index);
|
||||
/// Get the element in mgp_list at given position.
|
||||
/// MGP_ERROR_OUT_OF_RANGE is returned if the index is not within mgp_list_size.
|
||||
enum mgp_error mgp_list_at(const struct mgp_list *list, size_t index, const struct mgp_value **result);
|
||||
|
||||
/// Create an empty map of character strings to mgp_value instances.
|
||||
/// You need to free the created instance with mgp_map_destroy.
|
||||
/// NULL is returned if unable to allocate a new map.
|
||||
struct mgp_map *mgp_map_make_empty(struct mgp_memory *memory);
|
||||
/// MGP_ERROR_UNABLE_TO_ALLOCATE is returned if unable to allocate a mgp_map.
|
||||
enum mgp_error mgp_map_make_empty(struct mgp_memory *memory, struct mgp_map **result);
|
||||
|
||||
/// Free the memory used by the given mgp_map and contained items.
|
||||
void mgp_map_destroy(struct mgp_map *map);
|
||||
@ -304,34 +351,36 @@ void mgp_map_destroy(struct mgp_map *map);
|
||||
/// In case of insertion, both the string and the value are copied into the map.
|
||||
/// Therefore, the map does not take ownership of the original key nor value, so
|
||||
/// you still need to free their memory explicitly.
|
||||
/// Return non-zero on success, or 0 if there's no memory to insert a new
|
||||
/// mapping or a previous mapping already exists.
|
||||
int mgp_map_insert(struct mgp_map *map, const char *key, const struct mgp_value *value);
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE is returned if unable to allocate for insertion.
|
||||
/// Return MGP_ERROR_KEY_ALREADY_EXISTS if a previous mapping already exists.
|
||||
enum mgp_error mgp_map_insert(struct mgp_map *map, const char *key, const struct mgp_value *value);
|
||||
|
||||
/// Return the number of items stored in mgp_map.
|
||||
size_t mgp_map_size(const struct mgp_map *map);
|
||||
/// Get the number of items stored in mgp_map.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_map_size(const struct mgp_map *map, size_t *result);
|
||||
|
||||
/// Return the mapped mgp_value to the given character string.
|
||||
/// NULL is returned if no mapping exists.
|
||||
const struct mgp_value *mgp_map_at(const struct mgp_map *map, const char *key);
|
||||
/// Get the mapped mgp_value to the given character string.
|
||||
/// Result is NULL if no mapping exists.
|
||||
enum mgp_error mgp_map_at(const struct mgp_map *map, const char *key, const struct mgp_value **result);
|
||||
|
||||
/// An item in the mgp_map.
|
||||
struct mgp_map_item;
|
||||
|
||||
/// Get the key of the mapped item.
|
||||
const char *mgp_map_item_key(const struct mgp_map_item *item);
|
||||
enum mgp_error mgp_map_item_key(const struct mgp_map_item *item, const char **result);
|
||||
|
||||
/// Get the value of the mapped item.
|
||||
const struct mgp_value *mgp_map_item_value(const struct mgp_map_item *item);
|
||||
enum mgp_error mgp_map_item_value(const struct mgp_map_item *item, const struct mgp_value **result);
|
||||
|
||||
/// An iterator over the items in mgp_map.
|
||||
struct mgp_map_items_iterator;
|
||||
|
||||
/// Start iterating over items contained in the given map.
|
||||
/// The returned mgp_map_items_iterator needs to be deallocated with
|
||||
/// The resulting mgp_map_items_iterator needs to be deallocated with
|
||||
/// mgp_map_items_iterator_destroy.
|
||||
/// NULL is returned if unable to allocate a new iterator.
|
||||
struct mgp_map_items_iterator *mgp_map_iter_items(const struct mgp_map *map, struct mgp_memory *memory);
|
||||
/// MGP_ERROR_UNABLE_TO_ALLOCATE is returned if unable to allocate a mgp_map_items_iterator.
|
||||
enum mgp_error mgp_map_iter_items(const struct mgp_map *map, struct mgp_memory *memory,
|
||||
struct mgp_map_items_iterator **result);
|
||||
|
||||
/// Deallocate memory used by mgp_map_items_iterator.
|
||||
void mgp_map_items_iterator_destroy(struct mgp_map_items_iterator *it);
|
||||
@ -343,24 +392,25 @@ void mgp_map_items_iterator_destroy(struct mgp_map_items_iterator *it);
|
||||
/// throughout the lifetime of a map. Therefore, you can store the key as well
|
||||
/// as the value before, and use them after invoking
|
||||
/// mgp_map_items_iterator_next.
|
||||
/// NULL is returned if the end of the iteration has been reached.
|
||||
const struct mgp_map_item *mgp_map_items_iterator_get(const struct mgp_map_items_iterator *it);
|
||||
/// Result is NULL if the end of the iteration has been reached.
|
||||
enum mgp_error mgp_map_items_iterator_get(const struct mgp_map_items_iterator *it, const struct mgp_map_item **result);
|
||||
|
||||
/// Advance the iterator to the next item stored in map and return it.
|
||||
/// The previous pointer obtained through mgp_map_items_iterator_get will
|
||||
/// be invalidated, but the pointers to key and value will remain valid.
|
||||
/// NULL is returned if the end of the iteration has been reached.
|
||||
const struct mgp_map_item *mgp_map_items_iterator_next(struct mgp_map_items_iterator *it);
|
||||
/// Result is NULL if the end of the iteration has been reached.
|
||||
enum mgp_error mgp_map_items_iterator_next(struct mgp_map_items_iterator *it, const struct mgp_map_item **result);
|
||||
|
||||
/// Create a path with the copy of the given starting vertex.
|
||||
/// You need to free the created instance with mgp_path_destroy.
|
||||
/// NULL is returned if unable to allocate a path.
|
||||
struct mgp_path *mgp_path_make_with_start(const struct mgp_vertex *vertex, struct mgp_memory *memory);
|
||||
/// MGP_ERROR_UNABLE_TO_ALLOCATE is returned if unable to allocate a mgp_path.
|
||||
enum mgp_error mgp_path_make_with_start(const struct mgp_vertex *vertex, struct mgp_memory *memory,
|
||||
struct mgp_path **result);
|
||||
|
||||
/// Copy a mgp_path.
|
||||
/// Returned pointer must be freed with mgp_path_destroy.
|
||||
/// NULL is returned if unable to allocate a mgp_path.
|
||||
struct mgp_path *mgp_path_copy(const struct mgp_path *path, struct mgp_memory *memory);
|
||||
/// MGP_ERROR_UNABLE_TO_ALLOCATE is returned if unable to allocate a mgp_path.
|
||||
enum mgp_error mgp_path_copy(const struct mgp_path *path, struct mgp_memory *memory, struct mgp_path **result);
|
||||
|
||||
/// Free the memory used by the given mgp_path and contained vertices and edges.
|
||||
void mgp_path_destroy(struct mgp_path *path);
|
||||
@ -371,26 +421,26 @@ void mgp_path_destroy(struct mgp_path *path);
|
||||
/// explicitly.
|
||||
/// The last vertex on the path will become the other endpoint of the given
|
||||
/// edge, as continued from the current last vertex.
|
||||
/// Return non-zero on success, or 0 if the current last vertex in the path is
|
||||
/// not part of the given edge. 0 is also returned if unable to allocate memory
|
||||
/// for path extension.
|
||||
int mgp_path_expand(struct mgp_path *path, const struct mgp_edge *edge);
|
||||
/// Return MGP_ERROR_LOGIC_ERROR if the current last vertex in the path is not part of the given edge.
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate memory for path extension.
|
||||
enum mgp_error mgp_path_expand(struct mgp_path *path, const struct mgp_edge *edge);
|
||||
|
||||
/// Return the number of edges in a mgp_path.
|
||||
size_t mgp_path_size(const struct mgp_path *path);
|
||||
/// Get the number of edges in a mgp_path.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_path_size(const struct mgp_path *path, size_t *result);
|
||||
|
||||
/// Return the vertex from a path at given index.
|
||||
/// Get the vertex from a path at given index.
|
||||
/// The valid index range is [0, mgp_path_size].
|
||||
/// NULL is returned if index is out of range.
|
||||
const struct mgp_vertex *mgp_path_vertex_at(const struct mgp_path *path, size_t index);
|
||||
/// MGP_ERROR_OUT_OF_RANGE is returned if index is out of range.
|
||||
enum mgp_error mgp_path_vertex_at(const struct mgp_path *path, size_t index, const struct mgp_vertex **result);
|
||||
|
||||
/// Return the edge from a path at given index.
|
||||
/// Get the edge from a path at given index.
|
||||
/// The valid index range is [0, mgp_path_size - 1].
|
||||
/// NULL is returned if index is out of range.
|
||||
const struct mgp_edge *mgp_path_edge_at(const struct mgp_path *path, size_t index);
|
||||
/// MGP_ERROR_OUT_OF_RANGE is returned if index is out of range.
|
||||
enum mgp_error mgp_path_edge_at(const struct mgp_path *path, size_t index, const struct mgp_edge **result);
|
||||
|
||||
/// Return non-zero if given paths are equal, otherwise 0.
|
||||
int mgp_path_equal(const struct mgp_path *p1, const struct mgp_path *p2);
|
||||
/// Result is non-zero if given paths are equal, otherwise 0.
|
||||
enum mgp_error mgp_path_equal(const struct mgp_path *p1, const struct mgp_path *p2, int *result);
|
||||
|
||||
///@}
|
||||
|
||||
@ -405,20 +455,20 @@ struct mgp_result;
|
||||
struct mgp_result_record;
|
||||
|
||||
/// Set the error as the result of the procedure.
|
||||
/// If there's no memory for copying the error message, 0 is returned.
|
||||
int mgp_result_set_error_msg(struct mgp_result *res, const char *error_msg);
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE ff there's no memory for copying the error message.
|
||||
enum mgp_error mgp_result_set_error_msg(struct mgp_result *res, const char *error_msg);
|
||||
|
||||
/// Create a new record for results.
|
||||
/// The previously returned pointer to mgp_result_record is no longer valid, and
|
||||
/// you must not use it.
|
||||
/// Return NULL if unable to allocate a mgp_result_record.
|
||||
struct mgp_result_record *mgp_result_new_record(struct mgp_result *res);
|
||||
/// The previously obtained mgp_result_record pointer is no longer valid, and you must not use it.
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_result_record.
|
||||
enum mgp_error mgp_result_new_record(struct mgp_result *res, struct mgp_result_record **result);
|
||||
|
||||
/// Assign a value to a field in the given record.
|
||||
/// Return 0 if there's no memory to copy the mgp_value to mgp_result_record or
|
||||
/// if the combination of `field_name` and `val` does not satisfy the
|
||||
/// procedure's result signature.
|
||||
int mgp_result_record_insert(struct mgp_result_record *record, const char *field_name, const struct mgp_value *val);
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate memory to copy the mgp_value to mgp_result_record.
|
||||
/// Return MGP_ERROR_OUT_OF_RANGE if there is no field named `field_name`.
|
||||
/// Return MGP_ERROR_LOGIC_ERROR `val` does not satisfy the type of the field name `field_name`.
|
||||
enum mgp_error mgp_result_record_insert(struct mgp_result_record *record, const char *field_name,
|
||||
const struct mgp_value *val);
|
||||
///@}
|
||||
|
||||
/// @name Graph Constructs
|
||||
@ -453,14 +503,15 @@ struct mgp_property {
|
||||
/// Get the current property pointed to by the iterator.
|
||||
/// When the mgp_properties_iterator_next is invoked, the previous
|
||||
/// mgp_property is invalidated and its value must not be used.
|
||||
/// NULL is returned if the end of the iteration has been reached.
|
||||
const struct mgp_property *mgp_properties_iterator_get(const struct mgp_properties_iterator *it);
|
||||
/// Result is NULL if the end of the iteration has been reached.
|
||||
enum mgp_error mgp_properties_iterator_get(const struct mgp_properties_iterator *it,
|
||||
const struct mgp_property **result);
|
||||
|
||||
/// Advance the iterator to the next property and return it.
|
||||
/// The previous mgp_property obtained through mgp_properties_iterator_get
|
||||
/// will be invalidated, and you must not use its value.
|
||||
/// NULL is returned if the end of the iteration has been reached.
|
||||
const struct mgp_property *mgp_properties_iterator_next(struct mgp_properties_iterator *it);
|
||||
/// Result is NULL if the end of the iteration has been reached.
|
||||
enum mgp_error mgp_properties_iterator_next(struct mgp_properties_iterator *it, const struct mgp_property **result);
|
||||
|
||||
/// Iterator over edges of a vertex.
|
||||
struct mgp_edges_iterator;
|
||||
@ -476,67 +527,70 @@ struct mgp_vertex_id {
|
||||
/// Get the ID of given vertex.
|
||||
/// The ID is only valid for a single query execution, you should never store it
|
||||
/// globally in a query module.
|
||||
struct mgp_vertex_id mgp_vertex_get_id(const struct mgp_vertex *v);
|
||||
enum mgp_error mgp_vertex_get_id(const struct mgp_vertex *v, struct mgp_vertex_id *result);
|
||||
|
||||
/// Copy a mgp_vertex.
|
||||
/// Returned pointer must be freed with mgp_vertex_destroy.
|
||||
/// NULL is returned if unable to allocate a mgp_vertex.
|
||||
struct mgp_vertex *mgp_vertex_copy(const struct mgp_vertex *v, struct mgp_memory *memory);
|
||||
/// Resulting pointer must be freed with mgp_vertex_destroy.
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_vertex.
|
||||
enum mgp_error mgp_vertex_copy(const struct mgp_vertex *v, struct mgp_memory *memory, struct mgp_vertex **result);
|
||||
|
||||
/// Free the memory used by a mgp_vertex.
|
||||
void mgp_vertex_destroy(struct mgp_vertex *v);
|
||||
|
||||
/// Return non-zero if given vertices are equal, otherwise 0.
|
||||
int mgp_vertex_equal(const struct mgp_vertex *v1, const struct mgp_vertex *v2);
|
||||
/// Result is non-zero if given vertices are equal, otherwise 0.
|
||||
enum mgp_error mgp_vertex_equal(const struct mgp_vertex *v1, const struct mgp_vertex *v2, int *result);
|
||||
|
||||
/// Return the number of labels a given vertex has.
|
||||
size_t mgp_vertex_labels_count(const struct mgp_vertex *v);
|
||||
/// Get the number of labels a given vertex has.
|
||||
enum mgp_error mgp_vertex_labels_count(const struct mgp_vertex *v, size_t *result);
|
||||
|
||||
/// Return mgp_label in mgp_vertex at given index.
|
||||
/// If the index is out of bounds, mgp_label.name is set to NULL.
|
||||
struct mgp_label mgp_vertex_label_at(const struct mgp_vertex *v, size_t index);
|
||||
/// Get mgp_label in mgp_vertex at given index.
|
||||
/// Return MGP_ERROR_OUT_OF_RANGE if the index is out of range.
|
||||
enum mgp_error mgp_vertex_label_at(const struct mgp_vertex *v, size_t index, struct mgp_label *result);
|
||||
|
||||
/// Return non-zero if the given vertex has the given label.
|
||||
int mgp_vertex_has_label(const struct mgp_vertex *v, struct mgp_label label);
|
||||
/// Result is non-zero if the given vertex has the given label.
|
||||
enum mgp_error mgp_vertex_has_label(const struct mgp_vertex *v, struct mgp_label label, int *result);
|
||||
|
||||
/// Return non-zero if the given vertex has a label with given name.
|
||||
int mgp_vertex_has_label_named(const struct mgp_vertex *v, const char *label_name);
|
||||
/// Result is non-zero if the given vertex has a label with given name.
|
||||
enum mgp_error mgp_vertex_has_label_named(const struct mgp_vertex *v, const char *label_name, int *result);
|
||||
|
||||
/// Get a copy of a vertex property mapped to a given name.
|
||||
/// Returned value must be freed with mgp_value_destroy.
|
||||
/// NULL is returned if unable to allocate a mgp_value.
|
||||
struct mgp_value *mgp_vertex_get_property(const struct mgp_vertex *v, const char *property_name,
|
||||
struct mgp_memory *memory);
|
||||
/// Resulting value must be freed with mgp_value_destroy.
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_value.
|
||||
enum mgp_error mgp_vertex_get_property(const struct mgp_vertex *v, const char *property_name, struct mgp_memory *memory,
|
||||
struct mgp_value **result);
|
||||
|
||||
/// Start iterating over properties stored in the given vertex.
|
||||
/// The returned mgp_properties_iterator needs to be deallocated with
|
||||
/// The resulting mgp_properties_iterator needs to be deallocated with
|
||||
/// mgp_properties_iterator_destroy.
|
||||
/// NULL is returned if unable to allocate a new iterator.
|
||||
struct mgp_properties_iterator *mgp_vertex_iter_properties(const struct mgp_vertex *v, struct mgp_memory *memory);
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_properties_iterator.
|
||||
enum mgp_error mgp_vertex_iter_properties(const struct mgp_vertex *v, struct mgp_memory *memory,
|
||||
struct mgp_properties_iterator **result);
|
||||
|
||||
/// Start iterating over inbound edges of the given vertex.
|
||||
/// The returned mgp_edges_iterator needs to be deallocated with
|
||||
/// The resulting mgp_edges_iterator needs to be deallocated with
|
||||
/// mgp_edges_iterator_destroy.
|
||||
/// NULL is returned if unable to allocate a new iterator.
|
||||
struct mgp_edges_iterator *mgp_vertex_iter_in_edges(const struct mgp_vertex *v, struct mgp_memory *memory);
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_edges_iterator.
|
||||
enum mgp_error mgp_vertex_iter_in_edges(const struct mgp_vertex *v, struct mgp_memory *memory,
|
||||
struct mgp_edges_iterator **result);
|
||||
|
||||
/// Start iterating over outbound edges of the given vertex.
|
||||
/// The returned mgp_edges_iterator needs to be deallocated with
|
||||
/// mgp_edges_iterator_destroy.
|
||||
/// NULL is returned if unable to allocate a new iterator.
|
||||
struct mgp_edges_iterator *mgp_vertex_iter_out_edges(const struct mgp_vertex *v, struct mgp_memory *memory);
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_edges_iterator.
|
||||
enum mgp_error mgp_vertex_iter_out_edges(const struct mgp_vertex *v, struct mgp_memory *memory,
|
||||
struct mgp_edges_iterator **result);
|
||||
|
||||
/// Get the current edge pointed to by the iterator.
|
||||
/// When the mgp_edges_iterator_next is invoked, the previous
|
||||
/// mgp_edge is invalidated and its value must not be used.
|
||||
/// NULL is returned if the end of the iteration has been reached.
|
||||
const struct mgp_edge *mgp_edges_iterator_get(const struct mgp_edges_iterator *it);
|
||||
/// Result is NULL if the end of the iteration has been reached.
|
||||
enum mgp_error mgp_edges_iterator_get(const struct mgp_edges_iterator *it, const struct mgp_edge **result);
|
||||
|
||||
/// Advance the iterator to the next edge and return it.
|
||||
/// The previous mgp_edge obtained through mgp_edges_iterator_get
|
||||
/// will be invalidated, and you must not use its value.
|
||||
/// NULL is returned if the end of the iteration has been reached.
|
||||
const struct mgp_edge *mgp_edges_iterator_next(struct mgp_edges_iterator *it);
|
||||
/// Result is NULL if the end of the iteration has been reached.
|
||||
enum mgp_error mgp_edges_iterator_next(struct mgp_edges_iterator *it, const struct mgp_edge **result);
|
||||
|
||||
/// ID of an edge; valid during a single query execution.
|
||||
struct mgp_edge_id {
|
||||
@ -546,47 +600,51 @@ struct mgp_edge_id {
|
||||
/// Get the ID of given edge.
|
||||
/// The ID is only valid for a single query execution, you should never store it
|
||||
/// globally in a query module.
|
||||
struct mgp_edge_id mgp_edge_get_id(const struct mgp_edge *e);
|
||||
enum mgp_error mgp_edge_get_id(const struct mgp_edge *e, struct mgp_edge_id *result);
|
||||
|
||||
/// Copy a mgp_edge.
|
||||
/// Returned pointer must be freed with mgp_edge_destroy.
|
||||
/// NULL is returned if unable to allocate a mgp_edge.
|
||||
struct mgp_edge *mgp_edge_copy(const struct mgp_edge *e, struct mgp_memory *memory);
|
||||
/// Resulting pointer must be freed with mgp_edge_destroy.
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_edge.
|
||||
enum mgp_error mgp_edge_copy(const struct mgp_edge *e, struct mgp_memory *memory, struct mgp_edge **result);
|
||||
|
||||
/// Free the memory used by a mgp_edge.
|
||||
void mgp_edge_destroy(struct mgp_edge *e);
|
||||
|
||||
/// Return non-zero if given edges are equal, otherwise 0.
|
||||
int mgp_edge_equal(const struct mgp_edge *e1, const struct mgp_edge *e2);
|
||||
/// Result is non-zero if given edges are equal, otherwise 0.
|
||||
enum mgp_error mgp_edge_equal(const struct mgp_edge *e1, const struct mgp_edge *e2, int *result);
|
||||
|
||||
/// Return the type of the given edge.
|
||||
struct mgp_edge_type mgp_edge_get_type(const struct mgp_edge *e);
|
||||
/// Get the type of the given edge.
|
||||
enum mgp_error mgp_edge_get_type(const struct mgp_edge *e, struct mgp_edge_type *result);
|
||||
|
||||
/// Return the source vertex of the given edge.
|
||||
const struct mgp_vertex *mgp_edge_get_from(const struct mgp_edge *e);
|
||||
/// Get the source vertex of the given edge.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_edge_get_from(const struct mgp_edge *e, const struct mgp_vertex **result);
|
||||
|
||||
/// Return the destination vertex of the given edge.
|
||||
const struct mgp_vertex *mgp_edge_get_to(const struct mgp_edge *e);
|
||||
/// Get the destination vertex of the given edge.
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_edge_get_to(const struct mgp_edge *e, const struct mgp_vertex **result);
|
||||
|
||||
/// Get a copy of a edge property mapped to a given name.
|
||||
/// Returned value must be freed with mgp_value_destroy.
|
||||
/// NULL is returned if unable to allocate a mgp_value.
|
||||
struct mgp_value *mgp_edge_get_property(const struct mgp_edge *e, const char *property_name, struct mgp_memory *memory);
|
||||
/// Resulting value must be freed with mgp_value_destroy.
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_value.
|
||||
enum mgp_error mgp_edge_get_property(const struct mgp_edge *e, const char *property_name, struct mgp_memory *memory,
|
||||
struct mgp_value **result);
|
||||
|
||||
/// Start iterating over properties stored in the given edge.
|
||||
/// The returned mgp_properties_iterator needs to be deallocated with
|
||||
/// Resulting mgp_properties_iterator needs to be deallocated with
|
||||
/// mgp_properties_iterator_destroy.
|
||||
/// NULL is returned if unable to allocate a new iterator.
|
||||
struct mgp_properties_iterator *mgp_edge_iter_properties(const struct mgp_edge *e, struct mgp_memory *memory);
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_properties_iterator.
|
||||
enum mgp_error mgp_edge_iter_properties(const struct mgp_edge *e, struct mgp_memory *memory,
|
||||
struct mgp_properties_iterator **result);
|
||||
|
||||
/// State of the graph database.
|
||||
struct mgp_graph;
|
||||
|
||||
/// Return the vertex corresponding to given ID.
|
||||
/// The returned vertex must be freed using mgp_vertex_destroy.
|
||||
/// NULL is returned if unable to allocate the vertex or if ID is not valid.
|
||||
struct mgp_vertex *mgp_graph_get_vertex_by_id(const struct mgp_graph *g, struct mgp_vertex_id id,
|
||||
struct mgp_memory *memory);
|
||||
/// Resulting vertex must be freed using mgp_vertex_destroy.
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate the vertex or if ID is not valid.
|
||||
enum mgp_error mgp_graph_get_vertex_by_id(const struct mgp_graph *g, struct mgp_vertex_id id, struct mgp_memory *memory,
|
||||
struct mgp_vertex **result);
|
||||
|
||||
/// Iterator over vertices.
|
||||
struct mgp_vertices_iterator;
|
||||
@ -595,22 +653,22 @@ struct mgp_vertices_iterator;
|
||||
void mgp_vertices_iterator_destroy(struct mgp_vertices_iterator *it);
|
||||
|
||||
/// Start iterating over vertices of the given graph.
|
||||
/// The returned mgp_vertices_iterator needs to be deallocated with
|
||||
/// mgp_vertices_iterator_destroy.
|
||||
/// NULL is returned if unable to allocate a new iterator.
|
||||
struct mgp_vertices_iterator *mgp_graph_iter_vertices(const struct mgp_graph *g, struct mgp_memory *memory);
|
||||
/// Resulting mgp_vertices_iterator needs to be deallocated with mgp_vertices_iterator_destroy.
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_vertices_iterator.
|
||||
enum mgp_error mgp_graph_iter_vertices(const struct mgp_graph *g, struct mgp_memory *memory,
|
||||
struct mgp_vertices_iterator **result);
|
||||
|
||||
/// Get the current vertex pointed to by the iterator.
|
||||
/// When the mgp_vertices_iterator_next is invoked, the previous
|
||||
/// mgp_vertex is invalidated and its value must not be used.
|
||||
/// NULL is returned if the end of the iteration has been reached.
|
||||
const struct mgp_vertex *mgp_vertices_iterator_get(const struct mgp_vertices_iterator *it);
|
||||
/// Result is NULL if the end of the iteration has been reached.
|
||||
enum mgp_error mgp_vertices_iterator_get(const struct mgp_vertices_iterator *it, const struct mgp_vertex **result);
|
||||
|
||||
/// Advance the iterator to the next vertex and return it.
|
||||
/// The previous mgp_vertex obtained through mgp_vertices_iterator_get
|
||||
/// will be invalidated, and you must not use its value.
|
||||
/// NULL is returned if the end of the iteration has been reached.
|
||||
const struct mgp_vertex *mgp_vertices_iterator_next(struct mgp_vertices_iterator *it);
|
||||
/// Result is NULL if the end of the iteration has been reached.
|
||||
enum mgp_error mgp_vertices_iterator_next(struct mgp_vertices_iterator *it, const struct mgp_vertex **result);
|
||||
///@}
|
||||
|
||||
/// @name Type System
|
||||
@ -628,24 +686,30 @@ struct mgp_type;
|
||||
/// Get the type representing any value that isn't `null`.
|
||||
///
|
||||
/// The ANY type is the parent type of all types.
|
||||
const struct mgp_type *mgp_type_any();
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate the new type.
|
||||
enum mgp_error mgp_type_any(const struct mgp_type **result);
|
||||
|
||||
/// Get the type representing boolean values.
|
||||
const struct mgp_type *mgp_type_bool();
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate the new type.
|
||||
enum mgp_error mgp_type_bool(const struct mgp_type **result);
|
||||
|
||||
/// Get the type representing character string values.
|
||||
const struct mgp_type *mgp_type_string();
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate the new type.
|
||||
enum mgp_error mgp_type_string(const struct mgp_type **result);
|
||||
|
||||
/// Get the type representing integer values.
|
||||
const struct mgp_type *mgp_type_int();
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate the new type.
|
||||
enum mgp_error mgp_type_int(const struct mgp_type **result);
|
||||
|
||||
/// Get the type representing floating-point values.
|
||||
const struct mgp_type *mgp_type_float();
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate the new type.
|
||||
enum mgp_error mgp_type_float(const struct mgp_type **result);
|
||||
|
||||
/// Get the type representing any number value.
|
||||
///
|
||||
/// This is the parent type for numeric types, i.e. INTEGER and FLOAT.
|
||||
const struct mgp_type *mgp_type_number();
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate the new type.
|
||||
enum mgp_error mgp_type_number(const struct mgp_type **result);
|
||||
|
||||
/// Get the type representing map values.
|
||||
///
|
||||
@ -656,32 +720,36 @@ const struct mgp_type *mgp_type_number();
|
||||
///
|
||||
/// @sa mgp_type_node
|
||||
/// @sa mgp_type_relationship
|
||||
const struct mgp_type *mgp_type_map();
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate the new type.
|
||||
enum mgp_error mgp_type_map(const struct mgp_type **result);
|
||||
|
||||
/// Get the type representing graph node values.
|
||||
///
|
||||
/// Since a node contains a map of properties, the node itself is also of MAP
|
||||
/// type.
|
||||
const struct mgp_type *mgp_type_node();
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate the new type.
|
||||
enum mgp_error mgp_type_node(const struct mgp_type **result);
|
||||
|
||||
/// Get the type representing graph relationship values.
|
||||
///
|
||||
/// Since a relationship contains a map of properties, the relationship itself
|
||||
/// is also of MAP type.
|
||||
const struct mgp_type *mgp_type_relationship();
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate the new type.
|
||||
enum mgp_error mgp_type_relationship(const struct mgp_type **result);
|
||||
|
||||
/// Get the type representing a graph path (walk) from one node to another.
|
||||
const struct mgp_type *mgp_type_path();
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate the new type.
|
||||
enum mgp_error mgp_type_path(const struct mgp_type **result);
|
||||
|
||||
/// Build a type representing a list of values of given `element_type`.
|
||||
///
|
||||
/// NULL is returned if unable to allocate the new type.
|
||||
const struct mgp_type *mgp_type_list(const struct mgp_type *element_type);
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate the new type.
|
||||
enum mgp_error mgp_type_list(const struct mgp_type *element_type, const struct mgp_type **result);
|
||||
|
||||
/// Build a type representing either a `null` value or a value of given `type`.
|
||||
///
|
||||
/// NULL is returned if unable to allocate the new type.
|
||||
const struct mgp_type *mgp_type_nullable(const struct mgp_type *type);
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate the new type.
|
||||
enum mgp_error mgp_type_nullable(const struct mgp_type *type, const struct mgp_type **result);
|
||||
///@}
|
||||
|
||||
/// @name Query Module & Procedures
|
||||
@ -719,9 +787,11 @@ typedef void (*mgp_proc_cb)(const struct mgp_list *, const struct mgp_graph *, s
|
||||
/// Note that Unicode characters are not allowed. Additionally, names are
|
||||
/// case-sensitive.
|
||||
///
|
||||
/// NULL is returned if unable to allocate memory for mgp_proc; if `name` is
|
||||
/// not valid or a procedure with the same name was already registered.
|
||||
struct mgp_proc *mgp_module_add_read_procedure(struct mgp_module *module, const char *name, mgp_proc_cb cb);
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate memory for mgp_proc.
|
||||
/// Return MGP_ERROR_INVALID_ARGUMENT if `name` is not a valid procedure name.
|
||||
/// RETURN MGP_ERROR_LOGIC_ERROR if a procedure with the same name was already registered.
|
||||
enum mgp_error mgp_module_add_read_procedure(struct mgp_module *module, const char *name, mgp_proc_cb cb,
|
||||
struct mgp_proc **result);
|
||||
|
||||
/// Add a required argument to a procedure.
|
||||
///
|
||||
@ -734,10 +804,10 @@ struct mgp_proc *mgp_module_add_read_procedure(struct mgp_module *module, const
|
||||
///
|
||||
/// Passed in `type` describes what kind of values can be used as the argument.
|
||||
///
|
||||
/// 0 is returned if unable to allocate memory for an argument; if invoking this
|
||||
/// function after setting an optional argument or if `name` is not valid.
|
||||
/// Non-zero is returned on success.
|
||||
int mgp_proc_add_arg(struct mgp_proc *proc, const char *name, const struct mgp_type *type);
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate memory for an argument.
|
||||
/// Return MGP_ERROR_INVALID_ARGUMENT if `name` is not a valid argument name.
|
||||
/// RETURN MGP_ERROR_LOGIC_ERROR if the procedure already has any optional argument.
|
||||
enum mgp_error mgp_proc_add_arg(struct mgp_proc *proc, const char *name, const struct mgp_type *type);
|
||||
|
||||
/// Add an optional argument with a default value to a procedure.
|
||||
///
|
||||
@ -757,11 +827,12 @@ int mgp_proc_add_arg(struct mgp_proc *proc, const char *name, const struct mgp_t
|
||||
/// a graph element (node, relationship, path) and it must satisfy the given
|
||||
/// `type`.
|
||||
///
|
||||
/// 0 is returned if unable to allocate memory for an argument; if `name` is
|
||||
/// not valid or `default_value` does not satisfy `type`. Non-zero is returned
|
||||
/// on success.
|
||||
int mgp_proc_add_opt_arg(struct mgp_proc *proc, const char *name, const struct mgp_type *type,
|
||||
const struct mgp_value *default_value);
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate memory for an argument.
|
||||
/// Return MGP_ERROR_INVALID_ARGUMENT if `name` is not a valid argument name.
|
||||
/// RETURN MGP_ERROR_OUT_OF_RANGE if `default_value` is a graph element (vertex, edge or path).
|
||||
/// RETURN MGP_ERROR_LOGIC_ERROR if `default_value` does not satisfy `type`.
|
||||
enum mgp_error mgp_proc_add_opt_arg(struct mgp_proc *proc, const char *name, const struct mgp_type *type,
|
||||
const struct mgp_value *default_value);
|
||||
|
||||
/// Add a result field to a procedure.
|
||||
///
|
||||
@ -771,16 +842,20 @@ int mgp_proc_add_opt_arg(struct mgp_proc *proc, const char *name, const struct m
|
||||
/// Passed in `type` describes what kind of values can be returned through the
|
||||
/// result field.
|
||||
///
|
||||
/// 0 is returned if unable to allocate memory for a result field; if
|
||||
/// `name` is not valid or if a result field with the same name was already
|
||||
/// added. Non-zero is returned on success.
|
||||
int mgp_proc_add_result(struct mgp_proc *proc, const char *name, const struct mgp_type *type);
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate memory for an argument.
|
||||
/// Return MGP_ERROR_INVALID_ARGUMENT if `name` is not a valid result name.
|
||||
/// RETURN MGP_ERROR_LOGIC_ERROR if a result field with the same name was already added.
|
||||
enum mgp_error mgp_proc_add_result(struct mgp_proc *proc, const char *name, const struct mgp_type *type);
|
||||
|
||||
/// Add a result field to a procedure and mark it as deprecated.
|
||||
///
|
||||
/// This is the same as mgp_proc_add_result, but the result field will be marked
|
||||
/// as deprecated.
|
||||
int mgp_proc_add_deprecated_result(struct mgp_proc *proc, const char *name, const struct mgp_type *type);
|
||||
///
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate memory for an argument.
|
||||
/// Return MGP_ERROR_INVALID_ARGUMENT if `name` is not a valid result name.
|
||||
/// RETURN MGP_ERROR_LOGIC_ERROR if a result field with the same name was already added.
|
||||
enum mgp_error mgp_proc_add_deprecated_result(struct mgp_proc *proc, const char *name, const struct mgp_type *type);
|
||||
///@}
|
||||
|
||||
/// @name Execution
|
||||
@ -817,28 +892,29 @@ struct mgp_messages;
|
||||
/// Payload is not null terminated and not a string but rather a byte array.
|
||||
/// You need to call mgp_message_payload_size() first, to read the size of
|
||||
/// the payload.
|
||||
const char *mgp_message_payload(const struct mgp_message *);
|
||||
enum mgp_error mgp_message_payload(const struct mgp_message *message, const char **result);
|
||||
|
||||
/// Return the payload size
|
||||
size_t mgp_message_payload_size(const struct mgp_message *);
|
||||
enum mgp_error mgp_message_payload_size(const struct mgp_message *message, size_t *result);
|
||||
|
||||
/// Return the name of topic
|
||||
const char *mgp_message_topic_name(const struct mgp_message *);
|
||||
enum mgp_error mgp_message_topic_name(const struct mgp_message *message, const char **result);
|
||||
|
||||
/// Return the key of mgp_message as a byte array
|
||||
const char *mgp_message_key(const struct mgp_message *);
|
||||
enum mgp_error mgp_message_key(const struct mgp_message *message, const char **result);
|
||||
|
||||
/// Return the key size of mgp_message
|
||||
size_t mgp_message_key_size(const struct mgp_message *);
|
||||
enum mgp_error mgp_message_key_size(const struct mgp_message *message, size_t *result);
|
||||
|
||||
/// Return the timestamp of mgp_message as a byte array
|
||||
int64_t mgp_message_timestamp(const struct mgp_message *);
|
||||
enum mgp_error mgp_message_timestamp(const struct mgp_message *message, int64_t *result);
|
||||
|
||||
/// Return the number of messages contained in the mgp_messages list
|
||||
size_t mgp_messages_size(const struct mgp_messages *);
|
||||
/// Current implementation always returns without errors.
|
||||
enum mgp_error mgp_messages_size(const struct mgp_messages *message, size_t *result);
|
||||
|
||||
/// Return the message from a messages list at given index
|
||||
const struct mgp_message *mgp_messages_at(const struct mgp_messages *, size_t);
|
||||
enum mgp_error mgp_messages_at(const struct mgp_messages *message, size_t index, const struct mgp_message **result);
|
||||
|
||||
/// Entry-point for a module transformation, invoked through a stream transformation.
|
||||
///
|
||||
@ -848,9 +924,17 @@ const struct mgp_message *mgp_messages_at(const struct mgp_messages *, size_t);
|
||||
typedef void (*mgp_trans_cb)(const struct mgp_messages *, const struct mgp_graph *, struct mgp_result *,
|
||||
struct mgp_memory *);
|
||||
|
||||
/// Adds a transformation cb to the module pointed by mgp_module.
|
||||
/// Return non-zero if the transformation is added successfully.
|
||||
int mgp_module_add_transformation(struct mgp_module *module, const char *name, mgp_trans_cb cb);
|
||||
/// Register a transformation with a module.
|
||||
///
|
||||
/// The `name` must be a sequence of digits, underscores, lowercase and
|
||||
/// uppercase Latin letters. The name must begin with a non-digit character.
|
||||
/// Note that Unicode characters are not allowed. Additionally, names are
|
||||
/// case-sensitive.
|
||||
///
|
||||
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate memory for transformation.
|
||||
/// Return MGP_ERROR_INVALID_ARGUMENT if `name` is not a valid transformation name.
|
||||
/// RETURN MGP_ERROR_LOGIC_ERROR if a transformation with the same name was already registered.
|
||||
enum mgp_error mgp_module_add_transformation(struct mgp_module *module, const char *name, mgp_trans_cb cb);
|
||||
/// @}
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -16,61 +16,101 @@
|
||||
// CALL example.procedure(1, 2) YIELD args, result;
|
||||
// CALL example.procedure(1) YIELD args, result;
|
||||
// Naturally, you may pass in different arguments or yield less fields.
|
||||
static void procedure(const struct mgp_list *args,
|
||||
const struct mgp_graph *graph, struct mgp_result *result,
|
||||
static void procedure(const struct mgp_list *args, const struct mgp_graph *graph, struct mgp_result *result,
|
||||
struct mgp_memory *memory) {
|
||||
struct mgp_list *args_copy = mgp_list_make_empty(mgp_list_size(args), memory);
|
||||
if (args_copy == NULL) goto error_memory;
|
||||
for (size_t i = 0; i < mgp_list_size(args); ++i) {
|
||||
int success = mgp_list_append(args_copy, mgp_list_at(args, i));
|
||||
if (!success) goto error_free_list;
|
||||
size_t args_size = 0;
|
||||
if (mgp_list_size(args, &args_size) != MGP_ERROR_NO_ERROR) {
|
||||
goto error_something_went_wrong;
|
||||
}
|
||||
struct mgp_list *args_copy = NULL;
|
||||
if (mgp_list_make_empty(args_size, memory, &args_copy) != MGP_ERROR_NO_ERROR) {
|
||||
goto error_something_went_wrong;
|
||||
}
|
||||
for (size_t i = 0; i < args_size; ++i) {
|
||||
const struct mgp_value *value = NULL;
|
||||
if (mgp_list_at(args, i, &value) != MGP_ERROR_NO_ERROR) {
|
||||
goto error_free_list;
|
||||
}
|
||||
if (mgp_list_append(args_copy, value) != MGP_ERROR_NO_ERROR) {
|
||||
goto error_free_list;
|
||||
}
|
||||
}
|
||||
struct mgp_result_record *record = NULL;
|
||||
if (mgp_result_new_record(result, &record) != MGP_ERROR_NO_ERROR) {
|
||||
goto error_free_list;
|
||||
}
|
||||
struct mgp_result_record *record = mgp_result_new_record(result);
|
||||
if (record == NULL) goto error_free_list;
|
||||
// Transfer ownership of args_copy to mgp_value.
|
||||
struct mgp_value *args_value = mgp_value_make_list(args_copy);
|
||||
if (args_value == NULL) goto error_free_list;
|
||||
int args_inserted = mgp_result_record_insert(record, "args", args_value);
|
||||
struct mgp_value *args_value = NULL;
|
||||
if (mgp_value_make_list(args_copy, &args_value) != MGP_ERROR_NO_ERROR) {
|
||||
goto error_free_list;
|
||||
}
|
||||
// Release `args_value` and contained `args_copy`.
|
||||
if (mgp_result_record_insert(record, "args", args_value) != MGP_ERROR_NO_ERROR) {
|
||||
mgp_value_destroy(args_value);
|
||||
goto error_something_went_wrong;
|
||||
}
|
||||
mgp_value_destroy(args_value);
|
||||
if (!args_inserted) goto error_memory;
|
||||
struct mgp_value *hello_world_value =
|
||||
mgp_value_make_string("Hello World!", memory);
|
||||
if (hello_world_value == NULL) goto error_memory;
|
||||
int result_inserted =
|
||||
mgp_result_record_insert(record, "result", hello_world_value);
|
||||
struct mgp_value *hello_world_value = NULL;
|
||||
if (mgp_value_make_string("Hello World!", memory, &hello_world_value) != MGP_ERROR_NO_ERROR) {
|
||||
goto error_something_went_wrong;
|
||||
}
|
||||
enum mgp_error insert_result = mgp_result_record_insert(record, "result", hello_world_value);
|
||||
mgp_value_destroy(hello_world_value);
|
||||
if (!result_inserted) goto error_memory;
|
||||
if (insert_result != MGP_ERROR_NO_ERROR) {
|
||||
goto error_something_went_wrong;
|
||||
}
|
||||
// We have successfully finished, so return without error reporting.
|
||||
return;
|
||||
|
||||
error_free_list:
|
||||
mgp_list_destroy(args_copy);
|
||||
error_memory:
|
||||
mgp_result_set_error_msg(result, "Not enough memory!");
|
||||
error_something_went_wrong:
|
||||
mgp_result_set_error_msg(result, "Something went wrong!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Each module needs to define mgp_init_module function.
|
||||
// Here you can register multiple procedures your module supports.
|
||||
int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) {
|
||||
struct mgp_proc *proc =
|
||||
mgp_module_add_read_procedure(module, "procedure", procedure);
|
||||
if (!proc) return 1;
|
||||
if (!mgp_proc_add_arg(proc, "required_arg",
|
||||
mgp_type_nullable(mgp_type_any())))
|
||||
struct mgp_proc *proc = NULL;
|
||||
if (mgp_module_add_read_procedure(module, "procedure", procedure, &proc) != MGP_ERROR_NO_ERROR) {
|
||||
return 1;
|
||||
struct mgp_value *null_value = mgp_value_make_null(memory);
|
||||
if (!mgp_proc_add_opt_arg(proc, "optional_arg",
|
||||
mgp_type_nullable(mgp_type_any()), null_value)) {
|
||||
}
|
||||
const struct mgp_type *any_type = NULL;
|
||||
if (mgp_type_any(&any_type) != MGP_ERROR_NO_ERROR) {
|
||||
return 1;
|
||||
}
|
||||
const struct mgp_type *nullable_any_type = NULL;
|
||||
if (mgp_type_nullable(any_type, &nullable_any_type) != MGP_ERROR_NO_ERROR) {
|
||||
return 1;
|
||||
}
|
||||
if (mgp_proc_add_arg(proc, "required_arg", nullable_any_type) != MGP_ERROR_NO_ERROR) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct mgp_value *null_value = NULL;
|
||||
if (mgp_value_make_null(memory, &null_value) != MGP_ERROR_NO_ERROR) {
|
||||
return 1;
|
||||
}
|
||||
if (mgp_proc_add_opt_arg(proc, "optional_arg", nullable_any_type, null_value) != MGP_ERROR_NO_ERROR) {
|
||||
mgp_value_destroy(null_value);
|
||||
return 1;
|
||||
}
|
||||
mgp_value_destroy(null_value);
|
||||
if (!mgp_proc_add_result(proc, "result", mgp_type_string())) return 1;
|
||||
if (!mgp_proc_add_result(proc, "args",
|
||||
mgp_type_list(mgp_type_nullable(mgp_type_any()))))
|
||||
const struct mgp_type *string = NULL;
|
||||
if (mgp_type_string(&string) != MGP_ERROR_NO_ERROR) {
|
||||
return 1;
|
||||
}
|
||||
if (mgp_proc_add_result(proc, "result", string) != MGP_ERROR_NO_ERROR) {
|
||||
return 1;
|
||||
}
|
||||
const struct mgp_type *list_of_anything = NULL;
|
||||
if (mgp_type_list(nullable_any_type, &list_of_anything) != MGP_ERROR_NO_ERROR) {
|
||||
return 1;
|
||||
}
|
||||
if (mgp_proc_add_result(proc, "args", list_of_anything)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -229,13 +229,13 @@ void Consumer::Check(std::optional<std::chrono::milliseconds> timeout, std::opti
|
||||
utils::OnScopeExit restore_is_running([this] { is_running_.store(false); });
|
||||
|
||||
if (last_assignment_.empty()) {
|
||||
if (auto err = consumer_->assignment(last_assignment_); err != RdKafka::ERR_NO_ERROR) {
|
||||
if (const auto err = consumer_->assignment(last_assignment_); err != RdKafka::ERR_NO_ERROR) {
|
||||
spdlog::warn("Saving the commited offset of consumer {} failed: {}", info_.consumer_name, RdKafka::err2str(err));
|
||||
throw ConsumerCheckFailedException(info_.consumer_name,
|
||||
fmt::format("Couldn't save commited offsets: '{}'", RdKafka::err2str(err)));
|
||||
}
|
||||
} else {
|
||||
if (auto err = consumer_->assign(last_assignment_); err != RdKafka::ERR_NO_ERROR) {
|
||||
if (const auto err = consumer_->assign(last_assignment_); err != RdKafka::ERR_NO_ERROR) {
|
||||
throw ConsumerCheckFailedException(info_.consumer_name,
|
||||
fmt::format("Couldn't restore commited offsets: '{}'", RdKafka::err2str(err)));
|
||||
}
|
||||
@ -300,7 +300,7 @@ void Consumer::StartConsuming() {
|
||||
is_running_.store(true);
|
||||
|
||||
if (!last_assignment_.empty()) {
|
||||
if (auto err = consumer_->assign(last_assignment_); err != RdKafka::ERR_NO_ERROR) {
|
||||
if (const auto err = consumer_->assign(last_assignment_); err != RdKafka::ERR_NO_ERROR) {
|
||||
throw ConsumerStartFailedException(info_.consumer_name,
|
||||
fmt::format("Couldn't restore commited offsets: '{}'", RdKafka::err2str(err)));
|
||||
}
|
||||
@ -328,7 +328,7 @@ void Consumer::StartConsuming() {
|
||||
|
||||
try {
|
||||
consumer_function_(batch);
|
||||
if (auto err = consumer_->commitSync(); err != RdKafka::ERR_NO_ERROR) {
|
||||
if (const auto err = consumer_->commitSync(); err != RdKafka::ERR_NO_ERROR) {
|
||||
spdlog::warn("Committing offset of consumer {} failed: {}", info_.consumer_name, RdKafka::err2str(err));
|
||||
break;
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ struct ExecutionContext {
|
||||
static_assert(std::is_move_assignable_v<ExecutionContext>, "ExecutionContext must be move assignable!");
|
||||
static_assert(std::is_move_constructible_v<ExecutionContext>, "ExecutionContext must be move constructible!");
|
||||
|
||||
inline bool MustAbort(const ExecutionContext &context) {
|
||||
inline bool MustAbort(const ExecutionContext &context) noexcept {
|
||||
return (context.is_shutting_down != nullptr && context.is_shutting_down->load(std::memory_order_acquire)) ||
|
||||
context.timer.IsExpired();
|
||||
}
|
||||
|
@ -73,11 +73,11 @@ class EdgeAccessor final {
|
||||
|
||||
int64_t CypherId() const { return impl_.Gid().AsInt(); }
|
||||
|
||||
auto Gid() const { return impl_.Gid(); }
|
||||
storage::Gid Gid() const noexcept { return impl_.Gid(); }
|
||||
|
||||
bool operator==(const EdgeAccessor &e) const { return impl_ == e.impl_; }
|
||||
bool operator==(const EdgeAccessor &e) const noexcept { return impl_ == e.impl_; }
|
||||
|
||||
bool operator!=(const EdgeAccessor &e) const { return !(*this == e); }
|
||||
bool operator!=(const EdgeAccessor &e) const noexcept { return !(*this == e); }
|
||||
};
|
||||
|
||||
class VertexAccessor final {
|
||||
@ -87,7 +87,7 @@ class VertexAccessor final {
|
||||
static EdgeAccessor MakeEdgeAccessor(const storage::EdgeAccessor impl) { return EdgeAccessor(impl); }
|
||||
|
||||
public:
|
||||
explicit VertexAccessor(storage::VertexAccessor impl) : impl_(std::move(impl)) {}
|
||||
explicit VertexAccessor(storage::VertexAccessor impl) : impl_(impl) {}
|
||||
|
||||
bool IsVisible(storage::View view) const { return impl_.IsVisible(view); }
|
||||
|
||||
@ -158,11 +158,14 @@ class VertexAccessor final {
|
||||
|
||||
int64_t CypherId() const { return impl_.Gid().AsInt(); }
|
||||
|
||||
auto Gid() const { return impl_.Gid(); }
|
||||
storage::Gid Gid() const noexcept { return impl_.Gid(); }
|
||||
|
||||
bool operator==(const VertexAccessor &v) const { return impl_ == v.impl_; }
|
||||
bool operator==(const VertexAccessor &v) const noexcept {
|
||||
static_assert(noexcept(impl_ == v.impl_));
|
||||
return impl_ == v.impl_;
|
||||
}
|
||||
|
||||
bool operator!=(const VertexAccessor &v) const { return !(*this == v); }
|
||||
bool operator!=(const VertexAccessor &v) const noexcept { return !(*this == v); }
|
||||
};
|
||||
|
||||
inline VertexAccessor EdgeAccessor::To() const { return VertexAccessor(impl_.ToVertex()); }
|
||||
|
@ -3601,7 +3601,7 @@ std::unordered_map<std::string, int64_t> CallProcedure::GetAndResetCounters() {
|
||||
namespace {
|
||||
|
||||
void CallCustomProcedure(const std::string_view &fully_qualified_procedure_name, const mgp_proc &proc,
|
||||
const std::vector<Expression *> &args, const mgp_graph &graph, ExpressionEvaluator *evaluator,
|
||||
const std::vector<Expression *> &args, mgp_graph &graph, ExpressionEvaluator *evaluator,
|
||||
utils::MemoryResource *memory, std::optional<size_t> memory_limit, mgp_result *result) {
|
||||
static_assert(std::uses_allocator_v<mgp_value, utils::Allocator<mgp_value>>,
|
||||
"Expected mgp_value to use custom allocator and makes STL "
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
#include "query/procedure/mg_procedure_helpers.hpp"
|
||||
#include "query/typed_value.hpp"
|
||||
#include "utils/memory.hpp"
|
||||
#include "utils/pmr/string.hpp"
|
||||
@ -50,7 +51,7 @@ class AnyType : public CypherType {
|
||||
public:
|
||||
std::string_view GetPresentableName() const override { return "ANY"; }
|
||||
|
||||
bool SatisfiesType(const mgp_value &value) const override { return !mgp_value_is_null(&value); }
|
||||
bool SatisfiesType(const mgp_value &value) const override { return !CallBool(mgp_value_is_null, &value); }
|
||||
|
||||
bool SatisfiesType(const query::TypedValue &value) const override { return !value.IsNull(); }
|
||||
};
|
||||
@ -59,7 +60,7 @@ class BoolType : public CypherType {
|
||||
public:
|
||||
std::string_view GetPresentableName() const override { return "BOOLEAN"; }
|
||||
|
||||
bool SatisfiesType(const mgp_value &value) const override { return mgp_value_is_bool(&value); }
|
||||
bool SatisfiesType(const mgp_value &value) const override { return CallBool(mgp_value_is_bool, &value); }
|
||||
|
||||
bool SatisfiesType(const query::TypedValue &value) const override { return value.IsBool(); }
|
||||
};
|
||||
@ -68,7 +69,7 @@ class StringType : public CypherType {
|
||||
public:
|
||||
std::string_view GetPresentableName() const override { return "STRING"; }
|
||||
|
||||
bool SatisfiesType(const mgp_value &value) const override { return mgp_value_is_string(&value); }
|
||||
bool SatisfiesType(const mgp_value &value) const override { return CallBool(mgp_value_is_string, &value); }
|
||||
|
||||
bool SatisfiesType(const query::TypedValue &value) const override { return value.IsString(); }
|
||||
};
|
||||
@ -77,7 +78,7 @@ class IntType : public CypherType {
|
||||
public:
|
||||
std::string_view GetPresentableName() const override { return "INTEGER"; }
|
||||
|
||||
bool SatisfiesType(const mgp_value &value) const override { return mgp_value_is_int(&value); }
|
||||
bool SatisfiesType(const mgp_value &value) const override { return CallBool(mgp_value_is_int, &value); }
|
||||
|
||||
bool SatisfiesType(const query::TypedValue &value) const override { return value.IsInt(); }
|
||||
};
|
||||
@ -86,7 +87,7 @@ class FloatType : public CypherType {
|
||||
public:
|
||||
std::string_view GetPresentableName() const override { return "FLOAT"; }
|
||||
|
||||
bool SatisfiesType(const mgp_value &value) const override { return mgp_value_is_double(&value); }
|
||||
bool SatisfiesType(const mgp_value &value) const override { return CallBool(mgp_value_is_double, &value); }
|
||||
|
||||
bool SatisfiesType(const query::TypedValue &value) const override { return value.IsDouble(); }
|
||||
};
|
||||
@ -96,7 +97,7 @@ class NumberType : public CypherType {
|
||||
std::string_view GetPresentableName() const override { return "NUMBER"; }
|
||||
|
||||
bool SatisfiesType(const mgp_value &value) const override {
|
||||
return mgp_value_is_int(&value) || mgp_value_is_double(&value);
|
||||
return CallBool(mgp_value_is_int, &value) || CallBool(mgp_value_is_double, &value);
|
||||
}
|
||||
|
||||
bool SatisfiesType(const query::TypedValue &value) const override { return value.IsInt() || value.IsDouble(); }
|
||||
@ -106,7 +107,7 @@ class NodeType : public CypherType {
|
||||
public:
|
||||
std::string_view GetPresentableName() const override { return "NODE"; }
|
||||
|
||||
bool SatisfiesType(const mgp_value &value) const override { return mgp_value_is_vertex(&value); }
|
||||
bool SatisfiesType(const mgp_value &value) const override { return CallBool(mgp_value_is_vertex, &value); }
|
||||
|
||||
bool SatisfiesType(const query::TypedValue &value) const override { return value.IsVertex(); }
|
||||
};
|
||||
@ -115,7 +116,7 @@ class RelationshipType : public CypherType {
|
||||
public:
|
||||
std::string_view GetPresentableName() const override { return "RELATIONSHIP"; }
|
||||
|
||||
bool SatisfiesType(const mgp_value &value) const override { return mgp_value_is_edge(&value); }
|
||||
bool SatisfiesType(const mgp_value &value) const override { return CallBool(mgp_value_is_edge, &value); }
|
||||
|
||||
bool SatisfiesType(const query::TypedValue &value) const override { return value.IsEdge(); }
|
||||
};
|
||||
@ -124,7 +125,7 @@ class PathType : public CypherType {
|
||||
public:
|
||||
std::string_view GetPresentableName() const override { return "PATH"; }
|
||||
|
||||
bool SatisfiesType(const mgp_value &value) const override { return mgp_value_is_path(&value); }
|
||||
bool SatisfiesType(const mgp_value &value) const override { return CallBool(mgp_value_is_path, &value); }
|
||||
|
||||
bool SatisfiesType(const query::TypedValue &value) const override { return value.IsPath(); }
|
||||
};
|
||||
@ -141,7 +142,8 @@ class MapType : public CypherType {
|
||||
std::string_view GetPresentableName() const override { return "MAP"; }
|
||||
|
||||
bool SatisfiesType(const mgp_value &value) const override {
|
||||
return mgp_value_is_map(&value) || mgp_value_is_vertex(&value) || mgp_value_is_edge(&value);
|
||||
return CallBool(mgp_value_is_map, &value) || CallBool(mgp_value_is_vertex, &value) ||
|
||||
CallBool(mgp_value_is_edge, &value);
|
||||
}
|
||||
|
||||
bool SatisfiesType(const query::TypedValue &value) const override {
|
||||
@ -166,10 +168,15 @@ class ListType : public CypherType {
|
||||
std::string_view GetPresentableName() const override { return presentable_name_; }
|
||||
|
||||
bool SatisfiesType(const mgp_value &value) const override {
|
||||
if (!mgp_value_is_list(&value)) return false;
|
||||
const auto *list = mgp_value_get_list(&value);
|
||||
for (size_t i = 0; i < mgp_list_size(list); ++i) {
|
||||
if (!element_type_->SatisfiesType(*mgp_list_at(list, i))) return false;
|
||||
if (!CallBool(mgp_value_is_list, &value)) {
|
||||
return false;
|
||||
}
|
||||
auto *list = Call<const mgp_list *>(mgp_value_get_list, &value);
|
||||
const auto list_size = Call<size_t>(mgp_list_size, list);
|
||||
for (size_t i = 0; i < list_size; ++i) {
|
||||
if (!element_type_->SatisfiesType(*Call<const mgp_value *>(mgp_list_at, list, i))) {
|
||||
return false;
|
||||
};
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -228,7 +235,7 @@ class NullableType : public CypherType {
|
||||
std::string_view GetPresentableName() const override { return presentable_name_; }
|
||||
|
||||
bool SatisfiesType(const mgp_value &value) const override {
|
||||
return mgp_value_is_null(&value) || type_->SatisfiesType(value);
|
||||
return CallBool(mgp_value_is_null, &value) || type_->SatisfiesType(value);
|
||||
}
|
||||
|
||||
bool SatisfiesType(const query::TypedValue &value) const override {
|
||||
|
37
src/query/procedure/mg_procedure_helpers.hpp
Normal file
37
src/query/procedure/mg_procedure_helpers.hpp
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "mg_procedure.h"
|
||||
|
||||
namespace query::procedure {
|
||||
template <typename TResult, typename TFunc, typename... TArgs>
|
||||
TResult Call(TFunc func, TArgs... args) {
|
||||
static_assert(std::is_trivially_copyable_v<TFunc>);
|
||||
static_assert((std::is_trivially_copyable_v<std::remove_reference_t<TArgs>> && ...));
|
||||
TResult result{};
|
||||
MG_ASSERT(func(args..., &result) == MGP_ERROR_NO_ERROR);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename TFunc, typename... TArgs>
|
||||
bool CallBool(TFunc func, TArgs... args) {
|
||||
return Call<int>(func, args...) != 0;
|
||||
}
|
||||
|
||||
template <typename TObj>
|
||||
using MgpRawObjectDeleter = void (*)(TObj *);
|
||||
|
||||
template <typename TObj>
|
||||
using MgpUniquePtr = std::unique_ptr<TObj, MgpRawObjectDeleter<TObj>>;
|
||||
|
||||
template <typename TObj, typename TFunc, typename... TArgs>
|
||||
mgp_error CreateMgpObject(MgpUniquePtr<TObj> &obj, TFunc func, TArgs &&...args) {
|
||||
TObj *raw_obj{nullptr};
|
||||
const auto err = func(std::forward<TArgs>(args)..., &raw_obj);
|
||||
obj.reset(raw_obj);
|
||||
return err;
|
||||
}
|
||||
} // namespace query::procedure
|
File diff suppressed because it is too large
Load Diff
@ -221,6 +221,9 @@ struct mgp_vertex {
|
||||
mgp_vertex &operator=(const mgp_vertex &) = delete;
|
||||
mgp_vertex &operator=(mgp_vertex &&) = delete;
|
||||
|
||||
bool operator==(const mgp_vertex &other) const noexcept { return this->impl == other.impl; }
|
||||
bool operator!=(const mgp_vertex &other) const noexcept { return !(*this == other); };
|
||||
|
||||
~mgp_vertex() = default;
|
||||
|
||||
utils::MemoryResource *GetMemoryResource() const noexcept { return memory; }
|
||||
@ -257,9 +260,11 @@ struct mgp_edge {
|
||||
|
||||
mgp_edge &operator=(const mgp_edge &) = delete;
|
||||
mgp_edge &operator=(mgp_edge &&) = delete;
|
||||
|
||||
~mgp_edge() = default;
|
||||
|
||||
bool operator==(const mgp_edge &other) const noexcept { return this->impl == other.impl; }
|
||||
bool operator!=(const mgp_edge &other) const noexcept { return !(*this == other); };
|
||||
|
||||
utils::MemoryResource *GetMemoryResource() const noexcept { return memory; }
|
||||
|
||||
utils::MemoryResource *memory;
|
||||
@ -512,7 +517,7 @@ struct mgp_trans {
|
||||
utils::pmr::map<utils::pmr::string, std::pair<const query::procedure::CypherType *, bool>> results;
|
||||
};
|
||||
|
||||
bool MgpTransAddFixedResult(mgp_trans *trans);
|
||||
mgp_error MgpTransAddFixedResult(mgp_trans *trans) noexcept;
|
||||
|
||||
struct mgp_module {
|
||||
using allocator_type = utils::Allocator<mgp_module>;
|
||||
|
@ -91,30 +91,40 @@ void RegisterMgLoad(ModuleRegistry *module_registry, utils::RWLock *lock, Builti
|
||||
}
|
||||
lock->lock_shared();
|
||||
};
|
||||
auto load_all_cb = [module_registry, with_unlock_shared](const mgp_list *, const mgp_graph *, mgp_result *,
|
||||
mgp_memory *) {
|
||||
auto load_all_cb = [module_registry, with_unlock_shared](const mgp_list * /*args*/, const mgp_graph * /*graph*/,
|
||||
mgp_result * /*result*/, mgp_memory * /*memory*/) {
|
||||
with_unlock_shared([&]() { module_registry->UnloadAndLoadModulesFromDirectories(); });
|
||||
};
|
||||
mgp_proc load_all("load_all", load_all_cb, utils::NewDeleteResource());
|
||||
module->AddProcedure("load_all", std::move(load_all));
|
||||
auto load_cb = [module_registry, with_unlock_shared](const mgp_list *args, const mgp_graph *, mgp_result *res,
|
||||
mgp_memory *) {
|
||||
MG_ASSERT(mgp_list_size(args) == 1U, "Should have been type checked already");
|
||||
const mgp_value *arg = mgp_list_at(args, 0);
|
||||
MG_ASSERT(mgp_value_is_string(arg), "Should have been type checked already");
|
||||
auto load_cb = [module_registry, with_unlock_shared](const mgp_list *args, const mgp_graph * /*graph*/,
|
||||
mgp_result *result, mgp_memory * /*memory*/) {
|
||||
MG_ASSERT(Call<size_t>(mgp_list_size, args) == 1U, "Should have been type checked already");
|
||||
const auto *arg = Call<const mgp_value *>(mgp_list_at, args, 0);
|
||||
MG_ASSERT(CallBool(mgp_value_is_string, arg), "Should have been type checked already");
|
||||
bool succ = false;
|
||||
with_unlock_shared([&]() { succ = module_registry->LoadOrReloadModuleFromName(mgp_value_get_string(arg)); });
|
||||
if (!succ) mgp_result_set_error_msg(res, "Failed to (re)load the module.");
|
||||
with_unlock_shared([&]() {
|
||||
const char *arg_as_string{nullptr};
|
||||
if (const auto err = mgp_value_get_string(arg, &arg_as_string); err != MGP_ERROR_NO_ERROR) {
|
||||
succ = false;
|
||||
} else {
|
||||
succ = module_registry->LoadOrReloadModuleFromName(arg_as_string);
|
||||
}
|
||||
});
|
||||
if (!succ) {
|
||||
MG_ASSERT(mgp_result_set_error_msg(result, "Failed to (re)load the module.") == MGP_ERROR_NO_ERROR);
|
||||
}
|
||||
};
|
||||
mgp_proc load("load", load_cb, utils::NewDeleteResource());
|
||||
mgp_proc_add_arg(&load, "module_name", mgp_type_string());
|
||||
MG_ASSERT(mgp_proc_add_arg(&load, "module_name", Call<const mgp_type *>(mgp_type_string)) == MGP_ERROR_NO_ERROR);
|
||||
module->AddProcedure("load", std::move(load));
|
||||
}
|
||||
|
||||
void RegisterMgProcedures(
|
||||
// We expect modules to be sorted by name.
|
||||
const std::map<std::string, std::unique_ptr<Module>, std::less<>> *all_modules, BuiltinModule *module) {
|
||||
auto procedures_cb = [all_modules](const mgp_list *, const mgp_graph *, mgp_result *result, mgp_memory *memory) {
|
||||
auto procedures_cb = [all_modules](const mgp_list * /*args*/, const mgp_graph * /*graph*/, mgp_result *result,
|
||||
mgp_memory *memory) {
|
||||
// Iterating over all_modules assumes that the standard mechanism of custom
|
||||
// procedure invocations takes the ModuleRegistry::lock_ with READ access.
|
||||
// For details on how the invocation is done, take a look at the
|
||||
@ -125,43 +135,53 @@ void RegisterMgProcedures(
|
||||
std::is_same_v<decltype(module->Procedures()), const std::map<std::string, mgp_proc, std::less<>> *>,
|
||||
"Expected module procedures to be sorted by name");
|
||||
for (const auto &[proc_name, proc] : *module->Procedures()) {
|
||||
auto *record = mgp_result_new_record(result);
|
||||
if (!record) {
|
||||
mgp_result_set_error_msg(result, "Not enough memory!");
|
||||
mgp_result_record *record{nullptr};
|
||||
if (const auto err = mgp_result_new_record(result, &record); err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
static_cast<void>(mgp_result_set_error_msg(result, "Not enough memory!"));
|
||||
return;
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
static_cast<void>(mgp_result_set_error_msg(result, "Unexpected error"));
|
||||
return;
|
||||
}
|
||||
|
||||
utils::pmr::string full_name(module_name, memory->impl);
|
||||
full_name.append(1, '.');
|
||||
full_name.append(proc_name);
|
||||
auto *name_value = mgp_value_make_string(full_name.c_str(), memory);
|
||||
if (!name_value) {
|
||||
mgp_result_set_error_msg(result, "Not enough memory!");
|
||||
MgpUniquePtr<mgp_value> name_value{nullptr, mgp_value_destroy};
|
||||
if (const auto err = CreateMgpObject(name_value, mgp_value_make_string, full_name.c_str(), memory);
|
||||
err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
static_cast<void>(mgp_result_set_error_msg(result, "Not enough memory!"));
|
||||
return;
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
static_cast<void>(mgp_result_set_error_msg(result, "Unexpected error"));
|
||||
return;
|
||||
}
|
||||
std::stringstream ss;
|
||||
ss << module_name << ".";
|
||||
PrintProcSignature(proc, &ss);
|
||||
const auto signature = ss.str();
|
||||
auto *signature_value = mgp_value_make_string(signature.c_str(), memory);
|
||||
if (!signature_value) {
|
||||
mgp_value_destroy(name_value);
|
||||
mgp_result_set_error_msg(result, "Not enough memory!");
|
||||
MgpUniquePtr<mgp_value> signature_value{nullptr, mgp_value_destroy};
|
||||
if (const auto err = CreateMgpObject(signature_value, mgp_value_make_string, full_name.c_str(), memory);
|
||||
err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
static_cast<void>(mgp_result_set_error_msg(result, "Not enough memory!"));
|
||||
return;
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
static_cast<void>(mgp_result_set_error_msg(result, "Unexpected error"));
|
||||
return;
|
||||
}
|
||||
int succ1 = mgp_result_record_insert(record, "name", name_value);
|
||||
int succ2 = mgp_result_record_insert(record, "signature", signature_value);
|
||||
mgp_value_destroy(name_value);
|
||||
mgp_value_destroy(signature_value);
|
||||
if (!succ1 || !succ2) {
|
||||
mgp_result_set_error_msg(result, "Unable to set the result!");
|
||||
const auto err1 = mgp_result_record_insert(record, "name", name_value.get());
|
||||
const auto err2 = mgp_result_record_insert(record, "signature", signature_value.get());
|
||||
if (err1 != MGP_ERROR_NO_ERROR || err2 != MGP_ERROR_NO_ERROR) {
|
||||
static_cast<void>(mgp_result_set_error_msg(result, "Unable to set the result!"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
mgp_proc procedures("procedures", procedures_cb, utils::NewDeleteResource());
|
||||
mgp_proc_add_result(&procedures, "name", mgp_type_string());
|
||||
mgp_proc_add_result(&procedures, "signature", mgp_type_string());
|
||||
MG_ASSERT(mgp_proc_add_result(&procedures, "name", Call<const mgp_type *>(mgp_type_string)) == MGP_ERROR_NO_ERROR);
|
||||
MG_ASSERT(mgp_proc_add_result(&procedures, "signature", Call<const mgp_type *>(mgp_type_string)) ==
|
||||
MGP_ERROR_NO_ERROR);
|
||||
module->AddProcedure("procedures", std::move(procedures));
|
||||
}
|
||||
|
||||
@ -175,32 +195,41 @@ void RegisterMgTransformations(const std::map<std::string, std::unique_ptr<Modul
|
||||
std::is_same_v<decltype(module->Transformations()), const std::map<std::string, mgp_trans, std::less<>> *>,
|
||||
"Expected module transformations to be sorted by name");
|
||||
for (const auto &[trans_name, proc] : *module->Transformations()) {
|
||||
auto *record = mgp_result_new_record(result);
|
||||
if (!record) {
|
||||
mgp_result_set_error_msg(result, "Not enough memory!");
|
||||
mgp_result_record *record{nullptr};
|
||||
if (const auto err = mgp_result_new_record(result, &record); err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
static_cast<void>(mgp_result_set_error_msg(result, "Not enough memory!"));
|
||||
return;
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
static_cast<void>(mgp_result_set_error_msg(result, "Unexpected error"));
|
||||
return;
|
||||
}
|
||||
|
||||
utils::pmr::string full_name(module_name, memory->impl);
|
||||
full_name.append(1, '.');
|
||||
full_name.append(trans_name);
|
||||
auto *name_value = mgp_value_make_string(full_name.c_str(), memory);
|
||||
if (!name_value) {
|
||||
mgp_result_set_error_msg(result, "Not enough memory!");
|
||||
|
||||
MgpUniquePtr<mgp_value> name_value{nullptr, mgp_value_destroy};
|
||||
if (const auto err = CreateMgpObject(name_value, mgp_value_make_string, full_name.c_str(), memory);
|
||||
err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
static_cast<void>(mgp_result_set_error_msg(result, "Not enough memory!"));
|
||||
return;
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
static_cast<void>(mgp_result_set_error_msg(result, "Unexpected error"));
|
||||
return;
|
||||
}
|
||||
int succ = mgp_result_record_insert(record, "name", name_value);
|
||||
mgp_value_destroy(name_value);
|
||||
if (!succ) {
|
||||
mgp_result_set_error_msg(result, "Unable to set the result!");
|
||||
|
||||
if (const auto err = mgp_result_record_insert(record, "name", name_value.get()); err != MGP_ERROR_NO_ERROR) {
|
||||
static_cast<void>(mgp_result_set_error_msg(result, "Unable to set the result!"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
mgp_proc procedures("transformations", procedures_cb, utils::NewDeleteResource());
|
||||
mgp_proc_add_result(&procedures, "name", mgp_type_string());
|
||||
MG_ASSERT(mgp_proc_add_result(&procedures, "name", Call<const mgp_type *>(mgp_type_string)) == MGP_ERROR_NO_ERROR);
|
||||
module->AddProcedure("transformations", std::move(procedures));
|
||||
}
|
||||
|
||||
// Run `fun` with `mgp_module *` and `mgp_memory *` arguments. If `fun` returned
|
||||
// a `true` value, store the `mgp_module::procedures` and
|
||||
// `mgp_module::transformations into `proc_map`. The return value of WithModuleRegistration
|
||||
@ -392,11 +421,13 @@ bool PythonModule::Load(const std::filesystem::path &file_path) {
|
||||
return false;
|
||||
}
|
||||
bool succ = true;
|
||||
auto module_cb = [&](auto *module_def, auto *memory) {
|
||||
auto module_cb = [&](auto *module_def, auto * /*memory*/) {
|
||||
auto result = ImportPyModule(file_path.stem().c_str(), module_def);
|
||||
for (auto &trans : module_def->transformations) {
|
||||
succ = MgpTransAddFixedResult(&trans.second);
|
||||
if (!succ) return result;
|
||||
succ = MgpTransAddFixedResult(&trans.second) == MGP_ERROR_NO_ERROR;
|
||||
if (!succ) {
|
||||
return result;
|
||||
}
|
||||
};
|
||||
return result;
|
||||
};
|
||||
@ -578,7 +609,7 @@ void ModuleRegistry::UnloadAllModules() {
|
||||
DoUnloadAllModules();
|
||||
}
|
||||
|
||||
utils::MemoryResource &ModuleRegistry::GetSharedMemoryResource() { return *shared_; }
|
||||
utils::MemoryResource &ModuleRegistry::GetSharedMemoryResource() noexcept { return *shared_; }
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -100,7 +100,7 @@ class ModuleRegistry final {
|
||||
void UnloadAllModules();
|
||||
|
||||
/// Returns the shared memory allocator used by modules
|
||||
utils::MemoryResource &GetSharedMemoryResource();
|
||||
utils::MemoryResource &GetSharedMemoryResource() noexcept;
|
||||
|
||||
private:
|
||||
std::vector<std::filesystem::path> modules_dirs_;
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "query/procedure/mg_procedure_helpers.hpp"
|
||||
#include "query/procedure/mg_procedure_impl.hpp"
|
||||
#include "utils/pmr/vector.hpp"
|
||||
|
||||
@ -70,7 +71,7 @@ PyObject *PyVerticesIteratorGet(PyVerticesIterator *self, PyObject *Py_UNUSED(ig
|
||||
MG_ASSERT(self->it);
|
||||
MG_ASSERT(self->py_graph);
|
||||
MG_ASSERT(self->py_graph->graph);
|
||||
const auto *vertex = mgp_vertices_iterator_get(self->it);
|
||||
const auto *vertex = Call<const mgp_vertex *>(mgp_vertices_iterator_get, self->it);
|
||||
if (!vertex) Py_RETURN_NONE;
|
||||
return MakePyVertex(*vertex, self->py_graph);
|
||||
}
|
||||
@ -79,7 +80,7 @@ PyObject *PyVerticesIteratorNext(PyVerticesIterator *self, PyObject *Py_UNUSED(i
|
||||
MG_ASSERT(self->it);
|
||||
MG_ASSERT(self->py_graph);
|
||||
MG_ASSERT(self->py_graph->graph);
|
||||
const auto *vertex = mgp_vertices_iterator_next(self->it);
|
||||
const auto *vertex = Call<const mgp_vertex *>(mgp_vertices_iterator_next, self->it);
|
||||
if (!vertex) Py_RETURN_NONE;
|
||||
return MakePyVertex(*vertex, self->py_graph);
|
||||
}
|
||||
@ -130,7 +131,7 @@ PyObject *PyEdgesIteratorGet(PyEdgesIterator *self, PyObject *Py_UNUSED(ignored)
|
||||
MG_ASSERT(self->it);
|
||||
MG_ASSERT(self->py_graph);
|
||||
MG_ASSERT(self->py_graph->graph);
|
||||
const auto *edge = mgp_edges_iterator_get(self->it);
|
||||
const auto *edge = Call<const mgp_edge *>(mgp_edges_iterator_get, self->it);
|
||||
if (!edge) Py_RETURN_NONE;
|
||||
return MakePyEdge(*edge, self->py_graph);
|
||||
}
|
||||
@ -139,7 +140,7 @@ PyObject *PyEdgesIteratorNext(PyEdgesIterator *self, PyObject *Py_UNUSED(ignored
|
||||
MG_ASSERT(self->it);
|
||||
MG_ASSERT(self->py_graph);
|
||||
MG_ASSERT(self->py_graph->graph);
|
||||
const auto *edge = mgp_edges_iterator_next(self->it);
|
||||
const auto *edge = Call<const mgp_edge *>(mgp_edges_iterator_next, self->it);
|
||||
if (!edge) Py_RETURN_NONE;
|
||||
return MakePyEdge(*edge, self->py_graph);
|
||||
}
|
||||
@ -181,7 +182,7 @@ PyObject *PyGraphGetVertexById(PyGraph *self, PyObject *args) {
|
||||
static_assert(std::is_same_v<int64_t, long>);
|
||||
int64_t id = 0;
|
||||
if (!PyArg_ParseTuple(args, "l", &id)) return nullptr;
|
||||
auto *vertex = mgp_graph_get_vertex_by_id(self->graph, mgp_vertex_id{id}, self->memory);
|
||||
auto *vertex = Call<mgp_vertex *>(mgp_graph_get_vertex_by_id, self->graph, mgp_vertex_id{id}, self->memory);
|
||||
if (!vertex) {
|
||||
PyErr_SetString(PyExc_IndexError, "Unable to find the vertex with given ID.");
|
||||
return nullptr;
|
||||
@ -194,7 +195,7 @@ PyObject *PyGraphGetVertexById(PyGraph *self, PyObject *args) {
|
||||
PyObject *PyGraphIterVertices(PyGraph *self, PyObject *Py_UNUSED(ignored)) {
|
||||
MG_ASSERT(self->graph);
|
||||
MG_ASSERT(self->memory);
|
||||
auto *vertices_it = mgp_graph_iter_vertices(self->graph, self->memory);
|
||||
auto *vertices_it = Call<mgp_vertices_iterator *>(mgp_graph_iter_vertices, self->graph, self->memory);
|
||||
if (!vertices_it) {
|
||||
PyErr_SetString(PyExc_MemoryError, "Unable to allocate mgp_vertices_iterator.");
|
||||
return nullptr;
|
||||
@ -291,7 +292,7 @@ PyObject *PyQueryProcAddArg(PyQueryProc *self, PyObject *args) {
|
||||
return nullptr;
|
||||
}
|
||||
const auto *type = reinterpret_cast<PyCypherType *>(py_type)->type;
|
||||
if (!mgp_proc_add_arg(self->proc, name, type)) {
|
||||
if (mgp_proc_add_arg(self->proc, name, type) != MGP_ERROR_NO_ERROR) {
|
||||
PyErr_SetString(PyExc_ValueError, "Invalid call to mgp_proc_add_arg.");
|
||||
return nullptr;
|
||||
}
|
||||
@ -310,7 +311,7 @@ PyObject *PyQueryProcAddOptArg(PyQueryProc *self, PyObject *args) {
|
||||
}
|
||||
const auto *type = reinterpret_cast<PyCypherType *>(py_type)->type;
|
||||
mgp_memory memory{self->proc->opt_args.get_allocator().GetMemoryResource()};
|
||||
mgp_value *value;
|
||||
mgp_value *value{nullptr};
|
||||
try {
|
||||
value = PyObjectToMgpValue(py_value, &memory);
|
||||
} catch (const std::bad_alloc &e) {
|
||||
@ -327,7 +328,7 @@ PyObject *PyQueryProcAddOptArg(PyQueryProc *self, PyObject *args) {
|
||||
return nullptr;
|
||||
}
|
||||
MG_ASSERT(value);
|
||||
if (!mgp_proc_add_opt_arg(self->proc, name, type, value)) {
|
||||
if (mgp_proc_add_opt_arg(self->proc, name, type, value) != MGP_ERROR_NO_ERROR) {
|
||||
mgp_value_destroy(value);
|
||||
PyErr_SetString(PyExc_ValueError, "Invalid call to mgp_proc_add_opt_arg.");
|
||||
return nullptr;
|
||||
@ -346,7 +347,7 @@ PyObject *PyQueryProcAddResult(PyQueryProc *self, PyObject *args) {
|
||||
return nullptr;
|
||||
}
|
||||
const auto *type = reinterpret_cast<PyCypherType *>(py_type)->type;
|
||||
if (!mgp_proc_add_result(self->proc, name, type)) {
|
||||
if (mgp_proc_add_result(self->proc, name, type) != MGP_ERROR_NO_ERROR) {
|
||||
PyErr_SetString(PyExc_ValueError, "Invalid call to mgp_proc_add_result.");
|
||||
return nullptr;
|
||||
}
|
||||
@ -363,7 +364,7 @@ PyObject *PyQueryProcAddDeprecatedResult(PyQueryProc *self, PyObject *args) {
|
||||
return nullptr;
|
||||
}
|
||||
const auto *type = reinterpret_cast<PyCypherType *>(py_type)->type;
|
||||
if (!mgp_proc_add_deprecated_result(self->proc, name, type)) {
|
||||
if (const auto err = mgp_proc_add_deprecated_result(self->proc, name, type); err != MGP_ERROR_NO_ERROR) {
|
||||
PyErr_SetString(PyExc_ValueError, "Invalid call to mgp_proc_add_deprecated_result.");
|
||||
return nullptr;
|
||||
}
|
||||
@ -424,8 +425,8 @@ PyObject *PyMessageIsValid(PyMessage *self, PyObject *Py_UNUSED(ignored)) {
|
||||
|
||||
PyObject *PyMessageGetPayload(PyMessage *self, PyObject *Py_UNUSED(ignored)) {
|
||||
MG_ASSERT(self->message);
|
||||
auto payload_size = mgp_message_payload_size(self->message);
|
||||
const auto *payload = mgp_message_payload(self->message);
|
||||
auto payload_size = Call<size_t>(mgp_message_payload_size, self->message);
|
||||
const auto *payload = Call<const char *>(mgp_message_payload, self->message);
|
||||
auto *raw_bytes = PyByteArray_FromStringAndSize(payload, payload_size);
|
||||
if (!raw_bytes) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Unable to get raw bytes from payload");
|
||||
@ -437,7 +438,7 @@ PyObject *PyMessageGetPayload(PyMessage *self, PyObject *Py_UNUSED(ignored)) {
|
||||
PyObject *PyMessageGetTopicName(PyMessage *self, PyObject *Py_UNUSED(ignored)) {
|
||||
MG_ASSERT(self->message);
|
||||
MG_ASSERT(self->memory);
|
||||
const auto *topic_name = mgp_message_topic_name(self->message);
|
||||
const auto *topic_name = Call<const char *>(mgp_message_topic_name, self->message);
|
||||
auto *py_topic_name = PyUnicode_FromString(topic_name);
|
||||
if (!py_topic_name) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Unable to get raw bytes from payload");
|
||||
@ -449,8 +450,8 @@ PyObject *PyMessageGetTopicName(PyMessage *self, PyObject *Py_UNUSED(ignored)) {
|
||||
PyObject *PyMessageGetKey(PyMessage *self, PyObject *Py_UNUSED(ignored)) {
|
||||
MG_ASSERT(self->message);
|
||||
MG_ASSERT(self->memory);
|
||||
auto key_size = mgp_message_key_size(self->message);
|
||||
const auto *key = mgp_message_key(self->message);
|
||||
auto key_size = Call<size_t>(mgp_message_key_size, self->message);
|
||||
const auto *key = Call<const char *>(mgp_message_key, self->message);
|
||||
auto *raw_bytes = PyByteArray_FromStringAndSize(key, key_size);
|
||||
if (!raw_bytes) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Unable to get raw bytes from payload");
|
||||
@ -462,7 +463,7 @@ PyObject *PyMessageGetKey(PyMessage *self, PyObject *Py_UNUSED(ignored)) {
|
||||
PyObject *PyMessageGetTimestamp(PyMessage *self, PyObject *Py_UNUSED(ignored)) {
|
||||
MG_ASSERT(self->message);
|
||||
MG_ASSERT(self->memory);
|
||||
auto timestamp = mgp_message_timestamp(self->message);
|
||||
auto timestamp = Call<int64_t>(mgp_message_timestamp, self->message);
|
||||
auto *py_int = PyLong_FromUnsignedLong(timestamp);
|
||||
if (!py_int) {
|
||||
PyErr_SetString(PyExc_IndexError, "Unable to get timestamp.");
|
||||
@ -529,7 +530,7 @@ PyObject *PyMessagesGetMessageAt(PyMessages *self, PyObject *args) {
|
||||
int64_t id = 0;
|
||||
if (!PyArg_ParseTuple(args, "l", &id)) return nullptr;
|
||||
if (id < 0) return nullptr;
|
||||
const auto *message = mgp_messages_at(self->messages, id);
|
||||
const auto *message = Call<const mgp_message *>(mgp_messages_at, self->messages, id);
|
||||
// NOLINTNEXTLINE
|
||||
auto *py_message = PyObject_New(PyMessage, &PyMessageType);
|
||||
if (!py_message) {
|
||||
@ -586,11 +587,11 @@ PyObject *MakePyMessages(const mgp_messages *msgs, mgp_memory *memory) {
|
||||
py::Object MgpListToPyTuple(const mgp_list *list, PyGraph *py_graph) {
|
||||
MG_ASSERT(list);
|
||||
MG_ASSERT(py_graph);
|
||||
const size_t len = mgp_list_size(list);
|
||||
const auto len = Call<size_t>(mgp_list_size, list);
|
||||
py::Object py_tuple(PyTuple_New(len));
|
||||
if (!py_tuple) return nullptr;
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
auto elem = MgpValueToPyObject(*mgp_list_at(list, i), py_graph);
|
||||
auto elem = MgpValueToPyObject(*Call<const mgp_value *>(mgp_list_at, list, i), py_graph);
|
||||
if (!elem) return nullptr;
|
||||
// Explicitly convert `py_tuple`, which is `py::Object`, via static_cast.
|
||||
// Then the macro will cast it to `PyTuple *`.
|
||||
@ -629,7 +630,7 @@ std::optional<py::ExceptionInfo> AddRecordFromPython(mgp_result *result, py::Obj
|
||||
}
|
||||
py::Object items(PyDict_Items(fields.Ptr()));
|
||||
if (!items) return py::FetchError();
|
||||
auto *record = mgp_result_new_record(result);
|
||||
auto *record = Call<mgp_result_record *>(mgp_result_new_record, result);
|
||||
if (!record) {
|
||||
PyErr_NoMemory();
|
||||
return py::FetchError();
|
||||
@ -662,7 +663,7 @@ std::optional<py::ExceptionInfo> AddRecordFromPython(mgp_result *result, py::Obj
|
||||
return py::FetchError();
|
||||
}
|
||||
MG_ASSERT(field_val);
|
||||
if (!mgp_result_record_insert(record, field_name, field_val)) {
|
||||
if (mgp_result_record_insert(record, field_name, field_val) != MGP_ERROR_NO_ERROR) {
|
||||
std::stringstream ss;
|
||||
ss << "Unable to insert field '" << py::Object::FromBorrow(key) << "' with value: '"
|
||||
<< py::Object::FromBorrow(val) << "'; did you set the correct field type?";
|
||||
@ -764,7 +765,7 @@ void CallPythonProcedure(const py::Object &py_cb, const mgp_list *args, const mg
|
||||
}
|
||||
|
||||
if (maybe_msg) {
|
||||
mgp_result_set_error_msg(result, maybe_msg->c_str());
|
||||
static_cast<void>(mgp_result_set_error_msg(result, maybe_msg->c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -845,7 +846,7 @@ void CallPythonTransformation(const py::Object &py_cb, const mgp_messages *msgs,
|
||||
}
|
||||
|
||||
if (maybe_msg) {
|
||||
mgp_result_set_error_msg(result, maybe_msg->c_str());
|
||||
static_cast<void>(mgp_result_set_error_msg(result, maybe_msg->c_str()));
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
@ -945,7 +946,7 @@ PyObject *PyMgpModuleTypeNullable(PyObject *mod, PyObject *obj) {
|
||||
return nullptr;
|
||||
}
|
||||
auto *py_type = reinterpret_cast<PyCypherType *>(obj);
|
||||
return MakePyCypherType(mgp_type_nullable(py_type->type));
|
||||
return MakePyCypherType(Call<const mgp_type *>(mgp_type_nullable, py_type->type));
|
||||
}
|
||||
|
||||
PyObject *PyMgpModuleTypeList(PyObject *mod, PyObject *obj) {
|
||||
@ -954,36 +955,48 @@ PyObject *PyMgpModuleTypeList(PyObject *mod, PyObject *obj) {
|
||||
return nullptr;
|
||||
}
|
||||
auto *py_type = reinterpret_cast<PyCypherType *>(obj);
|
||||
return MakePyCypherType(mgp_type_list(py_type->type));
|
||||
return MakePyCypherType(Call<const mgp_type *>(mgp_type_list, py_type->type));
|
||||
}
|
||||
|
||||
PyObject *PyMgpModuleTypeAny(PyObject *mod, PyObject *Py_UNUSED(ignored)) { return MakePyCypherType(mgp_type_any()); }
|
||||
|
||||
PyObject *PyMgpModuleTypeBool(PyObject *mod, PyObject *Py_UNUSED(ignored)) { return MakePyCypherType(mgp_type_bool()); }
|
||||
|
||||
PyObject *PyMgpModuleTypeString(PyObject *mod, PyObject *Py_UNUSED(ignored)) {
|
||||
return MakePyCypherType(mgp_type_string());
|
||||
PyObject *PyMgpModuleTypeAny(PyObject * /*mod*/, PyObject *Py_UNUSED(ignored)) {
|
||||
return MakePyCypherType(Call<const mgp_type *>(mgp_type_any));
|
||||
}
|
||||
|
||||
PyObject *PyMgpModuleTypeInt(PyObject *mod, PyObject *Py_UNUSED(ignored)) { return MakePyCypherType(mgp_type_int()); }
|
||||
|
||||
PyObject *PyMgpModuleTypeFloat(PyObject *mod, PyObject *Py_UNUSED(ignored)) {
|
||||
return MakePyCypherType(mgp_type_float());
|
||||
PyObject *PyMgpModuleTypeBool(PyObject * /*mod*/, PyObject *Py_UNUSED(ignored)) {
|
||||
return MakePyCypherType(Call<const mgp_type *>(mgp_type_bool));
|
||||
}
|
||||
|
||||
PyObject *PyMgpModuleTypeNumber(PyObject *mod, PyObject *Py_UNUSED(ignored)) {
|
||||
return MakePyCypherType(mgp_type_number());
|
||||
PyObject *PyMgpModuleTypeString(PyObject * /*mod*/, PyObject *Py_UNUSED(ignored)) {
|
||||
return MakePyCypherType(Call<const mgp_type *>(mgp_type_string));
|
||||
}
|
||||
|
||||
PyObject *PyMgpModuleTypeMap(PyObject *mod, PyObject *Py_UNUSED(ignored)) { return MakePyCypherType(mgp_type_map()); }
|
||||
|
||||
PyObject *PyMgpModuleTypeNode(PyObject *mod, PyObject *Py_UNUSED(ignored)) { return MakePyCypherType(mgp_type_node()); }
|
||||
|
||||
PyObject *PyMgpModuleTypeRelationship(PyObject *mod, PyObject *Py_UNUSED(ignored)) {
|
||||
return MakePyCypherType(mgp_type_relationship());
|
||||
PyObject *PyMgpModuleTypeInt(PyObject * /*mod*/, PyObject *Py_UNUSED(ignored)) {
|
||||
return MakePyCypherType(Call<const mgp_type *>(mgp_type_int));
|
||||
}
|
||||
|
||||
PyObject *PyMgpModuleTypePath(PyObject *mod, PyObject *Py_UNUSED(ignored)) { return MakePyCypherType(mgp_type_path()); }
|
||||
PyObject *PyMgpModuleTypeFloat(PyObject * /*mod*/, PyObject *Py_UNUSED(ignored)) {
|
||||
return MakePyCypherType(Call<const mgp_type *>(mgp_type_float));
|
||||
}
|
||||
|
||||
PyObject *PyMgpModuleTypeNumber(PyObject * /*mod*/, PyObject *Py_UNUSED(ignored)) {
|
||||
return MakePyCypherType(Call<const mgp_type *>(mgp_type_number));
|
||||
}
|
||||
|
||||
PyObject *PyMgpModuleTypeMap(PyObject * /*mod*/, PyObject *Py_UNUSED(ignored)) {
|
||||
return MakePyCypherType(Call<const mgp_type *>(mgp_type_map));
|
||||
}
|
||||
|
||||
PyObject *PyMgpModuleTypeNode(PyObject * /*mod*/, PyObject *Py_UNUSED(ignored)) {
|
||||
return MakePyCypherType(Call<const mgp_type *>(mgp_type_node));
|
||||
}
|
||||
|
||||
PyObject *PyMgpModuleTypeRelationship(PyObject * /*mod*/, PyObject *Py_UNUSED(ignored)) {
|
||||
return MakePyCypherType(Call<const mgp_type *>(mgp_type_relationship));
|
||||
}
|
||||
|
||||
PyObject *PyMgpModuleTypePath(PyObject * /*mod*/, PyObject *Py_UNUSED(ignored)) {
|
||||
return MakePyCypherType(Call<const mgp_type *>(mgp_type_path));
|
||||
}
|
||||
|
||||
static PyMethodDef PyMgpModuleMethods[] = {
|
||||
{"type_nullable", PyMgpModuleTypeNullable, METH_O,
|
||||
@ -1038,7 +1051,7 @@ PyObject *PyPropertiesIteratorGet(PyPropertiesIterator *self, PyObject *Py_UNUSE
|
||||
MG_ASSERT(self->it);
|
||||
MG_ASSERT(self->py_graph);
|
||||
MG_ASSERT(self->py_graph->graph);
|
||||
const auto *property = mgp_properties_iterator_get(self->it);
|
||||
const auto *property = Call<const mgp_property *>(mgp_properties_iterator_get, self->it);
|
||||
if (!property) Py_RETURN_NONE;
|
||||
py::Object py_name(PyUnicode_FromString(property->name));
|
||||
if (!py_name) return nullptr;
|
||||
@ -1051,7 +1064,7 @@ PyObject *PyPropertiesIteratorNext(PyPropertiesIterator *self, PyObject *Py_UNUS
|
||||
MG_ASSERT(self->it);
|
||||
MG_ASSERT(self->py_graph);
|
||||
MG_ASSERT(self->py_graph->graph);
|
||||
const auto *property = mgp_properties_iterator_next(self->it);
|
||||
const auto *property = Call<const mgp_property *>(mgp_properties_iterator_next, self->it);
|
||||
if (!property) Py_RETURN_NONE;
|
||||
py::Object py_name(PyUnicode_FromString(property->name));
|
||||
if (!py_name) return nullptr;
|
||||
@ -1093,7 +1106,7 @@ PyObject *PyEdgeGetTypeName(PyEdge *self, PyObject *Py_UNUSED(ignored)) {
|
||||
MG_ASSERT(self->edge);
|
||||
MG_ASSERT(self->py_graph);
|
||||
MG_ASSERT(self->py_graph->graph);
|
||||
return PyUnicode_FromString(mgp_edge_get_type(self->edge).name);
|
||||
return PyUnicode_FromString(Call<mgp_edge_type>(mgp_edge_get_type, self->edge).name);
|
||||
}
|
||||
|
||||
PyObject *PyEdgeFromVertex(PyEdge *self, PyObject *Py_UNUSED(ignored)) {
|
||||
@ -1101,7 +1114,7 @@ PyObject *PyEdgeFromVertex(PyEdge *self, PyObject *Py_UNUSED(ignored)) {
|
||||
MG_ASSERT(self->edge);
|
||||
MG_ASSERT(self->py_graph);
|
||||
MG_ASSERT(self->py_graph->graph);
|
||||
const auto *vertex = mgp_edge_get_from(self->edge);
|
||||
const auto *vertex = Call<const mgp_vertex *>(mgp_edge_get_from, self->edge);
|
||||
MG_ASSERT(vertex);
|
||||
return MakePyVertex(*vertex, self->py_graph);
|
||||
}
|
||||
@ -1111,7 +1124,7 @@ PyObject *PyEdgeToVertex(PyEdge *self, PyObject *Py_UNUSED(ignored)) {
|
||||
MG_ASSERT(self->edge);
|
||||
MG_ASSERT(self->py_graph);
|
||||
MG_ASSERT(self->py_graph->graph);
|
||||
const auto *vertex = mgp_edge_get_to(self->edge);
|
||||
const auto *vertex = Call<const mgp_vertex *>(mgp_edge_get_to, self->edge);
|
||||
MG_ASSERT(vertex);
|
||||
return MakePyVertex(*vertex, self->py_graph);
|
||||
}
|
||||
@ -1136,7 +1149,7 @@ PyObject *PyEdgeGetId(PyEdge *self, PyObject *Py_UNUSED(ignored)) {
|
||||
MG_ASSERT(self->edge);
|
||||
MG_ASSERT(self->py_graph);
|
||||
MG_ASSERT(self->py_graph->graph);
|
||||
return PyLong_FromLongLong(mgp_edge_get_id(self->edge).as_int);
|
||||
return PyLong_FromLongLong(Call<mgp_edge_id>(mgp_edge_get_id, self->edge).as_int);
|
||||
}
|
||||
|
||||
PyObject *PyEdgeIterProperties(PyEdge *self, PyObject *Py_UNUSED(ignored)) {
|
||||
@ -1144,10 +1157,14 @@ PyObject *PyEdgeIterProperties(PyEdge *self, PyObject *Py_UNUSED(ignored)) {
|
||||
MG_ASSERT(self->edge);
|
||||
MG_ASSERT(self->py_graph);
|
||||
MG_ASSERT(self->py_graph->graph);
|
||||
auto *properties_it = mgp_edge_iter_properties(self->edge, self->py_graph->memory);
|
||||
if (!properties_it) {
|
||||
mgp_properties_iterator *properties_it{nullptr};
|
||||
if (const auto err = mgp_edge_iter_properties(self->edge, self->py_graph->memory, &properties_it);
|
||||
err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
PyErr_SetString(PyExc_MemoryError, "Unable to allocate mgp_properties_iterator.");
|
||||
return nullptr;
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Unexpected error during getting mgp_properties_iterator.");
|
||||
return nullptr;
|
||||
}
|
||||
auto *py_properties_it = PyObject_New(PyPropertiesIterator, &PyPropertiesIteratorType);
|
||||
if (!py_properties_it) {
|
||||
@ -1167,10 +1184,14 @@ PyObject *PyEdgeGetProperty(PyEdge *self, PyObject *args) {
|
||||
MG_ASSERT(self->py_graph->graph);
|
||||
const char *prop_name = nullptr;
|
||||
if (!PyArg_ParseTuple(args, "s", &prop_name)) return nullptr;
|
||||
auto *prop_value = mgp_edge_get_property(self->edge, prop_name, self->py_graph->memory);
|
||||
if (!prop_value) {
|
||||
mgp_value *prop_value{nullptr};
|
||||
if (const auto err = mgp_edge_get_property(self->edge, prop_name, self->py_graph->memory, &prop_value);
|
||||
err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
PyErr_SetString(PyExc_MemoryError, "Unable to allocate mgp_value for edge property value.");
|
||||
return nullptr;
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Unexpected error during getting mgp_edge property.");
|
||||
return nullptr;
|
||||
}
|
||||
auto py_prop_value = MgpValueToPyObject(*prop_value, self->py_graph);
|
||||
mgp_value_destroy(prop_value);
|
||||
@ -1214,10 +1235,13 @@ static PyTypeObject PyEdgeType = {
|
||||
PyObject *MakePyEdge(const mgp_edge &edge, PyGraph *py_graph) {
|
||||
MG_ASSERT(py_graph);
|
||||
MG_ASSERT(py_graph->graph && py_graph->memory);
|
||||
auto *edge_copy = mgp_edge_copy(&edge, py_graph->memory);
|
||||
if (!edge_copy) {
|
||||
mgp_edge *edge_copy{nullptr};
|
||||
if (const auto err = mgp_edge_copy(&edge, py_graph->memory, &edge_copy); err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
PyErr_SetString(PyExc_MemoryError, "Unable to allocate mgp_edge.");
|
||||
return nullptr;
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Unexpected error during creating mgp_edge");
|
||||
return nullptr;
|
||||
}
|
||||
auto *py_edge = PyObject_New(PyEdge, &PyEdgeType);
|
||||
if (!py_edge) {
|
||||
@ -1243,7 +1267,12 @@ PyObject *PyEdgeRichCompare(PyObject *self, PyObject *other, int op) {
|
||||
MG_ASSERT(e1->edge);
|
||||
MG_ASSERT(e2->edge);
|
||||
|
||||
return PyBool_FromLong(mgp_edge_equal(e1->edge, e2->edge));
|
||||
int equals{0};
|
||||
if (const auto err = mgp_edge_equal(e1->edge, e2->edge, &equals); err != MGP_ERROR_NO_ERROR) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Unexpected error during comparing edges");
|
||||
return nullptr;
|
||||
}
|
||||
return PyBool_FromLong(equals);
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
@ -1274,7 +1303,12 @@ PyObject *PyVertexGetId(PyVertex *self, PyObject *Py_UNUSED(ignored)) {
|
||||
MG_ASSERT(self->vertex);
|
||||
MG_ASSERT(self->py_graph);
|
||||
MG_ASSERT(self->py_graph->graph);
|
||||
return PyLong_FromLongLong(mgp_vertex_get_id(self->vertex).as_int);
|
||||
mgp_vertex_id id{};
|
||||
if (const auto err = mgp_vertex_get_id(self->vertex, &id); err != MGP_ERROR_NO_ERROR) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Unexpected error during getting id of mgp_vertex");
|
||||
return nullptr;
|
||||
}
|
||||
return PyLong_FromLongLong(id.as_int);
|
||||
}
|
||||
|
||||
PyObject *PyVertexLabelsCount(PyVertex *self, PyObject *Py_UNUSED(ignored)) {
|
||||
@ -1282,7 +1316,12 @@ PyObject *PyVertexLabelsCount(PyVertex *self, PyObject *Py_UNUSED(ignored)) {
|
||||
MG_ASSERT(self->vertex);
|
||||
MG_ASSERT(self->py_graph);
|
||||
MG_ASSERT(self->py_graph->graph);
|
||||
return PyLong_FromSize_t(mgp_vertex_labels_count(self->vertex));
|
||||
size_t label_count{0};
|
||||
if (const auto err = mgp_vertex_labels_count(self->vertex, &label_count); err != MGP_ERROR_NO_ERROR) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Unexpected error during getting label count of mgp_vertex");
|
||||
return nullptr;
|
||||
}
|
||||
return PyLong_FromSize_t(label_count);
|
||||
}
|
||||
|
||||
PyObject *PyVertexLabelAt(PyVertex *self, PyObject *args) {
|
||||
@ -1292,8 +1331,14 @@ PyObject *PyVertexLabelAt(PyVertex *self, PyObject *args) {
|
||||
MG_ASSERT(self->py_graph->graph);
|
||||
static_assert(std::numeric_limits<Py_ssize_t>::max() <= std::numeric_limits<size_t>::max());
|
||||
Py_ssize_t id;
|
||||
if (!PyArg_ParseTuple(args, "n", &id)) return nullptr;
|
||||
auto label = mgp_vertex_label_at(self->vertex, id);
|
||||
if (!PyArg_ParseTuple(args, "n", &id)) {
|
||||
return nullptr;
|
||||
}
|
||||
mgp_label label{nullptr};
|
||||
if (const auto err = mgp_vertex_label_at(self->vertex, id, &label); err != MGP_ERROR_NO_ERROR) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Unexpected error during getting label of mgp_vertex");
|
||||
return nullptr;
|
||||
}
|
||||
if (label.name == nullptr || id < 0) {
|
||||
PyErr_SetString(PyExc_IndexError, "Unable to find the label with given ID.");
|
||||
return nullptr;
|
||||
@ -1306,10 +1351,14 @@ PyObject *PyVertexIterInEdges(PyVertex *self, PyObject *Py_UNUSED(ignored)) {
|
||||
MG_ASSERT(self->vertex);
|
||||
MG_ASSERT(self->py_graph);
|
||||
MG_ASSERT(self->py_graph->graph);
|
||||
auto *edges_it = mgp_vertex_iter_in_edges(self->vertex, self->py_graph->memory);
|
||||
if (!edges_it) {
|
||||
mgp_edges_iterator *edges_it{nullptr};
|
||||
if (const auto err = mgp_vertex_iter_in_edges(self->vertex, self->py_graph->memory, &edges_it);
|
||||
err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
PyErr_SetString(PyExc_MemoryError, "Unable to allocate mgp_edges_iterator for in edges.");
|
||||
return nullptr;
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Unexpected error during getting mgp_edges_iterator for in edges");
|
||||
return nullptr;
|
||||
}
|
||||
auto *py_edges_it = PyObject_New(PyEdgesIterator, &PyEdgesIteratorType);
|
||||
if (!py_edges_it) {
|
||||
@ -1327,10 +1376,14 @@ PyObject *PyVertexIterOutEdges(PyVertex *self, PyObject *Py_UNUSED(ignored)) {
|
||||
MG_ASSERT(self->vertex);
|
||||
MG_ASSERT(self->py_graph);
|
||||
MG_ASSERT(self->py_graph->graph);
|
||||
auto *edges_it = mgp_vertex_iter_out_edges(self->vertex, self->py_graph->memory);
|
||||
if (!edges_it) {
|
||||
mgp_edges_iterator *edges_it{nullptr};
|
||||
if (const auto err = mgp_vertex_iter_out_edges(self->vertex, self->py_graph->memory, &edges_it);
|
||||
err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
PyErr_SetString(PyExc_MemoryError, "Unable to allocate mgp_edges_iterator for out edges.");
|
||||
return nullptr;
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Unexpected error during getting mgp_edges_iterator for out edges");
|
||||
return nullptr;
|
||||
}
|
||||
auto *py_edges_it = PyObject_New(PyEdgesIterator, &PyEdgesIteratorType);
|
||||
if (!py_edges_it) {
|
||||
@ -1348,10 +1401,14 @@ PyObject *PyVertexIterProperties(PyVertex *self, PyObject *Py_UNUSED(ignored)) {
|
||||
MG_ASSERT(self->vertex);
|
||||
MG_ASSERT(self->py_graph);
|
||||
MG_ASSERT(self->py_graph->graph);
|
||||
auto *properties_it = mgp_vertex_iter_properties(self->vertex, self->py_graph->memory);
|
||||
if (!properties_it) {
|
||||
mgp_properties_iterator *properties_it{nullptr};
|
||||
if (const auto err = mgp_vertex_iter_properties(self->vertex, self->py_graph->memory, &properties_it);
|
||||
err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
PyErr_SetString(PyExc_MemoryError, "Unable to allocate mgp_properties_iterator.");
|
||||
return nullptr;
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Unexpected error during getting mgp_properties_iterator.");
|
||||
return nullptr;
|
||||
}
|
||||
auto *py_properties_it = PyObject_New(PyPropertiesIterator, &PyPropertiesIteratorType);
|
||||
if (!py_properties_it) {
|
||||
@ -1370,11 +1427,17 @@ PyObject *PyVertexGetProperty(PyVertex *self, PyObject *args) {
|
||||
MG_ASSERT(self->py_graph);
|
||||
MG_ASSERT(self->py_graph->graph);
|
||||
const char *prop_name = nullptr;
|
||||
if (!PyArg_ParseTuple(args, "s", &prop_name)) return nullptr;
|
||||
auto *prop_value = mgp_vertex_get_property(self->vertex, prop_name, self->py_graph->memory);
|
||||
if (!prop_value) {
|
||||
if (!PyArg_ParseTuple(args, "s", &prop_name)) {
|
||||
return nullptr;
|
||||
}
|
||||
mgp_value *prop_value{nullptr};
|
||||
if (const auto err = mgp_vertex_get_property(self->vertex, prop_name, self->py_graph->memory, &prop_value);
|
||||
err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
PyErr_SetString(PyExc_MemoryError, "Unable to allocate mgp_value for vertex property value.");
|
||||
return nullptr;
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Unexpected error during getting mgp_vertex property.");
|
||||
return nullptr;
|
||||
}
|
||||
auto py_prop_value = MgpValueToPyObject(*prop_value, self->py_graph);
|
||||
mgp_value_destroy(prop_value);
|
||||
@ -1432,10 +1495,14 @@ PyObject *MakePyVertex(mgp_vertex *vertex, PyGraph *py_graph) {
|
||||
PyObject *MakePyVertex(const mgp_vertex &vertex, PyGraph *py_graph) {
|
||||
MG_ASSERT(py_graph);
|
||||
MG_ASSERT(py_graph->graph && py_graph->memory);
|
||||
auto *vertex_copy = mgp_vertex_copy(&vertex, py_graph->memory);
|
||||
if (!vertex_copy) {
|
||||
|
||||
mgp_vertex *vertex_copy{nullptr};
|
||||
if (const auto err = mgp_vertex_copy(&vertex, py_graph->memory, &vertex_copy); err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
PyErr_SetString(PyExc_MemoryError, "Unable to allocate mgp_vertex.");
|
||||
return nullptr;
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Unexpected error during creating mgp_vertex");
|
||||
return nullptr;
|
||||
}
|
||||
auto *py_vertex = MakePyVertex(vertex_copy, py_graph);
|
||||
if (!py_vertex) mgp_vertex_destroy(vertex_copy);
|
||||
@ -1455,7 +1522,12 @@ PyObject *PyVertexRichCompare(PyObject *self, PyObject *other, int op) {
|
||||
MG_ASSERT(v1->vertex);
|
||||
MG_ASSERT(v2->vertex);
|
||||
|
||||
return PyBool_FromLong(mgp_vertex_equal(v1->vertex, v2->vertex));
|
||||
int equals{0};
|
||||
if (const auto err = mgp_vertex_equal(v1->vertex, v2->vertex, &equals); err != MGP_ERROR_NO_ERROR) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Unexpected error during comparing vertices");
|
||||
return nullptr;
|
||||
}
|
||||
return PyBool_FromLong(equals);
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
@ -1492,14 +1564,10 @@ PyObject *PyPathExpand(PyPath *self, PyObject *edge) {
|
||||
return nullptr;
|
||||
}
|
||||
auto *py_edge = reinterpret_cast<PyEdge *>(edge);
|
||||
const auto *to = mgp_edge_get_to(py_edge->edge);
|
||||
const auto *from = mgp_edge_get_from(py_edge->edge);
|
||||
const auto *last_vertex = mgp_path_vertex_at(self->path, mgp_path_size(self->path));
|
||||
if (!mgp_vertex_equal(last_vertex, to) && !mgp_vertex_equal(last_vertex, from)) {
|
||||
if (const auto err = mgp_path_expand(self->path, py_edge->edge); err == MGP_ERROR_LOGIC_ERROR) {
|
||||
PyErr_SetString(PyExc_ValueError, "Edge is not a continuation of the path.");
|
||||
return nullptr;
|
||||
}
|
||||
if (!mgp_path_expand(self->path, py_edge->edge)) {
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
PyErr_SetString(PyExc_MemoryError, "Unable to expand mgp_path.");
|
||||
return nullptr;
|
||||
}
|
||||
@ -1510,7 +1578,7 @@ PyObject *PyPathSize(PyPath *self, PyObject *Py_UNUSED(ignored)) {
|
||||
MG_ASSERT(self->path);
|
||||
MG_ASSERT(self->py_graph);
|
||||
MG_ASSERT(self->py_graph->graph);
|
||||
return PyLong_FromSize_t(mgp_path_size(self->path));
|
||||
return PyLong_FromSize_t(Call<size_t>(mgp_path_size, self->path));
|
||||
}
|
||||
|
||||
PyObject *PyPathVertexAt(PyPath *self, PyObject *args) {
|
||||
@ -1519,11 +1587,16 @@ PyObject *PyPathVertexAt(PyPath *self, PyObject *args) {
|
||||
MG_ASSERT(self->py_graph->graph);
|
||||
static_assert(std::numeric_limits<Py_ssize_t>::max() <= std::numeric_limits<size_t>::max());
|
||||
Py_ssize_t i;
|
||||
if (!PyArg_ParseTuple(args, "n", &i)) return nullptr;
|
||||
const auto *vertex = mgp_path_vertex_at(self->path, i);
|
||||
if (!vertex) {
|
||||
if (!PyArg_ParseTuple(args, "n", &i)) {
|
||||
return nullptr;
|
||||
}
|
||||
const mgp_vertex *vertex{nullptr};
|
||||
if (const auto err = mgp_path_vertex_at(self->path, i, &vertex); err == MGP_ERROR_OUT_OF_RANGE) {
|
||||
PyErr_SetString(PyExc_IndexError, "Index is out of range.");
|
||||
return nullptr;
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Unexpected error during getting vertex from path.");
|
||||
return nullptr;
|
||||
}
|
||||
return MakePyVertex(*vertex, self->py_graph);
|
||||
}
|
||||
@ -1534,11 +1607,16 @@ PyObject *PyPathEdgeAt(PyPath *self, PyObject *args) {
|
||||
MG_ASSERT(self->py_graph->graph);
|
||||
static_assert(std::numeric_limits<Py_ssize_t>::max() <= std::numeric_limits<size_t>::max());
|
||||
Py_ssize_t i;
|
||||
if (!PyArg_ParseTuple(args, "n", &i)) return nullptr;
|
||||
const auto *edge = mgp_path_edge_at(self->path, i);
|
||||
if (!edge) {
|
||||
if (!PyArg_ParseTuple(args, "n", &i)) {
|
||||
return nullptr;
|
||||
}
|
||||
const mgp_edge *edge{nullptr};
|
||||
if (const auto err = mgp_path_edge_at(self->path, i, &edge); err == MGP_ERROR_OUT_OF_RANGE) {
|
||||
PyErr_SetString(PyExc_IndexError, "Index is out of range.");
|
||||
return nullptr;
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Unexpected error during getting edge from path.");
|
||||
return nullptr;
|
||||
}
|
||||
return MakePyEdge(*edge, self->py_graph);
|
||||
}
|
||||
@ -1586,10 +1664,13 @@ PyObject *MakePyPath(mgp_path *path, PyGraph *py_graph) {
|
||||
PyObject *MakePyPath(const mgp_path &path, PyGraph *py_graph) {
|
||||
MG_ASSERT(py_graph);
|
||||
MG_ASSERT(py_graph->graph && py_graph->memory);
|
||||
auto *path_copy = mgp_path_copy(&path, py_graph->memory);
|
||||
if (!path_copy) {
|
||||
mgp_path *path_copy{nullptr};
|
||||
if (const auto err = mgp_path_copy(&path, py_graph->memory, &path_copy); err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
PyErr_SetString(PyExc_MemoryError, "Unable to allocate mgp_path.");
|
||||
return nullptr;
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Unexpected error during copying a path");
|
||||
return nullptr;
|
||||
}
|
||||
auto *py_path = MakePyPath(path_copy, py_graph);
|
||||
if (!py_path) mgp_path_destroy(path_copy);
|
||||
@ -1606,10 +1687,14 @@ PyObject *PyPathMakeWithStart(PyTypeObject *type, PyObject *vertex) {
|
||||
return nullptr;
|
||||
}
|
||||
auto *py_vertex = reinterpret_cast<PyVertex *>(vertex);
|
||||
auto *path = mgp_path_make_with_start(py_vertex->vertex, py_vertex->py_graph->memory);
|
||||
if (!path) {
|
||||
mgp_path *path{nullptr};
|
||||
if (const auto err = mgp_path_make_with_start(py_vertex->vertex, py_vertex->py_graph->memory, &path);
|
||||
err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
PyErr_SetString(PyExc_MemoryError, "Unable to allocate mgp_path.");
|
||||
return nullptr;
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Unexpected error during creating a path");
|
||||
return nullptr;
|
||||
}
|
||||
auto *py_path = MakePyPath(path, py_vertex->py_graph);
|
||||
if (!py_path) mgp_path_destroy(path);
|
||||
@ -1698,27 +1783,31 @@ py::Object MgpValueToPyObject(const mgp_value &value, PyObject *py_graph) {
|
||||
}
|
||||
|
||||
py::Object MgpValueToPyObject(const mgp_value &value, PyGraph *py_graph) {
|
||||
switch (mgp_value_get_type(&value)) {
|
||||
switch (Call<mgp_value_type>(mgp_value_get_type, &value)) {
|
||||
case MGP_VALUE_TYPE_NULL:
|
||||
Py_INCREF(Py_None);
|
||||
return py::Object(Py_None);
|
||||
case MGP_VALUE_TYPE_BOOL:
|
||||
return py::Object(PyBool_FromLong(mgp_value_get_bool(&value)));
|
||||
return py::Object(PyBool_FromLong(CallBool(mgp_value_get_bool, &value)));
|
||||
case MGP_VALUE_TYPE_INT:
|
||||
return py::Object(PyLong_FromLongLong(mgp_value_get_int(&value)));
|
||||
return py::Object(PyLong_FromLongLong(Call<int64_t>(mgp_value_get_int, &value)));
|
||||
case MGP_VALUE_TYPE_DOUBLE:
|
||||
return py::Object(PyFloat_FromDouble(mgp_value_get_double(&value)));
|
||||
return py::Object(PyFloat_FromDouble(Call<double>(mgp_value_get_double, &value)));
|
||||
case MGP_VALUE_TYPE_STRING:
|
||||
return py::Object(PyUnicode_FromString(mgp_value_get_string(&value)));
|
||||
return py::Object(PyUnicode_FromString(Call<const char *>(mgp_value_get_string, &value)));
|
||||
case MGP_VALUE_TYPE_LIST:
|
||||
return MgpListToPyTuple(mgp_value_get_list(&value), py_graph);
|
||||
return MgpListToPyTuple(Call<const mgp_list *>(mgp_value_get_list, &value), py_graph);
|
||||
case MGP_VALUE_TYPE_MAP: {
|
||||
const auto *map = mgp_value_get_map(&value);
|
||||
const auto *map = Call<const mgp_map *>(mgp_value_get_map, &value);
|
||||
py::Object py_dict(PyDict_New());
|
||||
if (!py_dict) return nullptr;
|
||||
if (!py_dict) {
|
||||
return nullptr;
|
||||
}
|
||||
for (const auto &[key, val] : map->items) {
|
||||
auto py_val = MgpValueToPyObject(val, py_graph);
|
||||
if (!py_val) return nullptr;
|
||||
if (!py_val) {
|
||||
return nullptr;
|
||||
}
|
||||
// Unlike PyList_SET_ITEM, PyDict_SetItem does not steal the value.
|
||||
if (PyDict_SetItemString(py_dict.Ptr(), key.c_str(), py_val.Ptr()) != 0) return nullptr;
|
||||
}
|
||||
@ -1727,21 +1816,21 @@ py::Object MgpValueToPyObject(const mgp_value &value, PyGraph *py_graph) {
|
||||
case MGP_VALUE_TYPE_VERTEX: {
|
||||
py::Object py_mgp(PyImport_ImportModule("mgp"));
|
||||
if (!py_mgp) return nullptr;
|
||||
const auto *v = mgp_value_get_vertex(&value);
|
||||
const auto *v = Call<const mgp_vertex *>(mgp_value_get_vertex, &value);
|
||||
py::Object py_vertex(reinterpret_cast<PyObject *>(MakePyVertex(*v, py_graph)));
|
||||
return py_mgp.CallMethod("Vertex", py_vertex);
|
||||
}
|
||||
case MGP_VALUE_TYPE_EDGE: {
|
||||
py::Object py_mgp(PyImport_ImportModule("mgp"));
|
||||
if (!py_mgp) return nullptr;
|
||||
const auto *e = mgp_value_get_edge(&value);
|
||||
const auto *e = Call<const mgp_edge *>(mgp_value_get_edge, &value);
|
||||
py::Object py_edge(reinterpret_cast<PyObject *>(MakePyEdge(*e, py_graph)));
|
||||
return py_mgp.CallMethod("Edge", py_edge);
|
||||
}
|
||||
case MGP_VALUE_TYPE_PATH: {
|
||||
py::Object py_mgp(PyImport_ImportModule("mgp"));
|
||||
if (!py_mgp) return nullptr;
|
||||
const auto *p = mgp_value_get_path(&value);
|
||||
const auto *p = Call<const mgp_path *>(mgp_value_get_path, &value);
|
||||
py::Object py_path(reinterpret_cast<PyObject *>(MakePyPath(*p, py_graph)));
|
||||
return py_mgp.CallMethod("Path", py_path);
|
||||
}
|
||||
@ -1751,29 +1840,33 @@ py::Object MgpValueToPyObject(const mgp_value &value, PyGraph *py_graph) {
|
||||
mgp_value *PyObjectToMgpValue(PyObject *o, mgp_memory *memory) {
|
||||
auto py_seq_to_list = [memory](PyObject *seq, Py_ssize_t len, const auto &py_seq_get_item) {
|
||||
static_assert(std::numeric_limits<Py_ssize_t>::max() <= std::numeric_limits<size_t>::max());
|
||||
mgp_list *list = mgp_list_make_empty(len, memory);
|
||||
if (!list) throw std::bad_alloc();
|
||||
MgpUniquePtr<mgp_list> list{nullptr, &mgp_list_destroy};
|
||||
if (const auto err = CreateMgpObject<mgp_list>(list, mgp_list_make_empty, len, memory);
|
||||
err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
throw std::bad_alloc{};
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
throw std::runtime_error{"Unexpected error during making mgp_list"};
|
||||
}
|
||||
for (Py_ssize_t i = 0; i < len; ++i) {
|
||||
PyObject *e = py_seq_get_item(seq, i);
|
||||
mgp_value *v{nullptr};
|
||||
try {
|
||||
v = PyObjectToMgpValue(e, memory);
|
||||
} catch (...) {
|
||||
mgp_list_destroy(list);
|
||||
throw;
|
||||
}
|
||||
if (!mgp_list_append(list, v)) {
|
||||
mgp_value_destroy(v);
|
||||
mgp_list_destroy(list);
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
v = PyObjectToMgpValue(e, memory);
|
||||
const auto err = mgp_list_append(list.get(), v);
|
||||
mgp_value_destroy(v);
|
||||
if (err != MGP_ERROR_NO_ERROR) {
|
||||
if (err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
throw std::bad_alloc{};
|
||||
}
|
||||
throw std::runtime_error{"Unexpected error during appending to mgp_list"};
|
||||
}
|
||||
}
|
||||
auto *v = mgp_value_make_list(list);
|
||||
if (!v) {
|
||||
mgp_list_destroy(list);
|
||||
throw std::bad_alloc();
|
||||
mgp_value *v{nullptr};
|
||||
if (const auto err = mgp_value_make_list(list.get(), &v); err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
throw std::bad_alloc{};
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
throw std::runtime_error{"Unexpected error during making mgp_value"};
|
||||
}
|
||||
static_cast<void>(list.release());
|
||||
return v;
|
||||
};
|
||||
|
||||
@ -1802,31 +1895,37 @@ mgp_value *PyObjectToMgpValue(PyObject *o, mgp_memory *memory) {
|
||||
};
|
||||
|
||||
mgp_value *mgp_v{nullptr};
|
||||
mgp_error last_error{MGP_ERROR_NO_ERROR};
|
||||
|
||||
if (o == Py_None) {
|
||||
mgp_v = mgp_value_make_null(memory);
|
||||
last_error = mgp_value_make_null(memory, &mgp_v);
|
||||
} else if (PyBool_Check(o)) {
|
||||
mgp_v = mgp_value_make_bool(static_cast<int>(o == Py_True), memory);
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) Py_True is defined with C-style cast
|
||||
last_error = mgp_value_make_bool(static_cast<int>(o == Py_True), memory, &mgp_v);
|
||||
} else if (PyLong_Check(o)) {
|
||||
int64_t value = PyLong_AsLong(o);
|
||||
if (PyErr_Occurred()) {
|
||||
PyErr_Clear();
|
||||
throw std::overflow_error("Python integer is out of range");
|
||||
}
|
||||
mgp_v = mgp_value_make_int(value, memory);
|
||||
last_error = mgp_value_make_int(value, memory, &mgp_v);
|
||||
} else if (PyFloat_Check(o)) {
|
||||
mgp_v = mgp_value_make_double(PyFloat_AsDouble(o), memory);
|
||||
} else if (PyUnicode_Check(o)) {
|
||||
mgp_v = mgp_value_make_string(PyUnicode_AsUTF8(o), memory);
|
||||
last_error = mgp_value_make_double(PyFloat_AsDouble(o), memory, &mgp_v);
|
||||
} else if (PyUnicode_Check(o)) { // NOLINT(hicpp-signed-bitwise)
|
||||
last_error = mgp_value_make_string(PyUnicode_AsUTF8(o), memory, &mgp_v);
|
||||
} else if (PyList_Check(o)) {
|
||||
mgp_v = py_seq_to_list(o, PyList_Size(o), [](auto *list, const auto i) { return PyList_GET_ITEM(list, i); });
|
||||
} else if (PyTuple_Check(o)) {
|
||||
mgp_v = py_seq_to_list(o, PyTuple_Size(o), [](auto *tuple, const auto i) { return PyTuple_GET_ITEM(tuple, i); });
|
||||
} else if (PyDict_Check(o)) {
|
||||
mgp_map *map = mgp_map_make_empty(memory);
|
||||
} else if (PyDict_Check(o)) { // NOLINT(hicpp-signed-bitwise)
|
||||
MgpUniquePtr<mgp_map> map{nullptr, mgp_map_destroy};
|
||||
const auto map_err = CreateMgpObject(map, mgp_map_make_empty, memory);
|
||||
|
||||
if (!map) {
|
||||
throw std::bad_alloc();
|
||||
if (map_err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
throw std::bad_alloc{};
|
||||
}
|
||||
if (map_err != MGP_ERROR_NO_ERROR) {
|
||||
throw std::runtime_error{"Unexpected error during creating mgp_map"};
|
||||
}
|
||||
|
||||
PyObject *key{nullptr};
|
||||
@ -1834,73 +1933,79 @@ mgp_value *PyObjectToMgpValue(PyObject *o, mgp_memory *memory) {
|
||||
Py_ssize_t pos{0};
|
||||
while (PyDict_Next(o, &pos, &key, &value)) {
|
||||
if (!PyUnicode_Check(key)) {
|
||||
mgp_map_destroy(map);
|
||||
throw std::invalid_argument("Dictionary keys must be strings");
|
||||
}
|
||||
|
||||
const char *k = PyUnicode_AsUTF8(key);
|
||||
mgp_value *v{nullptr};
|
||||
|
||||
if (!k) {
|
||||
PyErr_Clear();
|
||||
mgp_map_destroy(map);
|
||||
throw std::bad_alloc();
|
||||
throw std::bad_alloc{};
|
||||
}
|
||||
|
||||
try {
|
||||
v = PyObjectToMgpValue(value, memory);
|
||||
} catch (...) {
|
||||
mgp_map_destroy(map);
|
||||
throw;
|
||||
}
|
||||
MgpUniquePtr<mgp_value> v{PyObjectToMgpValue(value, memory), mgp_value_destroy};
|
||||
|
||||
if (!mgp_map_insert(map, k, v)) {
|
||||
mgp_value_destroy(v);
|
||||
mgp_map_destroy(map);
|
||||
throw std::bad_alloc();
|
||||
if (const auto err = mgp_map_insert(map.get(), k, v.get()); err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
throw std::bad_alloc{};
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
throw std::runtime_error{"Unexpected error during inserting an item to mgp_map"};
|
||||
}
|
||||
|
||||
mgp_value_destroy(v);
|
||||
}
|
||||
|
||||
mgp_v = mgp_value_make_map(map);
|
||||
if (!mgp_v) {
|
||||
mgp_map_destroy(map);
|
||||
throw std::bad_alloc();
|
||||
if (const auto err = mgp_value_make_map(map.get(), &mgp_v); err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
throw std::bad_alloc{};
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
throw std::runtime_error{"Unexpected error during creating mgp_value"};
|
||||
}
|
||||
static_cast<void>(map.release());
|
||||
} else if (Py_TYPE(o) == &PyEdgeType) {
|
||||
MgpUniquePtr<mgp_edge> e{nullptr, mgp_edge_destroy};
|
||||
// Copy the edge and pass the ownership to the created mgp_value.
|
||||
auto *e = mgp_edge_copy(reinterpret_cast<PyEdge *>(o)->edge, memory);
|
||||
if (!e) {
|
||||
throw std::bad_alloc();
|
||||
|
||||
if (const auto err = CreateMgpObject(e, mgp_edge_copy, reinterpret_cast<PyEdge *>(o)->edge, memory);
|
||||
err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
throw std::bad_alloc{};
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
throw std::runtime_error{"Unexpected error during copying mgp_edge"};
|
||||
}
|
||||
mgp_v = mgp_value_make_edge(e);
|
||||
if (!mgp_v) {
|
||||
mgp_edge_destroy(e);
|
||||
throw std::bad_alloc();
|
||||
if (const auto err = mgp_value_make_edge(e.get(), &mgp_v); err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
throw std::bad_alloc{};
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
throw std::runtime_error{"Unexpected error during copying mgp_edge"};
|
||||
}
|
||||
static_cast<void>(e.release());
|
||||
} else if (Py_TYPE(o) == &PyPathType) {
|
||||
// Copy the path and pass the ownership to the created mgp_value.
|
||||
auto *p = mgp_path_copy(reinterpret_cast<PyPath *>(o)->path, memory);
|
||||
if (!p) {
|
||||
throw std::bad_alloc();
|
||||
MgpUniquePtr<mgp_path> p{nullptr, mgp_path_destroy};
|
||||
// Copy the edge and pass the ownership to the created mgp_value.
|
||||
|
||||
if (const auto err = CreateMgpObject(p, mgp_path_copy, reinterpret_cast<PyPath *>(o)->path, memory);
|
||||
err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
throw std::bad_alloc{};
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
throw std::runtime_error{"Unexpected error during copying mgp_path"};
|
||||
}
|
||||
mgp_v = mgp_value_make_path(p);
|
||||
if (!mgp_v) {
|
||||
mgp_path_destroy(p);
|
||||
throw std::bad_alloc();
|
||||
if (const auto err = mgp_value_make_path(p.get(), &mgp_v); err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
throw std::bad_alloc{};
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
throw std::runtime_error{"Unexpected error during copying mgp_path"};
|
||||
}
|
||||
static_cast<void>(p.release());
|
||||
} else if (Py_TYPE(o) == &PyVertexType) {
|
||||
// Copy the vertex and pass the ownership to the created mgp_value.
|
||||
auto *v = mgp_vertex_copy(reinterpret_cast<PyVertex *>(o)->vertex, memory);
|
||||
if (!v) {
|
||||
throw std::bad_alloc();
|
||||
MgpUniquePtr<mgp_vertex> v{nullptr, mgp_vertex_destroy};
|
||||
// Copy the edge and pass the ownership to the created mgp_value.
|
||||
|
||||
if (const auto err = CreateMgpObject(v, mgp_vertex_copy, reinterpret_cast<PyVertex *>(o)->vertex, memory);
|
||||
err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
throw std::bad_alloc{};
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
throw std::runtime_error{"Unexpected error during copying mgp_vertex"};
|
||||
}
|
||||
mgp_v = mgp_value_make_vertex(v);
|
||||
if (!mgp_v) {
|
||||
mgp_vertex_destroy(v);
|
||||
throw std::bad_alloc();
|
||||
if (const auto err = mgp_value_make_vertex(v.get(), &mgp_v); err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
throw std::bad_alloc{};
|
||||
} else if (err != MGP_ERROR_NO_ERROR) {
|
||||
throw std::runtime_error{"Unexpected error during copying mgp_vertex"};
|
||||
}
|
||||
static_cast<void>(v.release());
|
||||
} else if (is_mgp_instance(o, "Edge")) {
|
||||
py::Object edge(PyObject_GetAttrString(o, "_edge"));
|
||||
if (!edge) {
|
||||
@ -1926,8 +2031,11 @@ mgp_value *PyObjectToMgpValue(PyObject *o, mgp_memory *memory) {
|
||||
throw std::invalid_argument("Unsupported PyObject conversion");
|
||||
}
|
||||
|
||||
if (!mgp_v) {
|
||||
throw std::bad_alloc();
|
||||
if (last_error == MGP_ERROR_UNABLE_TO_ALLOCATE) {
|
||||
throw std::bad_alloc{};
|
||||
}
|
||||
if (last_error != MGP_ERROR_NO_ERROR) {
|
||||
throw std::runtime_error{"Unexpected error while creating mgp_value"};
|
||||
}
|
||||
|
||||
return mgp_v;
|
||||
|
@ -57,7 +57,7 @@ class EdgeAccessor final {
|
||||
/// @throw std::bad_alloc
|
||||
Result<std::map<PropertyId, PropertyValue>> Properties(View view) const;
|
||||
|
||||
Gid Gid() const {
|
||||
Gid Gid() const noexcept {
|
||||
if (config_.properties_on_edges) {
|
||||
return edge_.ptr->gid;
|
||||
} else {
|
||||
@ -67,10 +67,10 @@ class EdgeAccessor final {
|
||||
|
||||
bool IsCycle() const { return from_vertex_ == to_vertex_; }
|
||||
|
||||
bool operator==(const EdgeAccessor &other) const {
|
||||
bool operator==(const EdgeAccessor &other) const noexcept {
|
||||
return edge_ == other.edge_ && transaction_ == other.transaction_;
|
||||
}
|
||||
bool operator!=(const EdgeAccessor &other) const { return !(*this == other); }
|
||||
bool operator!=(const EdgeAccessor &other) const noexcept { return !(*this == other); }
|
||||
|
||||
private:
|
||||
EdgeRef edge_;
|
||||
|
@ -24,8 +24,8 @@ static_assert(std::is_standard_layout_v<Gid>, "The Gid must have a standard layo
|
||||
static_assert(std::is_standard_layout_v<Edge *>, "The Edge * must have a standard layout!");
|
||||
static_assert(std::is_standard_layout_v<EdgeRef>, "The EdgeRef must have a standard layout!");
|
||||
|
||||
inline bool operator==(const EdgeRef &a, const EdgeRef &b) { return a.gid == b.gid; }
|
||||
inline bool operator==(const EdgeRef &a, const EdgeRef &b) noexcept { return a.gid == b.gid; }
|
||||
|
||||
inline bool operator!=(const EdgeRef &a, const EdgeRef &b) { return a.gid != b.gid; }
|
||||
inline bool operator!=(const EdgeRef &a, const EdgeRef &b) noexcept { return a.gid != b.gid; }
|
||||
|
||||
} // namespace storage
|
||||
|
@ -83,12 +83,12 @@ class VertexAccessor final {
|
||||
|
||||
Result<size_t> OutDegree(View view) const;
|
||||
|
||||
Gid Gid() const { return vertex_->gid; }
|
||||
Gid Gid() const noexcept { return vertex_->gid; }
|
||||
|
||||
bool operator==(const VertexAccessor &other) const {
|
||||
bool operator==(const VertexAccessor &other) const noexcept {
|
||||
return vertex_ == other.vertex_ && transaction_ == other.transaction_;
|
||||
}
|
||||
bool operator!=(const VertexAccessor &other) const { return !(*this == other); }
|
||||
bool operator!=(const VertexAccessor &other) const noexcept { return !(*this == other); }
|
||||
|
||||
private:
|
||||
Vertex *vertex_;
|
||||
|
@ -168,7 +168,7 @@ AsyncTimer &AsyncTimer::operator=(AsyncTimer &&other) {
|
||||
return *this;
|
||||
};
|
||||
|
||||
bool AsyncTimer::IsExpired() const {
|
||||
bool AsyncTimer::IsExpired() const noexcept {
|
||||
if (expiration_flag_ != nullptr) {
|
||||
return expiration_flag_->load(std::memory_order_relaxed);
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ class AsyncTimer {
|
||||
AsyncTimer &operator=(const AsyncTimer &) = delete;
|
||||
|
||||
// Returns false if the object isn't associated with any timer.
|
||||
bool IsExpired() const;
|
||||
bool IsExpired() const noexcept;
|
||||
|
||||
private:
|
||||
void ReleaseResources();
|
||||
|
@ -28,6 +28,10 @@ class OnScopeExit {
|
||||
explicit OnScopeExit(const std::function<void()> &function) : function_(function) {}
|
||||
~OnScopeExit() { function_(); }
|
||||
|
||||
void Disable() {
|
||||
function_ = [] {};
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<void()> function_;
|
||||
};
|
||||
|
@ -39,7 +39,6 @@ Checks: '*,
|
||||
-hicpp-vararg,
|
||||
-llvm-header-guard,
|
||||
-misc-non-private-member-variables-in-classes,
|
||||
-misc-unused-parameters,
|
||||
-modernize-avoid-c-arrays,
|
||||
-modernize-concat-nested-namespaces,
|
||||
-modernize-pass-by-value,
|
||||
|
@ -6,26 +6,32 @@ void set_error(struct mgp_result *result) { mgp_result_set_error_msg(result, "So
|
||||
|
||||
static void procedure(const struct mgp_list *args, const struct mgp_graph *graph, struct mgp_result *result,
|
||||
struct mgp_memory *memory) {
|
||||
struct mgp_result_record *record = mgp_result_new_record(result);
|
||||
if (record == NULL) return set_error(result);
|
||||
struct mgp_result_record *record = NULL;
|
||||
const enum mgp_error new_record_err = mgp_result_new_record(result, &record);
|
||||
if (new_record_err != MGP_ERROR_NO_ERROR) return set_error(result);
|
||||
|
||||
struct mgp_value *result_msg = mgp_value_make_string("mgp_init_module allocation works", memory);
|
||||
if (result_msg == NULL) return set_error(result);
|
||||
struct mgp_value *result_msg = NULL;
|
||||
const enum mgp_error make_string_err = mgp_value_make_string("mgp_init_module allocation works", memory, &result_msg);
|
||||
if (make_string_err != MGP_ERROR_NO_ERROR) return set_error(result);
|
||||
|
||||
int result_inserted = mgp_result_record_insert(record, "result", result_msg);
|
||||
const enum mgp_error result_inserted = mgp_result_record_insert(record, "result", result_msg);
|
||||
mgp_value_destroy(result_msg);
|
||||
if (!result_inserted) return set_error(result);
|
||||
if (result_inserted != MGP_ERROR_NO_ERROR) return set_error(result);
|
||||
}
|
||||
|
||||
int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) {
|
||||
const size_t one_gb = 1 << 30;
|
||||
gVal = mgp_global_alloc(one_gb);
|
||||
if (!gVal) return 1;
|
||||
const enum mgp_error alloc_err = mgp_global_alloc(one_gb, &gVal);
|
||||
if (alloc_err != MGP_ERROR_NO_ERROR) return 1;
|
||||
|
||||
struct mgp_proc *proc = mgp_module_add_read_procedure(module, "procedure", procedure);
|
||||
if (!proc) return 1;
|
||||
struct mgp_proc *proc = NULL;
|
||||
const enum mgp_error proc_err = mgp_module_add_read_procedure(module, "procedure", procedure, &proc);
|
||||
if (proc_err != MGP_ERROR_NO_ERROR) return 1;
|
||||
|
||||
if (!mgp_proc_add_result(proc, "result", mgp_type_string())) return 1;
|
||||
const struct mgp_type *string_type = NULL;
|
||||
const enum mgp_error string_type_err = mgp_type_string(&string_type);
|
||||
if (string_type_err != MGP_ERROR_NO_ERROR) return 1;
|
||||
if (mgp_proc_add_result(proc, "result", string_type) != MGP_ERROR_NO_ERROR) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -14,45 +14,57 @@ static void error(const struct mgp_list *args, const struct mgp_graph *graph, st
|
||||
gVal = NULL;
|
||||
}
|
||||
if (!gVal) {
|
||||
gVal = mgp_global_alloc(one_gb);
|
||||
if (!gVal) return set_out_of_memory_error(result);
|
||||
const enum mgp_error err = mgp_global_alloc(one_gb, &gVal);
|
||||
if (err == MGP_ERROR_UNABLE_TO_ALLOCATE) return set_out_of_memory_error(result);
|
||||
if (err != MGP_ERROR_NO_ERROR) return set_error(result);
|
||||
}
|
||||
struct mgp_result_record *record = mgp_result_new_record(result);
|
||||
if (record == NULL) return set_error(result);
|
||||
struct mgp_value *error_value = mgp_value_make_string("ERROR", memory);
|
||||
if (error_value == NULL) return set_error(result);
|
||||
int result_inserted = mgp_result_record_insert(record, "error_result", error_value);
|
||||
struct mgp_result_record *record = NULL;
|
||||
const enum mgp_error new_record_err = mgp_result_new_record(result, &record);
|
||||
if (new_record_err != MGP_ERROR_NO_ERROR) return set_error(result);
|
||||
struct mgp_value *error_value = NULL;
|
||||
const enum mgp_error make_string_err = mgp_value_make_string("ERROR", memory, &error_value);
|
||||
if (make_string_err != MGP_ERROR_NO_ERROR) return set_error(result);
|
||||
const enum mgp_error result_inserted = mgp_result_record_insert(record, "error_result", error_value);
|
||||
mgp_value_destroy(error_value);
|
||||
if (!result_inserted) return set_error(result);
|
||||
if (result_inserted != MGP_ERROR_NO_ERROR) return set_error(result);
|
||||
}
|
||||
|
||||
static void success(const struct mgp_list *args, const struct mgp_graph *graph, struct mgp_result *result,
|
||||
struct mgp_memory *memory) {
|
||||
const size_t bytes = 1024;
|
||||
if (!gVal) {
|
||||
gVal = mgp_global_alloc(bytes);
|
||||
if (!gVal) set_out_of_memory_error(result);
|
||||
const enum mgp_error err = mgp_global_alloc(bytes, &gVal);
|
||||
if (err == MGP_ERROR_UNABLE_TO_ALLOCATE) return set_out_of_memory_error(result);
|
||||
if (err != MGP_ERROR_NO_ERROR) return set_error(result);
|
||||
}
|
||||
|
||||
struct mgp_result_record *record = mgp_result_new_record(result);
|
||||
if (record == NULL) return set_error(result);
|
||||
struct mgp_value *success_value = mgp_value_make_string("sucess", memory);
|
||||
if (success_value == NULL) return set_error(result);
|
||||
int result_inserted = mgp_result_record_insert(record, "success_result", success_value);
|
||||
struct mgp_result_record *record = NULL;
|
||||
const enum mgp_error new_record_err = mgp_result_new_record(result, &record);
|
||||
if (new_record_err != MGP_ERROR_NO_ERROR) return set_error(result);
|
||||
|
||||
struct mgp_value *success_value = NULL;
|
||||
const enum mgp_error make_string_err = mgp_value_make_string("sucess", memory, &success_value);
|
||||
if (make_string_err != MGP_ERROR_NO_ERROR) return set_error(result);
|
||||
const enum mgp_error result_inserted = mgp_result_record_insert(record, "success_result", success_value);
|
||||
mgp_value_destroy(success_value);
|
||||
if (!result_inserted) return set_error(result);
|
||||
if (result_inserted != MGP_ERROR_NO_ERROR) return set_error(result);
|
||||
}
|
||||
|
||||
int mgp_init_module(struct mgp_module *module, struct mgp_memory *memory) {
|
||||
struct mgp_proc *error_proc = mgp_module_add_read_procedure(module, "error", error);
|
||||
if (!error_proc) return 1;
|
||||
struct mgp_proc *error_proc = NULL;
|
||||
const enum mgp_error error_proc_err = mgp_module_add_read_procedure(module, "error", error, &error_proc);
|
||||
if (error_proc_err != MGP_ERROR_NO_ERROR) return 1;
|
||||
|
||||
if (!mgp_proc_add_result(error_proc, "error_result", mgp_type_string())) return 1;
|
||||
const struct mgp_type *string_type = NULL;
|
||||
const enum mgp_error string_type_err = mgp_type_string(&string_type);
|
||||
if (string_type_err != MGP_ERROR_NO_ERROR) return 1;
|
||||
if (mgp_proc_add_result(error_proc, "error_result", string_type) != MGP_ERROR_NO_ERROR) return 1;
|
||||
|
||||
struct mgp_proc *succ_proc = mgp_module_add_read_procedure(module, "success", success);
|
||||
if (!succ_proc) return 1;
|
||||
struct mgp_proc *succ_proc = NULL;
|
||||
const enum mgp_error succ_proc_err = mgp_module_add_read_procedure(module, "success", success, &succ_proc);
|
||||
if (succ_proc_err != MGP_ERROR_NO_ERROR) return 1;
|
||||
|
||||
if (!mgp_proc_add_result(succ_proc, "success_result", mgp_type_string())) return 1;
|
||||
if (mgp_proc_add_result(succ_proc, "success_result", string_type) != MGP_ERROR_NO_ERROR) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "integrations/kafka/consumer.hpp"
|
||||
#include "query/procedure/mg_procedure_impl.hpp"
|
||||
#include "test_utils.hpp"
|
||||
#include "utils/pmr/vector.hpp"
|
||||
|
||||
/// This class implements the interface of RdKafka::Message such that it can be mocked.
|
||||
@ -133,20 +134,21 @@ class MgpApiTest : public ::testing::Test {
|
||||
|
||||
TEST_F(MgpApiTest, TestAllMgpKafkaCApi) {
|
||||
const mgp_messages &messages = Messages();
|
||||
EXPECT_EQ(mgp_messages_size(&messages), expected.size());
|
||||
EXPECT_EQ(EXPECT_MGP_NO_ERROR(size_t, mgp_messages_size, &messages), expected.size());
|
||||
|
||||
for (int i = 0; i < expected.size(); ++i) {
|
||||
const auto *message = mgp_messages_at(&messages, i);
|
||||
const auto *message = EXPECT_MGP_NO_ERROR(const mgp_message *, mgp_messages_at, &messages, i);
|
||||
// Test for key and key size. Key size is always 1 in this test.
|
||||
EXPECT_EQ(mgp_message_key_size(message), 1);
|
||||
EXPECT_EQ(*mgp_message_key(message), expected[i].key);
|
||||
EXPECT_EQ(EXPECT_MGP_NO_ERROR(size_t, mgp_message_key_size, message), 1);
|
||||
EXPECT_EQ(*EXPECT_MGP_NO_ERROR(const char *, mgp_message_key, message), expected[i].key);
|
||||
|
||||
// Test for payload size
|
||||
EXPECT_EQ(mgp_message_payload_size(message), expected[i].payload_size);
|
||||
EXPECT_EQ(EXPECT_MGP_NO_ERROR(size_t, mgp_message_payload_size, message), expected[i].payload_size);
|
||||
// Test for payload
|
||||
EXPECT_FALSE(std::strcmp(mgp_message_payload(message), expected[i].payload));
|
||||
EXPECT_FALSE(std::strcmp(EXPECT_MGP_NO_ERROR(const char *, mgp_message_payload, message), expected[i].payload));
|
||||
// Test for topic name
|
||||
EXPECT_FALSE(std::strcmp(mgp_message_topic_name(message), expected[i].topic_name));
|
||||
EXPECT_FALSE(
|
||||
std::strcmp(EXPECT_MGP_NO_ERROR(const char *, mgp_message_topic_name, message), expected[i].topic_name));
|
||||
}
|
||||
|
||||
// Unfortunately, we can't test timestamp here because we can't mock (as explained above)
|
||||
|
@ -13,13 +13,13 @@ TEST(MgpTransTest, TestMgpTransApi) {
|
||||
// for different string cases as these are all handled by
|
||||
// IsValidIdentifier().
|
||||
// Maybe add a mock instead and expect IsValidIdentifier() to be called once?
|
||||
EXPECT_FALSE(mgp_module_add_transformation(&module, "dash-dash", no_op_cb));
|
||||
EXPECT_TRUE(module.transformations.size() == 0);
|
||||
EXPECT_EQ(mgp_module_add_transformation(&module, "dash-dash", no_op_cb), MGP_ERROR_INVALID_ARGUMENT);
|
||||
EXPECT_TRUE(module.transformations.empty());
|
||||
|
||||
EXPECT_TRUE(mgp_module_add_transformation(&module, "transform", no_op_cb));
|
||||
EXPECT_EQ(mgp_module_add_transformation(&module, "transform", no_op_cb), MGP_ERROR_NO_ERROR);
|
||||
EXPECT_NE(module.transformations.find("transform"), module.transformations.end());
|
||||
|
||||
// Try to register a transformation twice
|
||||
EXPECT_FALSE(mgp_module_add_transformation(&module, "transform", no_op_cb));
|
||||
EXPECT_EQ(mgp_module_add_transformation(&module, "transform", no_op_cb), MGP_ERROR_LOGIC_ERROR);
|
||||
EXPECT_TRUE(module.transformations.size() == 1);
|
||||
}
|
||||
|
@ -11,34 +11,42 @@ static void DummyCallback(const mgp_list *, const mgp_graph *, mgp_result *, mgp
|
||||
|
||||
TEST(Module, InvalidProcedureRegistration) {
|
||||
mgp_module module(utils::NewDeleteResource());
|
||||
EXPECT_FALSE(mgp_module_add_read_procedure(&module, "dashes-not-supported", DummyCallback));
|
||||
mgp_proc *proc{nullptr};
|
||||
EXPECT_EQ(mgp_module_add_read_procedure(&module, "dashes-not-supported", DummyCallback, &proc),
|
||||
MGP_ERROR_INVALID_ARGUMENT);
|
||||
// as u8string this is u8"unicode\u22c6not\u2014supported"
|
||||
EXPECT_FALSE(mgp_module_add_read_procedure(&module, "unicode\xE2\x8B\x86not\xE2\x80\x94supported", DummyCallback));
|
||||
EXPECT_EQ(mgp_module_add_read_procedure(&module, "unicode\xE2\x8B\x86not\xE2\x80\x94supported", DummyCallback, &proc),
|
||||
MGP_ERROR_INVALID_ARGUMENT);
|
||||
// as u8string this is u8"`backticks⋆\u22c6won't-save\u2014you`"
|
||||
EXPECT_FALSE(
|
||||
mgp_module_add_read_procedure(&module, "`backticks⋆\xE2\x8B\x86won't-save\xE2\x80\x94you`", DummyCallback));
|
||||
EXPECT_FALSE(mgp_module_add_read_procedure(&module, "42_name_must_not_start_with_number", DummyCallback));
|
||||
EXPECT_FALSE(mgp_module_add_read_procedure(&module, "div/", DummyCallback));
|
||||
EXPECT_FALSE(mgp_module_add_read_procedure(&module, "mul*", DummyCallback));
|
||||
EXPECT_FALSE(mgp_module_add_read_procedure(&module, "question_mark_is_not_valid?", DummyCallback));
|
||||
EXPECT_EQ(
|
||||
mgp_module_add_read_procedure(&module, "`backticks⋆\xE2\x8B\x86won't-save\xE2\x80\x94you`", DummyCallback, &proc),
|
||||
MGP_ERROR_INVALID_ARGUMENT);
|
||||
EXPECT_EQ(mgp_module_add_read_procedure(&module, "42_name_must_not_start_with_number", DummyCallback, &proc),
|
||||
MGP_ERROR_INVALID_ARGUMENT);
|
||||
EXPECT_EQ(mgp_module_add_read_procedure(&module, "div/", DummyCallback, &proc), MGP_ERROR_INVALID_ARGUMENT);
|
||||
EXPECT_EQ(mgp_module_add_read_procedure(&module, "mul*", DummyCallback, &proc), MGP_ERROR_INVALID_ARGUMENT);
|
||||
EXPECT_EQ(mgp_module_add_read_procedure(&module, "question_mark_is_not_valid?", DummyCallback, &proc),
|
||||
MGP_ERROR_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
TEST(Module, RegisteringTheSameProcedureMultipleTimes) {
|
||||
mgp_module module(utils::NewDeleteResource());
|
||||
mgp_proc *proc{nullptr};
|
||||
EXPECT_EQ(module.procedures.find("same_name"), module.procedures.end());
|
||||
EXPECT_TRUE(mgp_module_add_read_procedure(&module, "same_name", DummyCallback));
|
||||
EXPECT_EQ(mgp_module_add_read_procedure(&module, "same_name", DummyCallback, &proc), MGP_ERROR_NO_ERROR);
|
||||
EXPECT_NE(module.procedures.find("same_name"), module.procedures.end());
|
||||
EXPECT_FALSE(mgp_module_add_read_procedure(&module, "same_name", DummyCallback));
|
||||
EXPECT_FALSE(mgp_module_add_read_procedure(&module, "same_name", DummyCallback));
|
||||
EXPECT_EQ(mgp_module_add_read_procedure(&module, "same_name", DummyCallback, &proc), MGP_ERROR_LOGIC_ERROR);
|
||||
EXPECT_EQ(mgp_module_add_read_procedure(&module, "same_name", DummyCallback, &proc), MGP_ERROR_LOGIC_ERROR);
|
||||
EXPECT_NE(module.procedures.find("same_name"), module.procedures.end());
|
||||
}
|
||||
|
||||
TEST(Module, CaseSensitiveProcedureNames) {
|
||||
mgp_module module(utils::NewDeleteResource());
|
||||
EXPECT_TRUE(module.procedures.empty());
|
||||
EXPECT_TRUE(mgp_module_add_read_procedure(&module, "not_same", DummyCallback));
|
||||
EXPECT_TRUE(mgp_module_add_read_procedure(&module, "NoT_saME", DummyCallback));
|
||||
EXPECT_TRUE(mgp_module_add_read_procedure(&module, "NOT_SAME", DummyCallback));
|
||||
mgp_proc *proc{nullptr};
|
||||
EXPECT_EQ(mgp_module_add_read_procedure(&module, "not_same", DummyCallback, &proc), MGP_ERROR_NO_ERROR);
|
||||
EXPECT_EQ(mgp_module_add_read_procedure(&module, "NoT_saME", DummyCallback, &proc), MGP_ERROR_NO_ERROR);
|
||||
EXPECT_EQ(mgp_module_add_read_procedure(&module, "NOT_SAME", DummyCallback, &proc), MGP_ERROR_NO_ERROR);
|
||||
EXPECT_EQ(module.procedures.size(), 3U);
|
||||
}
|
||||
|
||||
@ -51,29 +59,42 @@ static void CheckSignature(const mgp_proc *proc, const std::string &expected) {
|
||||
TEST(Module, ProcedureSignature) {
|
||||
mgp_memory memory{utils::NewDeleteResource()};
|
||||
mgp_module module(utils::NewDeleteResource());
|
||||
auto *proc = mgp_module_add_read_procedure(&module, "proc", DummyCallback);
|
||||
auto *proc = EXPECT_MGP_NO_ERROR(mgp_proc *, mgp_module_add_read_procedure, &module, "proc", &DummyCallback);
|
||||
CheckSignature(proc, "proc() :: ()");
|
||||
mgp_proc_add_arg(proc, "arg1", mgp_type_number());
|
||||
EXPECT_EQ(mgp_proc_add_arg(proc, "arg1", EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_number)), MGP_ERROR_NO_ERROR);
|
||||
CheckSignature(proc, "proc(arg1 :: NUMBER) :: ()");
|
||||
mgp_proc_add_opt_arg(proc, "opt1", mgp_type_nullable(mgp_type_any()),
|
||||
test_utils::CreateValueOwningPtr(mgp_value_make_null(&memory)).get());
|
||||
EXPECT_EQ(
|
||||
mgp_proc_add_opt_arg(
|
||||
proc, "opt1",
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_nullable, EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_any)),
|
||||
test_utils::CreateValueOwningPtr(EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_null, &memory)).get()),
|
||||
MGP_ERROR_NO_ERROR);
|
||||
CheckSignature(proc, "proc(arg1 :: NUMBER, opt1 = Null :: ANY?) :: ()");
|
||||
mgp_proc_add_result(proc, "res1", mgp_type_list(mgp_type_int()));
|
||||
EXPECT_EQ(mgp_proc_add_result(proc, "res1",
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_list,
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_int))),
|
||||
MGP_ERROR_NO_ERROR);
|
||||
CheckSignature(proc, "proc(arg1 :: NUMBER, opt1 = Null :: ANY?) :: (res1 :: LIST OF INTEGER)");
|
||||
EXPECT_FALSE(mgp_proc_add_arg(proc, "arg2", mgp_type_number()));
|
||||
EXPECT_EQ(mgp_proc_add_arg(proc, "arg2", EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_number)),
|
||||
MGP_ERROR_LOGIC_ERROR);
|
||||
CheckSignature(proc, "proc(arg1 :: NUMBER, opt1 = Null :: ANY?) :: (res1 :: LIST OF INTEGER)");
|
||||
EXPECT_FALSE(mgp_proc_add_arg(proc, "arg2", mgp_type_map()));
|
||||
CheckSignature(proc,
|
||||
"proc(arg1 :: NUMBER, opt1 = Null :: ANY?) :: "
|
||||
"(res1 :: LIST OF INTEGER)");
|
||||
mgp_proc_add_deprecated_result(proc, "res2", mgp_type_string());
|
||||
EXPECT_EQ(mgp_proc_add_arg(proc, "arg2", EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_map)), MGP_ERROR_LOGIC_ERROR);
|
||||
CheckSignature(proc, "proc(arg1 :: NUMBER, opt1 = Null :: ANY?) :: (res1 :: LIST OF INTEGER)");
|
||||
EXPECT_EQ(mgp_proc_add_deprecated_result(proc, "res2", EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_string)),
|
||||
MGP_ERROR_NO_ERROR);
|
||||
CheckSignature(proc,
|
||||
"proc(arg1 :: NUMBER, opt1 = Null :: ANY?) :: "
|
||||
"(res1 :: LIST OF INTEGER, DEPRECATED res2 :: STRING)");
|
||||
EXPECT_FALSE(mgp_proc_add_result(proc, "res2", mgp_type_any()));
|
||||
EXPECT_FALSE(mgp_proc_add_deprecated_result(proc, "res1", mgp_type_any()));
|
||||
mgp_proc_add_opt_arg(proc, "opt2", mgp_type_string(),
|
||||
test_utils::CreateValueOwningPtr(mgp_value_make_string("string=\"value\"", &memory)).get());
|
||||
EXPECT_EQ(mgp_proc_add_result(proc, "res2", EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_any)),
|
||||
MGP_ERROR_LOGIC_ERROR);
|
||||
EXPECT_EQ(mgp_proc_add_deprecated_result(proc, "res1", EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_any)),
|
||||
MGP_ERROR_LOGIC_ERROR);
|
||||
EXPECT_EQ(
|
||||
mgp_proc_add_opt_arg(proc, "opt2", EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_string),
|
||||
test_utils::CreateValueOwningPtr(
|
||||
EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_string, "string=\"value\"", &memory))
|
||||
.get()),
|
||||
MGP_ERROR_NO_ERROR);
|
||||
CheckSignature(proc,
|
||||
"proc(arg1 :: NUMBER, opt1 = Null :: ANY?, "
|
||||
"opt2 = \"string=\\\"value\\\"\" :: STRING) :: "
|
||||
@ -83,8 +104,12 @@ TEST(Module, ProcedureSignature) {
|
||||
TEST(Module, ProcedureSignatureOnlyOptArg) {
|
||||
mgp_memory memory{utils::NewDeleteResource()};
|
||||
mgp_module module(utils::NewDeleteResource());
|
||||
auto *proc = mgp_module_add_read_procedure(&module, "proc", DummyCallback);
|
||||
mgp_proc_add_opt_arg(proc, "opt1", mgp_type_nullable(mgp_type_any()),
|
||||
test_utils::CreateValueOwningPtr(mgp_value_make_null(&memory)).get());
|
||||
auto *proc = EXPECT_MGP_NO_ERROR(mgp_proc *, mgp_module_add_read_procedure, &module, "proc", &DummyCallback);
|
||||
EXPECT_EQ(
|
||||
mgp_proc_add_opt_arg(
|
||||
proc, "opt1",
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_nullable, EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_any)),
|
||||
test_utils::CreateValueOwningPtr(EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_null, &memory)).get()),
|
||||
MGP_ERROR_NO_ERROR);
|
||||
CheckSignature(proc, "proc(opt1 = Null :: ANY?) :: ()");
|
||||
}
|
||||
|
@ -9,46 +9,63 @@
|
||||
#include "test_utils.hpp"
|
||||
|
||||
TEST(CypherType, PresentableNameSimpleTypes) {
|
||||
EXPECT_EQ(mgp_type_any()->impl->GetPresentableName(), "ANY");
|
||||
EXPECT_EQ(mgp_type_bool()->impl->GetPresentableName(), "BOOLEAN");
|
||||
EXPECT_EQ(mgp_type_string()->impl->GetPresentableName(), "STRING");
|
||||
EXPECT_EQ(mgp_type_int()->impl->GetPresentableName(), "INTEGER");
|
||||
EXPECT_EQ(mgp_type_float()->impl->GetPresentableName(), "FLOAT");
|
||||
EXPECT_EQ(mgp_type_number()->impl->GetPresentableName(), "NUMBER");
|
||||
EXPECT_EQ(mgp_type_map()->impl->GetPresentableName(), "MAP");
|
||||
EXPECT_EQ(mgp_type_node()->impl->GetPresentableName(), "NODE");
|
||||
EXPECT_EQ(mgp_type_relationship()->impl->GetPresentableName(), "RELATIONSHIP");
|
||||
EXPECT_EQ(mgp_type_path()->impl->GetPresentableName(), "PATH");
|
||||
EXPECT_EQ(EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_any)->impl->GetPresentableName(), "ANY");
|
||||
EXPECT_EQ(EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_bool)->impl->GetPresentableName(), "BOOLEAN");
|
||||
EXPECT_EQ(EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_string)->impl->GetPresentableName(), "STRING");
|
||||
EXPECT_EQ(EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_int)->impl->GetPresentableName(), "INTEGER");
|
||||
EXPECT_EQ(EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_float)->impl->GetPresentableName(), "FLOAT");
|
||||
EXPECT_EQ(EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_number)->impl->GetPresentableName(), "NUMBER");
|
||||
EXPECT_EQ(EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_map)->impl->GetPresentableName(), "MAP");
|
||||
EXPECT_EQ(EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_node)->impl->GetPresentableName(), "NODE");
|
||||
EXPECT_EQ(EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_relationship)->impl->GetPresentableName(), "RELATIONSHIP");
|
||||
EXPECT_EQ(EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_path)->impl->GetPresentableName(), "PATH");
|
||||
}
|
||||
|
||||
TEST(CypherType, PresentableNameCompositeTypes) {
|
||||
const mgp_type *any_type = EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_any);
|
||||
{
|
||||
const auto *nullable_any = mgp_type_nullable(mgp_type_any());
|
||||
const auto *nullable_any = EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_nullable, any_type);
|
||||
EXPECT_EQ(nullable_any->impl->GetPresentableName(), "ANY?");
|
||||
}
|
||||
{
|
||||
const auto *nullable_any = mgp_type_nullable(mgp_type_nullable(mgp_type_any()));
|
||||
const auto *nullable_any =
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_nullable,
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_nullable,
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_nullable, any_type)));
|
||||
EXPECT_EQ(nullable_any->impl->GetPresentableName(), "ANY?");
|
||||
}
|
||||
{
|
||||
const auto *nullable_list = mgp_type_nullable(mgp_type_list(mgp_type_any()));
|
||||
const auto *nullable_list = EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_nullable,
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_list, any_type));
|
||||
EXPECT_EQ(nullable_list->impl->GetPresentableName(), "LIST? OF ANY");
|
||||
}
|
||||
{
|
||||
const auto *list_of_int = mgp_type_list(mgp_type_int());
|
||||
const auto *list_of_int =
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_list, EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_int));
|
||||
EXPECT_EQ(list_of_int->impl->GetPresentableName(), "LIST OF INTEGER");
|
||||
}
|
||||
{
|
||||
const auto *list_of_nullable_path = mgp_type_list(mgp_type_nullable(mgp_type_path()));
|
||||
const auto *list_of_nullable_path = EXPECT_MGP_NO_ERROR(
|
||||
const mgp_type *, mgp_type_list,
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_nullable, EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_path)));
|
||||
EXPECT_EQ(list_of_nullable_path->impl->GetPresentableName(), "LIST OF PATH?");
|
||||
}
|
||||
{
|
||||
const auto *list_of_list_of_map = mgp_type_list(mgp_type_list(mgp_type_map()));
|
||||
const auto *list_of_list_of_map = EXPECT_MGP_NO_ERROR(
|
||||
const mgp_type *, mgp_type_list,
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_list, EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_map)));
|
||||
EXPECT_EQ(list_of_list_of_map->impl->GetPresentableName(), "LIST OF LIST OF MAP");
|
||||
}
|
||||
{
|
||||
const auto *nullable_list_of_nullable_list_of_nullable_string =
|
||||
mgp_type_nullable(mgp_type_list(mgp_type_nullable(mgp_type_list(mgp_type_nullable(mgp_type_string())))));
|
||||
const auto *nullable_list_of_nullable_list_of_nullable_string = EXPECT_MGP_NO_ERROR(
|
||||
const mgp_type *, mgp_type_nullable,
|
||||
EXPECT_MGP_NO_ERROR(
|
||||
const mgp_type *, mgp_type_list,
|
||||
EXPECT_MGP_NO_ERROR(
|
||||
const mgp_type *, mgp_type_nullable,
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_list,
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_nullable,
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_string))))));
|
||||
EXPECT_EQ(nullable_list_of_nullable_list_of_nullable_string->impl->GetPresentableName(),
|
||||
"LIST? OF LIST? OF STRING?");
|
||||
}
|
||||
@ -57,17 +74,26 @@ TEST(CypherType, PresentableNameCompositeTypes) {
|
||||
TEST(CypherType, NullSatisfiesType) {
|
||||
mgp_memory memory{utils::NewDeleteResource()};
|
||||
{
|
||||
auto *mgp_null = mgp_value_make_null(&memory);
|
||||
auto *mgp_null = EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_null, &memory);
|
||||
const query::TypedValue tv_null;
|
||||
std::vector<const mgp_type *> primitive_types{
|
||||
mgp_type_any(), mgp_type_bool(), mgp_type_string(), mgp_type_int(), mgp_type_float(),
|
||||
mgp_type_number(), mgp_type_map(), mgp_type_node(), mgp_type_relationship(), mgp_type_path()};
|
||||
std::vector<const mgp_type *> primitive_types{EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_any),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_bool),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_string),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_int),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_float),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_number),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_map),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_node),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_relationship),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_path)};
|
||||
for (const auto *primitive_type : primitive_types) {
|
||||
for (const auto *type :
|
||||
{primitive_type, mgp_type_list(primitive_type), mgp_type_list(mgp_type_nullable(primitive_type))}) {
|
||||
{primitive_type, EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_list, primitive_type),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_list,
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_nullable, primitive_type))}) {
|
||||
EXPECT_FALSE(type->impl->SatisfiesType(*mgp_null));
|
||||
EXPECT_FALSE(type->impl->SatisfiesType(tv_null));
|
||||
const auto *null_type = mgp_type_nullable(type);
|
||||
const auto *null_type = EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_nullable, type);
|
||||
EXPECT_TRUE(null_type->impl->SatisfiesType(*mgp_null));
|
||||
EXPECT_TRUE(null_type->impl->SatisfiesType(tv_null));
|
||||
}
|
||||
@ -81,7 +107,7 @@ static void CheckSatisfiesTypesAndNullable(const mgp_value *mgp_val, const query
|
||||
for (const auto *type : types) {
|
||||
EXPECT_TRUE(type->impl->SatisfiesType(*mgp_val)) << type->impl->GetPresentableName();
|
||||
EXPECT_TRUE(type->impl->SatisfiesType(tv));
|
||||
const auto *null_type = mgp_type_nullable(type);
|
||||
const auto *null_type = EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_nullable, type);
|
||||
EXPECT_TRUE(null_type->impl->SatisfiesType(*mgp_val)) << null_type->impl->GetPresentableName();
|
||||
EXPECT_TRUE(null_type->impl->SatisfiesType(tv));
|
||||
}
|
||||
@ -90,10 +116,13 @@ static void CheckSatisfiesTypesAndNullable(const mgp_value *mgp_val, const query
|
||||
static void CheckNotSatisfiesTypesAndListAndNullable(const mgp_value *mgp_val, const query::TypedValue &tv,
|
||||
const std::vector<const mgp_type *> &elem_types) {
|
||||
for (const auto *elem_type : elem_types) {
|
||||
for (const auto *type : {elem_type, mgp_type_list(elem_type), mgp_type_list(mgp_type_nullable(elem_type))}) {
|
||||
for (const auto *type :
|
||||
{elem_type, EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_list, elem_type),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_list,
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_nullable, elem_type))}) {
|
||||
EXPECT_FALSE(type->impl->SatisfiesType(*mgp_val)) << type->impl->GetPresentableName();
|
||||
EXPECT_FALSE(type->impl->SatisfiesType(tv));
|
||||
const auto *null_type = mgp_type_nullable(type);
|
||||
const auto *null_type = EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_nullable, type);
|
||||
EXPECT_FALSE(null_type->impl->SatisfiesType(*mgp_val)) << null_type->impl->GetPresentableName();
|
||||
EXPECT_FALSE(null_type->impl->SatisfiesType(tv));
|
||||
}
|
||||
@ -102,59 +131,94 @@ static void CheckNotSatisfiesTypesAndListAndNullable(const mgp_value *mgp_val, c
|
||||
|
||||
TEST(CypherType, BoolSatisfiesType) {
|
||||
mgp_memory memory{utils::NewDeleteResource()};
|
||||
auto *mgp_bool = mgp_value_make_bool(1, &memory);
|
||||
auto *mgp_bool = EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_bool, 1, &memory);
|
||||
const query::TypedValue tv_bool(true);
|
||||
CheckSatisfiesTypesAndNullable(mgp_bool, tv_bool, {mgp_type_any(), mgp_type_bool()});
|
||||
CheckNotSatisfiesTypesAndListAndNullable(mgp_bool, tv_bool,
|
||||
{mgp_type_string(), mgp_type_int(), mgp_type_float(), mgp_type_number(),
|
||||
mgp_type_map(), mgp_type_node(), mgp_type_relationship(), mgp_type_path()});
|
||||
CheckSatisfiesTypesAndNullable(
|
||||
mgp_bool, tv_bool,
|
||||
{EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_any), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_bool)});
|
||||
CheckNotSatisfiesTypesAndListAndNullable(
|
||||
mgp_bool, tv_bool,
|
||||
{EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_string), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_int),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_float), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_number),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_map), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_node),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_relationship),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_path)});
|
||||
mgp_value_destroy(mgp_bool);
|
||||
}
|
||||
|
||||
TEST(CypherType, IntSatisfiesType) {
|
||||
mgp_memory memory{utils::NewDeleteResource()};
|
||||
auto *mgp_int = mgp_value_make_int(42, &memory);
|
||||
auto *mgp_int = EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_int, 42, &memory);
|
||||
const query::TypedValue tv_int(42);
|
||||
CheckSatisfiesTypesAndNullable(mgp_int, tv_int, {mgp_type_any(), mgp_type_int(), mgp_type_number()});
|
||||
CheckNotSatisfiesTypesAndListAndNullable(mgp_int, tv_int,
|
||||
{mgp_type_bool(), mgp_type_string(), mgp_type_float(), mgp_type_map(),
|
||||
mgp_type_node(), mgp_type_relationship(), mgp_type_path()});
|
||||
CheckSatisfiesTypesAndNullable(
|
||||
mgp_int, tv_int,
|
||||
{EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_any), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_int),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_number)});
|
||||
CheckNotSatisfiesTypesAndListAndNullable(
|
||||
mgp_int, tv_int,
|
||||
{EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_bool), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_string),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_float), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_map),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_node),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_relationship),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_path)});
|
||||
mgp_value_destroy(mgp_int);
|
||||
}
|
||||
|
||||
TEST(CypherType, DoubleSatisfiesType) {
|
||||
mgp_memory memory{utils::NewDeleteResource()};
|
||||
auto *mgp_double = mgp_value_make_double(42, &memory);
|
||||
auto *mgp_double = EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_double, 42, &memory);
|
||||
const query::TypedValue tv_double(42.0);
|
||||
CheckSatisfiesTypesAndNullable(mgp_double, tv_double, {mgp_type_any(), mgp_type_float(), mgp_type_number()});
|
||||
CheckNotSatisfiesTypesAndListAndNullable(mgp_double, tv_double,
|
||||
{mgp_type_bool(), mgp_type_string(), mgp_type_int(), mgp_type_map(),
|
||||
mgp_type_node(), mgp_type_relationship(), mgp_type_path()});
|
||||
CheckSatisfiesTypesAndNullable(
|
||||
mgp_double, tv_double,
|
||||
{EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_any), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_float),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_number)});
|
||||
CheckNotSatisfiesTypesAndListAndNullable(
|
||||
mgp_double, tv_double,
|
||||
{EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_bool), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_string),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_int), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_map),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_node),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_relationship),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_path)});
|
||||
mgp_value_destroy(mgp_double);
|
||||
}
|
||||
|
||||
TEST(CypherType, StringSatisfiesType) {
|
||||
mgp_memory memory{utils::NewDeleteResource()};
|
||||
auto *mgp_string = mgp_value_make_string("text", &memory);
|
||||
auto *mgp_string = EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_string, "text", &memory);
|
||||
const query::TypedValue tv_string("text");
|
||||
CheckSatisfiesTypesAndNullable(mgp_string, tv_string, {mgp_type_any(), mgp_type_string()});
|
||||
CheckNotSatisfiesTypesAndListAndNullable(mgp_string, tv_string,
|
||||
{mgp_type_bool(), mgp_type_int(), mgp_type_float(), mgp_type_number(),
|
||||
mgp_type_map(), mgp_type_node(), mgp_type_relationship(), mgp_type_path()});
|
||||
CheckSatisfiesTypesAndNullable(
|
||||
mgp_string, tv_string,
|
||||
{EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_any), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_string)});
|
||||
CheckNotSatisfiesTypesAndListAndNullable(
|
||||
mgp_string, tv_string,
|
||||
{EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_bool), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_int),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_float), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_number),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_map), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_node),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_relationship),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_path)});
|
||||
mgp_value_destroy(mgp_string);
|
||||
}
|
||||
|
||||
TEST(CypherType, MapSatisfiesType) {
|
||||
mgp_memory memory{utils::NewDeleteResource()};
|
||||
auto *map = mgp_map_make_empty(&memory);
|
||||
mgp_map_insert(map, "key", test_utils::CreateValueOwningPtr(mgp_value_make_int(42, &memory)).get());
|
||||
auto *mgp_map_v = mgp_value_make_map(map);
|
||||
auto *map = EXPECT_MGP_NO_ERROR(mgp_map *, mgp_map_make_empty, &memory);
|
||||
EXPECT_EQ(
|
||||
mgp_map_insert(
|
||||
map, "key",
|
||||
test_utils::CreateValueOwningPtr(EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_int, 42, &memory)).get()),
|
||||
MGP_ERROR_NO_ERROR);
|
||||
auto *mgp_map_v = EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_map, map);
|
||||
const query::TypedValue tv_map(std::map<std::string, query::TypedValue>{{"key", query::TypedValue(42)}});
|
||||
CheckSatisfiesTypesAndNullable(mgp_map_v, tv_map, {mgp_type_any(), mgp_type_map()});
|
||||
CheckSatisfiesTypesAndNullable(
|
||||
mgp_map_v, tv_map,
|
||||
{EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_any), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_map)});
|
||||
CheckNotSatisfiesTypesAndListAndNullable(
|
||||
mgp_map_v, tv_map,
|
||||
{mgp_type_bool(), mgp_type_string(), mgp_type_int(), mgp_type_float(), mgp_type_number(), mgp_type_node(),
|
||||
mgp_type_relationship(), mgp_type_path()});
|
||||
{EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_bool), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_string),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_int), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_float),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_number), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_node),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_relationship),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_path)});
|
||||
mgp_value_destroy(mgp_map_v);
|
||||
}
|
||||
|
||||
@ -166,12 +230,20 @@ TEST(CypherType, VertexSatisfiesType) {
|
||||
mgp_memory memory{utils::NewDeleteResource()};
|
||||
utils::Allocator<mgp_vertex> alloc(memory.impl);
|
||||
mgp_graph graph{&dba, storage::View::NEW};
|
||||
auto *mgp_vertex_v = mgp_value_make_vertex(alloc.new_object<mgp_vertex>(vertex, &graph));
|
||||
auto *mgp_vertex_v =
|
||||
EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_vertex, alloc.new_object<mgp_vertex>(vertex, &graph));
|
||||
const query::TypedValue tv_vertex(vertex);
|
||||
CheckSatisfiesTypesAndNullable(mgp_vertex_v, tv_vertex, {mgp_type_any(), mgp_type_node(), mgp_type_map()});
|
||||
CheckNotSatisfiesTypesAndListAndNullable(mgp_vertex_v, tv_vertex,
|
||||
{mgp_type_bool(), mgp_type_string(), mgp_type_int(), mgp_type_float(),
|
||||
mgp_type_number(), mgp_type_relationship(), mgp_type_path()});
|
||||
CheckSatisfiesTypesAndNullable(
|
||||
mgp_vertex_v, tv_vertex,
|
||||
{EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_any), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_node),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_map)});
|
||||
CheckNotSatisfiesTypesAndListAndNullable(
|
||||
mgp_vertex_v, tv_vertex,
|
||||
{EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_bool), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_string),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_int), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_float),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_number),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_relationship),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_path)});
|
||||
mgp_value_destroy(mgp_vertex_v);
|
||||
}
|
||||
|
||||
@ -185,12 +257,18 @@ TEST(CypherType, EdgeSatisfiesType) {
|
||||
mgp_memory memory{utils::NewDeleteResource()};
|
||||
utils::Allocator<mgp_edge> alloc(memory.impl);
|
||||
mgp_graph graph{&dba, storage::View::NEW};
|
||||
auto *mgp_edge_v = mgp_value_make_edge(alloc.new_object<mgp_edge>(edge, &graph));
|
||||
auto *mgp_edge_v = EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_edge, alloc.new_object<mgp_edge>(edge, &graph));
|
||||
const query::TypedValue tv_edge(edge);
|
||||
CheckSatisfiesTypesAndNullable(mgp_edge_v, tv_edge, {mgp_type_any(), mgp_type_relationship(), mgp_type_map()});
|
||||
CheckNotSatisfiesTypesAndListAndNullable(mgp_edge_v, tv_edge,
|
||||
{mgp_type_bool(), mgp_type_string(), mgp_type_int(), mgp_type_float(),
|
||||
mgp_type_number(), mgp_type_node(), mgp_type_path()});
|
||||
CheckSatisfiesTypesAndNullable(mgp_edge_v, tv_edge,
|
||||
{EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_any),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_relationship),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_map)});
|
||||
CheckNotSatisfiesTypesAndListAndNullable(
|
||||
mgp_edge_v, tv_edge,
|
||||
{EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_bool), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_string),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_int), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_float),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_number), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_node),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_path)});
|
||||
mgp_value_destroy(mgp_edge_v);
|
||||
}
|
||||
|
||||
@ -205,19 +283,24 @@ TEST(CypherType, PathSatisfiesType) {
|
||||
utils::Allocator<mgp_path> alloc(memory.impl);
|
||||
mgp_graph graph{&dba, storage::View::NEW};
|
||||
auto *mgp_vertex_v = alloc.new_object<mgp_vertex>(v1, &graph);
|
||||
auto path = mgp_path_make_with_start(mgp_vertex_v, &memory);
|
||||
auto path = EXPECT_MGP_NO_ERROR(mgp_path *, mgp_path_make_with_start, mgp_vertex_v, &memory);
|
||||
ASSERT_TRUE(path);
|
||||
alloc.delete_object(mgp_vertex_v);
|
||||
auto mgp_edge_v = alloc.new_object<mgp_edge>(edge, &graph);
|
||||
ASSERT_TRUE(mgp_path_expand(path, mgp_edge_v));
|
||||
ASSERT_EQ(mgp_path_expand(path, mgp_edge_v), MGP_ERROR_NO_ERROR);
|
||||
alloc.delete_object(mgp_edge_v);
|
||||
auto *mgp_path_v = mgp_value_make_path(path);
|
||||
auto *mgp_path_v = EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_path, path);
|
||||
const query::TypedValue tv_path(query::Path(v1, edge, v2));
|
||||
CheckSatisfiesTypesAndNullable(mgp_path_v, tv_path, {mgp_type_any(), mgp_type_path()});
|
||||
CheckSatisfiesTypesAndNullable(
|
||||
mgp_path_v, tv_path,
|
||||
{EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_any), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_path)});
|
||||
CheckNotSatisfiesTypesAndListAndNullable(
|
||||
mgp_path_v, tv_path,
|
||||
{mgp_type_bool(), mgp_type_string(), mgp_type_int(), mgp_type_float(), mgp_type_number(), mgp_type_map(),
|
||||
mgp_type_node(), mgp_type_relationship()});
|
||||
{EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_bool), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_string),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_int), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_float),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_number), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_map),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_node),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_relationship)});
|
||||
mgp_value_destroy(mgp_path_v);
|
||||
}
|
||||
|
||||
@ -225,23 +308,31 @@ static std::vector<const mgp_type *> MakeListTypes(const std::vector<const mgp_t
|
||||
std::vector<const mgp_type *> list_types;
|
||||
list_types.reserve(2U * element_types.size());
|
||||
for (const auto *type : element_types) {
|
||||
list_types.push_back(mgp_type_list(type));
|
||||
list_types.push_back(mgp_type_list(mgp_type_nullable(type)));
|
||||
list_types.push_back(EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_list, type));
|
||||
list_types.push_back(EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_list,
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_nullable, type)));
|
||||
}
|
||||
return list_types;
|
||||
}
|
||||
|
||||
TEST(CypherType, EmptyListSatisfiesType) {
|
||||
mgp_memory memory{utils::NewDeleteResource()};
|
||||
auto *list = mgp_list_make_empty(0, &memory);
|
||||
auto *mgp_list_v = mgp_value_make_list(list);
|
||||
auto *list = EXPECT_MGP_NO_ERROR(mgp_list *, mgp_list_make_empty, 0, &memory);
|
||||
auto *mgp_list_v = EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_list, list);
|
||||
query::TypedValue tv_list(std::vector<query::TypedValue>{});
|
||||
// Empty List satisfies all list element types
|
||||
std::vector<const mgp_type *> primitive_types{
|
||||
mgp_type_any(), mgp_type_bool(), mgp_type_string(), mgp_type_int(), mgp_type_float(),
|
||||
mgp_type_number(), mgp_type_map(), mgp_type_node(), mgp_type_relationship(), mgp_type_path()};
|
||||
std::vector<const mgp_type *> primitive_types{EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_any),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_bool),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_string),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_int),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_float),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_number),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_map),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_node),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_relationship),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_path)};
|
||||
auto all_types = MakeListTypes(primitive_types);
|
||||
all_types.push_back(mgp_type_any());
|
||||
all_types.push_back(EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_any));
|
||||
CheckSatisfiesTypesAndNullable(mgp_list_v, tv_list, all_types);
|
||||
mgp_value_destroy(mgp_list_v);
|
||||
}
|
||||
@ -249,18 +340,28 @@ TEST(CypherType, EmptyListSatisfiesType) {
|
||||
TEST(CypherType, ListOfIntSatisfiesType) {
|
||||
mgp_memory memory{utils::NewDeleteResource()};
|
||||
constexpr int64_t elem_count = 3;
|
||||
auto *list = mgp_list_make_empty(elem_count, &memory);
|
||||
auto *mgp_list_v = mgp_value_make_list(list);
|
||||
auto *list = EXPECT_MGP_NO_ERROR(mgp_list *, mgp_list_make_empty, elem_count, &memory);
|
||||
auto *mgp_list_v = EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_list, list);
|
||||
query::TypedValue tv_list(std::vector<query::TypedValue>{});
|
||||
for (int64_t i = 0; i < elem_count; ++i) {
|
||||
ASSERT_TRUE(mgp_list_append(list, test_utils::CreateValueOwningPtr(mgp_value_make_int(i, &memory)).get()));
|
||||
ASSERT_EQ(
|
||||
mgp_list_append(
|
||||
list,
|
||||
test_utils::CreateValueOwningPtr(EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_int, i, &memory)).get()),
|
||||
MGP_ERROR_NO_ERROR);
|
||||
tv_list.ValueList().emplace_back(i);
|
||||
auto valid_types = MakeListTypes({mgp_type_any(), mgp_type_int(), mgp_type_number()});
|
||||
valid_types.push_back(mgp_type_any());
|
||||
auto valid_types = MakeListTypes({EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_any),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_int),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_number)});
|
||||
valid_types.push_back(EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_any));
|
||||
CheckSatisfiesTypesAndNullable(mgp_list_v, tv_list, valid_types);
|
||||
CheckNotSatisfiesTypesAndListAndNullable(mgp_list_v, tv_list,
|
||||
{mgp_type_bool(), mgp_type_string(), mgp_type_float(), mgp_type_map(),
|
||||
mgp_type_node(), mgp_type_relationship(), mgp_type_path()});
|
||||
CheckNotSatisfiesTypesAndListAndNullable(
|
||||
mgp_list_v, tv_list,
|
||||
{EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_bool), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_string),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_float), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_map),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_node),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_relationship),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_path)});
|
||||
}
|
||||
mgp_value_destroy(mgp_list_v);
|
||||
}
|
||||
@ -268,52 +369,75 @@ TEST(CypherType, ListOfIntSatisfiesType) {
|
||||
TEST(CypherType, ListOfIntAndBoolSatisfiesType) {
|
||||
mgp_memory memory{utils::NewDeleteResource()};
|
||||
constexpr int64_t elem_count = 2;
|
||||
auto *list = mgp_list_make_empty(elem_count, &memory);
|
||||
auto *mgp_list_v = mgp_value_make_list(list);
|
||||
auto *list = EXPECT_MGP_NO_ERROR(mgp_list *, mgp_list_make_empty, elem_count, &memory);
|
||||
auto *mgp_list_v = EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_list, list);
|
||||
query::TypedValue tv_list(std::vector<query::TypedValue>{});
|
||||
// Add an int
|
||||
ASSERT_TRUE(mgp_list_append(list, test_utils::CreateValueOwningPtr(mgp_value_make_int(42, &memory)).get()));
|
||||
ASSERT_EQ(
|
||||
mgp_list_append(
|
||||
list,
|
||||
test_utils::CreateValueOwningPtr(EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_int, 42, &memory)).get()),
|
||||
MGP_ERROR_NO_ERROR);
|
||||
tv_list.ValueList().emplace_back(42);
|
||||
// Add a boolean
|
||||
ASSERT_TRUE(mgp_list_append(list, test_utils::CreateValueOwningPtr(mgp_value_make_bool(1, &memory)).get()));
|
||||
ASSERT_EQ(
|
||||
mgp_list_append(
|
||||
list,
|
||||
test_utils::CreateValueOwningPtr(EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_bool, 1, &memory)).get()),
|
||||
MGP_ERROR_NO_ERROR);
|
||||
tv_list.ValueList().emplace_back(true);
|
||||
auto valid_types = MakeListTypes({mgp_type_any()});
|
||||
valid_types.push_back(mgp_type_any());
|
||||
auto valid_types = MakeListTypes({EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_any)});
|
||||
valid_types.push_back(EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_any));
|
||||
CheckSatisfiesTypesAndNullable(mgp_list_v, tv_list, valid_types);
|
||||
// All other types will not be satisfied
|
||||
CheckNotSatisfiesTypesAndListAndNullable(
|
||||
mgp_list_v, tv_list,
|
||||
{mgp_type_bool(), mgp_type_string(), mgp_type_int(), mgp_type_float(), mgp_type_number(), mgp_type_map(),
|
||||
mgp_type_node(), mgp_type_relationship(), mgp_type_path()});
|
||||
{EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_bool), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_string),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_int), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_float),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_number), EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_map),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_node),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_relationship),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_path)});
|
||||
mgp_value_destroy(mgp_list_v);
|
||||
}
|
||||
|
||||
TEST(CypherType, ListOfNullSatisfiesType) {
|
||||
mgp_memory memory{utils::NewDeleteResource()};
|
||||
auto *list = mgp_list_make_empty(1, &memory);
|
||||
auto *mgp_list_v = mgp_value_make_list(list);
|
||||
auto *list = EXPECT_MGP_NO_ERROR(mgp_list *, mgp_list_make_empty, 1, &memory);
|
||||
auto *mgp_list_v = EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_list, list);
|
||||
query::TypedValue tv_list(std::vector<query::TypedValue>{});
|
||||
ASSERT_TRUE(mgp_list_append(list, test_utils::CreateValueOwningPtr(mgp_value_make_null(&memory)).get()));
|
||||
ASSERT_EQ(
|
||||
mgp_list_append(
|
||||
list, test_utils::CreateValueOwningPtr(EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_null, &memory)).get()),
|
||||
MGP_ERROR_NO_ERROR);
|
||||
tv_list.ValueList().emplace_back();
|
||||
// List with Null satisfies all nullable list element types
|
||||
std::vector<const mgp_type *> primitive_types{
|
||||
mgp_type_any(), mgp_type_bool(), mgp_type_string(), mgp_type_int(), mgp_type_float(),
|
||||
mgp_type_number(), mgp_type_map(), mgp_type_node(), mgp_type_relationship(), mgp_type_path()};
|
||||
std::vector<const mgp_type *> valid_types{mgp_type_any()};
|
||||
std::vector<const mgp_type *> primitive_types{EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_any),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_bool),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_string),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_int),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_float),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_number),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_map),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_node),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_relationship),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_path)};
|
||||
std::vector<const mgp_type *> valid_types{EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_any)};
|
||||
valid_types.reserve(1U + primitive_types.size());
|
||||
for (const auto *elem_type : primitive_types) {
|
||||
valid_types.push_back(mgp_type_list(mgp_type_nullable(elem_type)));
|
||||
valid_types.push_back(EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_list,
|
||||
EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_nullable, elem_type)));
|
||||
}
|
||||
CheckSatisfiesTypesAndNullable(mgp_list_v, tv_list, valid_types);
|
||||
std::vector<const mgp_type *> invalid_types;
|
||||
invalid_types.reserve(primitive_types.size());
|
||||
for (const auto *elem_type : primitive_types) {
|
||||
invalid_types.push_back(mgp_type_list(elem_type));
|
||||
invalid_types.push_back(EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_list, elem_type));
|
||||
}
|
||||
for (const auto *type : invalid_types) {
|
||||
EXPECT_FALSE(type->impl->SatisfiesType(*mgp_list_v)) << type->impl->GetPresentableName();
|
||||
EXPECT_FALSE(type->impl->SatisfiesType(tv_list));
|
||||
const auto *null_type = mgp_type_nullable(type);
|
||||
const auto *null_type = EXPECT_MGP_NO_ERROR(const mgp_type *, mgp_type_nullable, type);
|
||||
EXPECT_FALSE(null_type->impl->SatisfiesType(*mgp_list_v)) << null_type->impl->GetPresentableName();
|
||||
EXPECT_FALSE(null_type->impl->SatisfiesType(tv_list));
|
||||
}
|
||||
|
@ -5,25 +5,29 @@
|
||||
|
||||
#include "query/procedure/mg_procedure_impl.hpp"
|
||||
#include "query/procedure/py_module.hpp"
|
||||
#include "test_utils.hpp"
|
||||
|
||||
TEST(PyModule, MgpValueToPyObject) {
|
||||
mgp_memory memory{utils::NewDeleteResource()};
|
||||
auto *list = mgp_list_make_empty(42, &memory);
|
||||
auto *list = EXPECT_MGP_NO_ERROR(mgp_list *, mgp_list_make_empty, 42, &memory);
|
||||
{
|
||||
// Create a list: [null, false, true, 42, 0.1, "some text"]
|
||||
auto primitive_values = {mgp_value_make_null(&memory), mgp_value_make_bool(0, &memory),
|
||||
mgp_value_make_bool(1, &memory), mgp_value_make_int(42, &memory),
|
||||
mgp_value_make_double(0.1, &memory), mgp_value_make_string("some text", &memory)};
|
||||
auto primitive_values = {EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_null, &memory),
|
||||
EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_bool, 0, &memory),
|
||||
EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_bool, 1, &memory),
|
||||
EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_int, 42, &memory),
|
||||
EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_double, 0.1, &memory),
|
||||
EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_string, "some text", &memory)};
|
||||
for (auto *val : primitive_values) {
|
||||
mgp_list_append(list, val);
|
||||
EXPECT_EQ(mgp_list_append(list, val), MGP_ERROR_NO_ERROR);
|
||||
mgp_value_destroy(val);
|
||||
}
|
||||
}
|
||||
auto *list_val = mgp_value_make_list(list);
|
||||
auto *map = mgp_map_make_empty(&memory);
|
||||
mgp_map_insert(map, "list", list_val);
|
||||
auto *list_val = EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_list, list);
|
||||
auto *map = EXPECT_MGP_NO_ERROR(mgp_map *, mgp_map_make_empty, &memory);
|
||||
EXPECT_EQ(mgp_map_insert(map, "list", list_val), MGP_ERROR_NO_ERROR);
|
||||
mgp_value_destroy(list_val);
|
||||
auto *map_val = mgp_value_make_map(map);
|
||||
auto *map_val = EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_map, map);
|
||||
auto gil = py::EnsureGIL();
|
||||
py::Object py_graph(query::procedure::MakePyGraph(nullptr, &memory));
|
||||
auto py_dict =
|
||||
@ -99,9 +103,10 @@ TEST(PyModule, PyVertex) {
|
||||
query::DbAccessor dba(&storage_dba);
|
||||
mgp_memory memory{utils::NewDeleteResource()};
|
||||
mgp_graph graph{&dba, storage::View::OLD};
|
||||
auto *vertex = mgp_graph_get_vertex_by_id(&graph, mgp_vertex_id{0}, &memory);
|
||||
auto *vertex = EXPECT_MGP_NO_ERROR(mgp_vertex *, mgp_graph_get_vertex_by_id, &graph, mgp_vertex_id{0}, &memory);
|
||||
ASSERT_TRUE(vertex);
|
||||
auto *vertex_value = mgp_value_make_vertex(mgp_vertex_copy(vertex, &memory));
|
||||
auto *vertex_value = EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_vertex,
|
||||
EXPECT_MGP_NO_ERROR(mgp_vertex *, mgp_vertex_copy, vertex, &memory));
|
||||
mgp_vertex_destroy(vertex);
|
||||
// Initialize the Python graph object.
|
||||
auto gil = py::EnsureGIL();
|
||||
@ -116,8 +121,11 @@ TEST(PyModule, PyVertex) {
|
||||
// Test for equality.
|
||||
ASSERT_TRUE(new_vertex_value);
|
||||
ASSERT_NE(new_vertex_value, vertex_value); // Pointer compare.
|
||||
ASSERT_TRUE(mgp_value_is_vertex(new_vertex_value));
|
||||
ASSERT_TRUE(mgp_vertex_equal(mgp_value_get_vertex(vertex_value), mgp_value_get_vertex(new_vertex_value)));
|
||||
ASSERT_EQ(EXPECT_MGP_NO_ERROR(int, mgp_value_is_vertex, new_vertex_value), 1);
|
||||
ASSERT_EQ(EXPECT_MGP_NO_ERROR(int, mgp_vertex_equal,
|
||||
EXPECT_MGP_NO_ERROR(const mgp_vertex *, mgp_value_get_vertex, vertex_value),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_vertex *, mgp_value_get_vertex, new_vertex_value)),
|
||||
1);
|
||||
// Clean up.
|
||||
mgp_value_destroy(new_vertex_value);
|
||||
mgp_value_destroy(vertex_value);
|
||||
@ -144,14 +152,15 @@ TEST(PyModule, PyEdge) {
|
||||
query::DbAccessor dba(&storage_dba);
|
||||
mgp_memory memory{utils::NewDeleteResource()};
|
||||
mgp_graph graph{&dba, storage::View::OLD};
|
||||
auto *start_v = mgp_graph_get_vertex_by_id(&graph, mgp_vertex_id{0}, &memory);
|
||||
auto *start_v = EXPECT_MGP_NO_ERROR(mgp_vertex *, mgp_graph_get_vertex_by_id, &graph, mgp_vertex_id{0}, &memory);
|
||||
ASSERT_TRUE(start_v);
|
||||
auto *edges_it = mgp_vertex_iter_out_edges(start_v, &memory);
|
||||
auto *edges_it = EXPECT_MGP_NO_ERROR(mgp_edges_iterator *, mgp_vertex_iter_out_edges, start_v, &memory);
|
||||
ASSERT_TRUE(edges_it);
|
||||
auto *edge = mgp_edge_copy(mgp_edges_iterator_get(edges_it), &memory);
|
||||
auto *edge_value = mgp_value_make_edge(edge);
|
||||
mgp_edges_iterator_next(edges_it);
|
||||
ASSERT_EQ(mgp_edges_iterator_get(edges_it), nullptr);
|
||||
auto *edge = EXPECT_MGP_NO_ERROR(mgp_edge *, mgp_edge_copy,
|
||||
EXPECT_MGP_NO_ERROR(const mgp_edge *, mgp_edges_iterator_get, edges_it), &memory);
|
||||
auto *edge_value = EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_edge, edge);
|
||||
ASSERT_EQ(EXPECT_MGP_NO_ERROR(const mgp_edge *, mgp_edges_iterator_next, edges_it), nullptr);
|
||||
ASSERT_EQ(EXPECT_MGP_NO_ERROR(const mgp_edge *, mgp_edges_iterator_get, edges_it), nullptr);
|
||||
mgp_edges_iterator_destroy(edges_it);
|
||||
mgp_vertex_destroy(start_v);
|
||||
// Initialize the Python graph object.
|
||||
@ -167,8 +176,11 @@ TEST(PyModule, PyEdge) {
|
||||
// Test for equality.
|
||||
ASSERT_TRUE(new_edge_value);
|
||||
ASSERT_NE(new_edge_value, edge_value); // Pointer compare.
|
||||
ASSERT_TRUE(mgp_value_is_edge(new_edge_value));
|
||||
ASSERT_TRUE(mgp_edge_equal(mgp_value_get_edge(edge_value), mgp_value_get_edge(new_edge_value)));
|
||||
ASSERT_EQ(EXPECT_MGP_NO_ERROR(int, mgp_value_is_edge, new_edge_value), 1);
|
||||
ASSERT_EQ(
|
||||
EXPECT_MGP_NO_ERROR(int, mgp_edge_equal, EXPECT_MGP_NO_ERROR(const mgp_edge *, mgp_value_get_edge, edge_value),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_edge *, mgp_value_get_edge, new_edge_value)),
|
||||
1);
|
||||
// Clean up.
|
||||
mgp_value_destroy(new_edge_value);
|
||||
mgp_value_destroy(edge_value);
|
||||
@ -188,19 +200,20 @@ TEST(PyModule, PyPath) {
|
||||
query::DbAccessor dba(&storage_dba);
|
||||
mgp_memory memory{utils::NewDeleteResource()};
|
||||
mgp_graph graph{&dba, storage::View::OLD};
|
||||
auto *start_v = mgp_graph_get_vertex_by_id(&graph, mgp_vertex_id{0}, &memory);
|
||||
auto *start_v = EXPECT_MGP_NO_ERROR(mgp_vertex *, mgp_graph_get_vertex_by_id, &graph, mgp_vertex_id{0}, &memory);
|
||||
ASSERT_TRUE(start_v);
|
||||
auto *path = mgp_path_make_with_start(start_v, &memory);
|
||||
auto *path = EXPECT_MGP_NO_ERROR(mgp_path *, mgp_path_make_with_start, start_v, &memory);
|
||||
ASSERT_TRUE(path);
|
||||
auto *edges_it = mgp_vertex_iter_out_edges(start_v, &memory);
|
||||
auto *edges_it = EXPECT_MGP_NO_ERROR(mgp_edges_iterator *, mgp_vertex_iter_out_edges, start_v, &memory);
|
||||
ASSERT_TRUE(edges_it);
|
||||
for (const auto *edge = mgp_edges_iterator_get(edges_it); edge; edge = mgp_edges_iterator_next(edges_it)) {
|
||||
ASSERT_TRUE(mgp_path_expand(path, edge));
|
||||
for (const auto *edge = EXPECT_MGP_NO_ERROR(const mgp_edge *, mgp_edges_iterator_get, edges_it); edge != nullptr;
|
||||
edge = EXPECT_MGP_NO_ERROR(const mgp_edge *, mgp_edges_iterator_next, edges_it)) {
|
||||
ASSERT_EQ(mgp_path_expand(path, edge), MGP_ERROR_NO_ERROR);
|
||||
}
|
||||
ASSERT_EQ(mgp_path_size(path), 1);
|
||||
ASSERT_EQ(EXPECT_MGP_NO_ERROR(size_t, mgp_path_size, path), 1);
|
||||
mgp_edges_iterator_destroy(edges_it);
|
||||
mgp_vertex_destroy(start_v);
|
||||
auto *path_value = mgp_value_make_path(path);
|
||||
auto *path_value = EXPECT_MGP_NO_ERROR(mgp_value *, mgp_value_make_path, path);
|
||||
ASSERT_TRUE(path_value);
|
||||
auto gil = py::EnsureGIL();
|
||||
py::Object py_graph(query::procedure::MakePyGraph(&graph, &memory));
|
||||
@ -213,8 +226,11 @@ TEST(PyModule, PyPath) {
|
||||
auto *new_path_value = query::procedure::PyObjectToMgpValue(py_path_value.Ptr(), &memory);
|
||||
ASSERT_TRUE(new_path_value);
|
||||
ASSERT_NE(new_path_value, path_value); // Pointer compare.
|
||||
ASSERT_TRUE(mgp_value_is_path(new_path_value));
|
||||
ASSERT_TRUE(mgp_path_equal(mgp_value_get_path(path_value), mgp_value_get_path(new_path_value)));
|
||||
ASSERT_EQ(EXPECT_MGP_NO_ERROR(int, mgp_value_is_path, new_path_value), 1);
|
||||
ASSERT_EQ(
|
||||
EXPECT_MGP_NO_ERROR(int, mgp_path_equal, EXPECT_MGP_NO_ERROR(const mgp_path *, mgp_value_get_path, path_value),
|
||||
EXPECT_MGP_NO_ERROR(const mgp_path *, mgp_value_get_path, new_path_value)),
|
||||
1);
|
||||
mgp_value_destroy(new_path_value);
|
||||
mgp_value_destroy(path_value);
|
||||
ASSERT_FALSE(dba.Commit().HasError());
|
||||
@ -225,35 +241,57 @@ TEST(PyModule, PyObjectToMgpValue) {
|
||||
auto gil = py::EnsureGIL();
|
||||
py::Object py_value{
|
||||
Py_BuildValue("[i f s (i f s) {s i s f}]", 1, 1.0, "one", 2, 2.0, "two", "three", 3, "four", 4.0)};
|
||||
mgp_value *value = query::procedure::PyObjectToMgpValue(py_value.Ptr(), &memory);
|
||||
auto *value = query::procedure::PyObjectToMgpValue(py_value.Ptr(), &memory);
|
||||
|
||||
ASSERT_TRUE(mgp_value_is_list(value));
|
||||
const mgp_list *list1 = mgp_value_get_list(value);
|
||||
EXPECT_EQ(mgp_list_size(list1), 5);
|
||||
ASSERT_TRUE(mgp_value_is_int(mgp_list_at(list1, 0)));
|
||||
EXPECT_EQ(mgp_value_get_int(mgp_list_at(list1, 0)), 1);
|
||||
ASSERT_TRUE(mgp_value_is_double(mgp_list_at(list1, 1)));
|
||||
EXPECT_EQ(mgp_value_get_double(mgp_list_at(list1, 1)), 1.0);
|
||||
ASSERT_TRUE(mgp_value_is_string(mgp_list_at(list1, 2)));
|
||||
EXPECT_STREQ(mgp_value_get_string(mgp_list_at(list1, 2)), "one");
|
||||
ASSERT_TRUE(mgp_value_is_list(mgp_list_at(list1, 3)));
|
||||
const mgp_list *list2 = mgp_value_get_list(mgp_list_at(list1, 3));
|
||||
EXPECT_EQ(mgp_list_size(list2), 3);
|
||||
ASSERT_TRUE(mgp_value_is_int(mgp_list_at(list2, 0)));
|
||||
EXPECT_EQ(mgp_value_get_int(mgp_list_at(list2, 0)), 2);
|
||||
ASSERT_TRUE(mgp_value_is_double(mgp_list_at(list2, 1)));
|
||||
EXPECT_EQ(mgp_value_get_double(mgp_list_at(list2, 1)), 2.0);
|
||||
ASSERT_TRUE(mgp_value_is_string(mgp_list_at(list2, 2)));
|
||||
EXPECT_STREQ(mgp_value_get_string(mgp_list_at(list2, 2)), "two");
|
||||
ASSERT_TRUE(mgp_value_is_map(mgp_list_at(list1, 4)));
|
||||
const mgp_map *map = mgp_value_get_map(mgp_list_at(list1, 4));
|
||||
EXPECT_EQ(mgp_map_size(map), 2);
|
||||
const mgp_value *v1 = mgp_map_at(map, "three");
|
||||
ASSERT_TRUE(mgp_value_is_int(v1));
|
||||
EXPECT_EQ(mgp_value_get_int(v1), 3);
|
||||
const mgp_value *v2 = mgp_map_at(map, "four");
|
||||
ASSERT_TRUE(mgp_value_is_double(v2));
|
||||
EXPECT_EQ(mgp_value_get_double(v2), 4.0);
|
||||
ASSERT_EQ(EXPECT_MGP_NO_ERROR(int, mgp_value_is_list, value), 1);
|
||||
auto *list1 = EXPECT_MGP_NO_ERROR(const mgp_list *, mgp_value_get_list, value);
|
||||
EXPECT_EQ(EXPECT_MGP_NO_ERROR(size_t, mgp_list_size, list1), 5);
|
||||
ASSERT_EQ(EXPECT_MGP_NO_ERROR(int, mgp_value_is_int, EXPECT_MGP_NO_ERROR(const mgp_value *, mgp_list_at, list1, 0)),
|
||||
1);
|
||||
EXPECT_EQ(
|
||||
EXPECT_MGP_NO_ERROR(int64_t, mgp_value_get_int, EXPECT_MGP_NO_ERROR(const mgp_value *, mgp_list_at, list1, 0)),
|
||||
1);
|
||||
ASSERT_EQ(
|
||||
EXPECT_MGP_NO_ERROR(int, mgp_value_is_double, EXPECT_MGP_NO_ERROR(const mgp_value *, mgp_list_at, list1, 1)), 1);
|
||||
EXPECT_EQ(
|
||||
EXPECT_MGP_NO_ERROR(double, mgp_value_get_double, EXPECT_MGP_NO_ERROR(const mgp_value *, mgp_list_at, list1, 1)),
|
||||
1.0);
|
||||
ASSERT_EQ(
|
||||
EXPECT_MGP_NO_ERROR(int, mgp_value_is_string, EXPECT_MGP_NO_ERROR(const mgp_value *, mgp_list_at, list1, 2)), 1);
|
||||
EXPECT_STREQ(EXPECT_MGP_NO_ERROR(const char *, mgp_value_get_string,
|
||||
EXPECT_MGP_NO_ERROR(const mgp_value *, mgp_list_at, list1, 2)),
|
||||
"one");
|
||||
ASSERT_EQ(EXPECT_MGP_NO_ERROR(int, mgp_value_is_list, EXPECT_MGP_NO_ERROR(const mgp_value *, mgp_list_at, list1, 3)),
|
||||
1);
|
||||
auto *list2 = EXPECT_MGP_NO_ERROR(const mgp_list *, mgp_value_get_list,
|
||||
EXPECT_MGP_NO_ERROR(const mgp_value *, mgp_list_at, list1, 3));
|
||||
EXPECT_EQ(EXPECT_MGP_NO_ERROR(size_t, mgp_list_size, list2), 3);
|
||||
ASSERT_EQ(EXPECT_MGP_NO_ERROR(int, mgp_value_is_int, EXPECT_MGP_NO_ERROR(const mgp_value *, mgp_list_at, list2, 0)),
|
||||
1);
|
||||
EXPECT_EQ(
|
||||
EXPECT_MGP_NO_ERROR(int64_t, mgp_value_get_int, EXPECT_MGP_NO_ERROR(const mgp_value *, mgp_list_at, list2, 0)),
|
||||
2);
|
||||
ASSERT_EQ(
|
||||
EXPECT_MGP_NO_ERROR(int, mgp_value_is_double, EXPECT_MGP_NO_ERROR(const mgp_value *, mgp_list_at, list2, 1)), 1);
|
||||
EXPECT_EQ(
|
||||
EXPECT_MGP_NO_ERROR(double, mgp_value_get_double, EXPECT_MGP_NO_ERROR(const mgp_value *, mgp_list_at, list2, 1)),
|
||||
2.0);
|
||||
ASSERT_EQ(
|
||||
EXPECT_MGP_NO_ERROR(int, mgp_value_is_string, EXPECT_MGP_NO_ERROR(const mgp_value *, mgp_list_at, list2, 2)), 1);
|
||||
EXPECT_STREQ(EXPECT_MGP_NO_ERROR(const char *, mgp_value_get_string,
|
||||
EXPECT_MGP_NO_ERROR(const mgp_value *, mgp_list_at, list2, 2)),
|
||||
"two");
|
||||
ASSERT_EQ(EXPECT_MGP_NO_ERROR(int, mgp_value_is_map, EXPECT_MGP_NO_ERROR(const mgp_value *, mgp_list_at, list1, 4)),
|
||||
1);
|
||||
auto *map = EXPECT_MGP_NO_ERROR(const mgp_map *, mgp_value_get_map,
|
||||
EXPECT_MGP_NO_ERROR(const mgp_value *, mgp_list_at, list1, 4));
|
||||
EXPECT_EQ(EXPECT_MGP_NO_ERROR(size_t, mgp_map_size, map), 2);
|
||||
const mgp_value *v1 = EXPECT_MGP_NO_ERROR(const mgp_value *, mgp_map_at, map, "three");
|
||||
ASSERT_EQ(EXPECT_MGP_NO_ERROR(int, mgp_value_is_int, v1), 1);
|
||||
EXPECT_EQ(EXPECT_MGP_NO_ERROR(int64_t, mgp_value_get_int, v1), 3);
|
||||
const mgp_value *v2 = EXPECT_MGP_NO_ERROR(const mgp_value *, mgp_map_at, map, "four");
|
||||
ASSERT_EQ(EXPECT_MGP_NO_ERROR(int, mgp_value_is_double, v2), 1);
|
||||
EXPECT_EQ(EXPECT_MGP_NO_ERROR(double, mgp_value_get_double, v2), 4.0);
|
||||
mgp_value_destroy(value);
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "mg_procedure.h"
|
||||
#include "query/procedure/mg_procedure_impl.hpp"
|
||||
|
||||
namespace test_utils {
|
||||
using MgpValueOwningPtr = std::unique_ptr<mgp_value, void (*)(mgp_value *)>;
|
||||
|
||||
MgpValueOwningPtr CreateValueOwningPtr(mgp_value *value) { return MgpValueOwningPtr(value, &mgp_value_destroy); }
|
||||
|
||||
template <typename TResult, typename TFunc, typename... TArgs>
|
||||
TResult ExpectNoError(const char *file, int line, TFunc func, TArgs &&...args) {
|
||||
static_assert(std::is_trivially_copyable_v<TFunc>);
|
||||
static_assert((std::is_trivially_copyable_v<std::remove_reference_t<TArgs>> && ...));
|
||||
TResult result{};
|
||||
EXPECT_EQ(func(args..., &result), MGP_ERROR_NO_ERROR) << fmt::format("Source of error: {} at line {}", file, line);
|
||||
return result;
|
||||
}
|
||||
} // namespace test_utils
|
||||
|
||||
#define EXPECT_MGP_NO_ERROR(type, ...) test_utils::ExpectNoError<type>(__FILE__, __LINE__, __VA_ARGS__)
|
Loading…
Reference in New Issue
Block a user