Define procedure API for temporal types (#229)

This commit is contained in:
antonio2368 2021-09-20 10:59:30 +02:00 committed by Antonio Andelic
parent 8ea281649a
commit 0a23eb11ae
8 changed files with 1313 additions and 46 deletions

View File

@ -125,6 +125,18 @@ struct mgp_edge;
/// Path containing mgp_vertex and mgp_edge instances.
struct mgp_path;
/// Date stored in Memgraph.
struct mgp_date;
/// Local time stored in Memgraph.
struct mgp_local_time;
/// Local date-time stored in Memgraph.
struct mgp_local_date_time;
/// Duration stored in Memgraph.
struct mgp_duration;
/// All available types that can be stored in a mgp_value
enum mgp_value_type {
// NOTE: New types need to be appended, so as not to break ABI.
@ -138,6 +150,10 @@ enum mgp_value_type {
MGP_VALUE_TYPE_VERTEX,
MGP_VALUE_TYPE_EDGE,
MGP_VALUE_TYPE_PATH,
MGP_VALUE_TYPE_DATE,
MGP_VALUE_TYPE_LOCAL_TIME,
MGP_VALUE_TYPE_LOCAL_DATE_TIME,
MGP_VALUE_TYPE_DURATION,
};
/// Free the memory used by the given mgp_value instance.
@ -209,6 +225,38 @@ enum mgp_error mgp_value_make_edge(struct mgp_edge *val, struct mgp_value **resu
/// 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);
/// Create a mgp_value storing a mgp_date.
/// You need to free the instance through mgp_value_destroy. The ownership of
/// the date is transferred to the created mgp_value and destroying the mgp_value will
/// destroy the mgp_date. Therefore, if a mgp_value is successfully created you
/// must not call mgp_date_destroy on the given date.
/// MGP_ERROR_UNABLE_TO_ALLOCATE is returned if unable to allocate a mgp_value.
enum mgp_error mgp_value_make_date(struct mgp_date *val, struct mgp_value **result);
/// Create a mgp_value storing a mgp_local_time.
/// You need to free the instance through mgp_value_destroy. The ownership of
/// the local time is transferred to the created mgp_value and destroying the mgp_value will
/// destroy the mgp_local_time. Therefore, if a mgp_value is successfully created you
/// must not call mgp_local_time_destroy on the given local time.
/// MGP_ERROR_UNABLE_TO_ALLOCATE is returned if unable to allocate a mgp_value.
enum mgp_error mgp_value_make_local_time(struct mgp_local_time *val, struct mgp_value **result);
/// Create a mgp_value storing a mgp_local_date_time.
/// You need to free the instance through mgp_value_destroy. The ownership of
/// the local date-time is transferred to the created mgp_value and destroying the mgp_value will
/// destroy the mgp_local_date_time. Therefore, if a mgp_value is successfully created you
/// must not call mgp_local_date_time_destroy on the given local date-time.
/// MGP_ERROR_UNABLE_TO_ALLOCATE is returned if unable to allocate a mgp_value.
enum mgp_error mgp_value_make_local_date_time(struct mgp_local_date_time *val, struct mgp_value **result);
/// Create a mgp_value storing a mgp_duration.
/// You need to free the instance through mgp_value_destroy. The ownership of
/// the duration is transferred to the created mgp_value and destroying the mgp_value will
/// destroy the mgp_duration. Therefore, if a mgp_value is successfully created you
/// must not call mgp_duration_destroy on the given duration.
/// MGP_ERROR_UNABLE_TO_ALLOCATE is returned if unable to allocate a mgp_value.
enum mgp_error mgp_value_make_duration(struct mgp_duration *val, struct mgp_value **result);
/// Get the type of the value contained in mgp_value.
/// Current implementation always returns without errors.
enum mgp_error mgp_value_get_type(struct mgp_value *val, enum mgp_value_type *result);
@ -253,6 +301,22 @@ enum mgp_error mgp_value_is_edge(struct mgp_value *val, int *result);
/// Current implementation always returns without errors.
enum mgp_error mgp_value_is_path(struct mgp_value *val, int *result);
/// Result is non-zero if the given mgp_value stores a date.
/// Current implementation always returns without errors.
enum mgp_error mgp_value_is_date(struct mgp_value *val, int *result);
/// Result is non-zero if the given mgp_value stores a local time.
/// Current implementation always returns without errors.
enum mgp_error mgp_value_is_local_time(struct mgp_value *val, int *result);
/// Result is non-zero if the given mgp_value stores a local date-time.
/// Current implementation always returns without errors.
enum mgp_error mgp_value_is_local_date_time(struct mgp_value *val, int *result);
/// Result is non-zero if the given mgp_value stores a duration.
/// Current implementation always returns without errors.
enum mgp_error mgp_value_is_duration(struct mgp_value *val, int *result);
/// Get the contained boolean value.
/// Non-zero values represent `true`, while zero represents `false`.
/// Result is undefined if mgp_value does not contain the expected type.
@ -299,6 +363,26 @@ enum mgp_error mgp_value_get_edge(struct mgp_value *val, struct mgp_edge **resul
/// Current implementation always returns without errors.
enum mgp_error mgp_value_get_path(struct mgp_value *val, struct mgp_path **result);
/// Get the contained date.
/// Result is undefined if mgp_value does not contain the expected type.
/// Current implementation always returns without errors.
enum mgp_error mgp_value_get_date(struct mgp_value *val, struct mgp_date **result);
/// Get the contained local time.
/// Result is undefined if mgp_value does not contain the expected type.
/// Current implementation always returns without errors.
enum mgp_error mgp_value_get_local_time(struct mgp_value *val, struct mgp_local_time **result);
/// Get the contained local date-time.
/// Result is undefined if mgp_value does not contain the expected type.
/// Current implementation always returns without errors.
enum mgp_error mgp_value_get_local_date_time(struct mgp_value *val, struct mgp_local_date_time **result);
/// Get the contained duration.
/// Result is undefined if mgp_value does not contain the expected type.
/// Current implementation always returns without errors.
enum mgp_error mgp_value_get_duration(struct mgp_value *val, struct mgp_duration **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
@ -774,6 +858,302 @@ enum mgp_error mgp_vertices_iterator_underlying_graph_is_mutable(struct mgp_vert
/// Result is NULL if the end of the iteration has been reached.
enum mgp_error mgp_vertices_iterator_get(struct mgp_vertices_iterator *it, struct mgp_vertex **result);
/// @name Temporal Types
///
///@{
struct mgp_date_parameters {
int year;
int month;
int day;
};
/// Create a date from a string following the ISO 8601 format.
/// Resulting date must be freed with mgp_date_destroy.
/// Return MGP_ERROR_INVALID_ARGUMENT if the string cannot be parsed correctly.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_date.
enum mgp_error mgp_date_from_string(const char *string, struct mgp_memory *memory, struct mgp_date **date);
/// Create a date from mgp_date_parameter.
/// Resulting date must be freed with mgp_date_destroy.
/// Return MGP_ERROR_INVALID_ARGUMENT if the parameters cannot be parsed correctly.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_date.
enum mgp_error mgp_date_from_parameters(struct mgp_date_parameters *parameters, struct mgp_memory *memory,
struct mgp_date **date);
/// Copy a mgp_date.
/// Resulting pointer must be freed with mgp_date_destroy.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_date.
enum mgp_error mgp_date_copy(struct mgp_date *date, struct mgp_memory *memory, struct mgp_date **result);
/// Free the memory used by a mgp_date.
void mgp_date_destroy(struct mgp_date *date);
/// Result is non-zero if given dates are equal, otherwise 0.
enum mgp_error mgp_date_equal(struct mgp_date *first, struct mgp_date *second, int *result);
/// Get the year property of the date.
enum mgp_error mgp_date_get_year(struct mgp_date *date, int *year);
/// Get the month property of the date.
enum mgp_error mgp_date_get_month(struct mgp_date *date, int *month);
/// Get the day property of the date.
enum mgp_error mgp_date_get_day(struct mgp_date *date, int *day);
/// Get the date as microseconds from Unix epoch.
enum mgp_error mgp_date_timestamp(struct mgp_date *date, int64_t *timestamp);
/// Get the date representing current date.
/// Resulting date must be freed with mgp_date_destroy.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_date.
enum mgp_error mgp_date_now(struct mgp_memory *memory, struct mgp_date **date);
/// Add a duration to the date.
/// Resulting date must be freed with mgp_date_destroy.
/// Return MGP_ERROR_INVALID_ARGUMENT if the operation results in an invalid date.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_date.
enum mgp_error mgp_date_add_duration(struct mgp_date *date, struct mgp_duration *dur, struct mgp_memory *memory,
struct mgp_date **result);
/// Subtract a duration from the date.
/// Resulting date must be freed with mgp_date_destroy.
/// Return MGP_ERROR_INVALID_ARGUMENT if the operation results in an invalid date.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_date.
enum mgp_error mgp_date_sub_duration(struct mgp_date *date, struct mgp_duration *dur, struct mgp_memory *memory,
struct mgp_date **result);
/// Get a duration between two dates.
/// Resulting duration must be freed with mgp_duration_destroy.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_date.
enum mgp_error mgp_date_diff(struct mgp_date *first, struct mgp_date *second, struct mgp_memory *memory,
struct mgp_duration **result);
struct mgp_local_time_parameters {
int hour;
int minute;
int second;
int millisecond;
int microsecond;
};
/// Create a local time from a string following the ISO 8601 format.
/// Resulting local time must be freed with mgp_local_time_destroy.
/// Return MGP_ERROR_INVALID_ARGUMENT if the string cannot be parsed correctly.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_date.
enum mgp_error mgp_local_time_from_string(const char *string, struct mgp_memory *memory,
struct mgp_local_time **local_time);
/// Create a local time from mgp_local_time_parameters.
/// Resulting local time must be freed with mgp_local_time_destroy.
/// Return MGP_ERROR_INVALID_ARGUMENT if the parameters cannot be parsed correctly.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_date.
enum mgp_error mgp_local_time_from_parameters(struct mgp_local_time_parameters *parameters, struct mgp_memory *memory,
struct mgp_local_time **local_time);
/// Copy a mgp_local_time.
/// Resulting pointer must be freed with mgp_local_time_destroy.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_date.
enum mgp_error mgp_local_time_copy(struct mgp_local_time *local_time, struct mgp_memory *memory,
struct mgp_local_time **result);
/// Free the memory used by a mgp_local_time.
void mgp_local_time_destroy(struct mgp_local_time *local_time);
/// Result is non-zero if given local times are equal, otherwise 0.
enum mgp_error mgp_local_time_equal(struct mgp_local_time *first, struct mgp_local_time *second, int *result);
/// Get the hour property of the local time.
enum mgp_error mgp_local_time_get_hour(struct mgp_local_time *local_time, int *hour);
/// Get the minute property of the local time.
enum mgp_error mgp_local_time_get_minute(struct mgp_local_time *local_time, int *minute);
/// Get the second property of the local time.
enum mgp_error mgp_local_time_get_second(struct mgp_local_time *local_time, int *second);
/// Get the millisecond property of the local time.
enum mgp_error mgp_local_time_get_millisecond(struct mgp_local_time *local_time, int *millisecond);
/// Get the microsecond property of the local time.
enum mgp_error mgp_local_time_get_microsecond(struct mgp_local_time *local_time, int *microsecond);
/// Get the local time as microseconds from midnight.
enum mgp_error mgp_local_time_timestamp(struct mgp_local_time *local_time, int64_t *timestamp);
/// Get the local time representing current time.
/// Resulting pointer must be freed with mgp_local_time_destroy.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_date.
enum mgp_error mgp_local_time_now(struct mgp_memory *memory, struct mgp_local_time **local_time);
/// Add a duration to the local time.
/// Resulting pointer must be freed with mgp_local_time_destroy.
/// Return MGP_ERROR_INVALID_ARGUMENT if the operation results in an invalid local time.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_date.
enum mgp_error mgp_local_time_add_duration(struct mgp_local_time *local_time, struct mgp_duration *dur,
struct mgp_memory *memory, struct mgp_local_time **result);
/// Subtract a duration from the local time.
/// Resulting pointer must be freed with mgp_local_time_destroy.
/// Return MGP_ERROR_INVALID_ARGUMENT if the operation results in an invalid local time.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_date.
enum mgp_error mgp_local_time_sub_duration(struct mgp_local_time *local_time, struct mgp_duration *dur,
struct mgp_memory *memory, struct mgp_local_time **result);
/// Get a duration between two local times.
/// Resulting pointer must be freed with mgp_duration_destroy.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_date.
enum mgp_error mgp_local_time_diff(struct mgp_local_time *first, struct mgp_local_time *second,
struct mgp_memory *memory, struct mgp_duration **result);
struct mgp_local_date_time_parameters {
struct mgp_date_parameters *date_parameters;
struct mgp_local_time_parameters *local_time_parameters;
};
/// Create a local date-time from a string following the ISO 8601 format.
/// Resulting local date-time must be freed with mgp_local_date_time_destroy.
/// Return MGP_ERROR_INVALID_ARGUMENT if the string cannot be parsed correctly.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_local_date_time.
enum mgp_error mgp_local_date_time_from_string(const char *string, struct mgp_memory *memory,
struct mgp_local_date_time **local_date_time);
/// Create a local date-time from mgp_local_date_time_parameters.
/// Resulting local date-time must be freed with mgp_local_date_time_destroy.
/// Return MGP_ERROR_INVALID_ARGUMENT if the parameters cannot be parsed correctly.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_local_date_time.
enum mgp_error mgp_local_date_time_from_parameters(struct mgp_local_date_time_parameters *parameters,
struct mgp_memory *memory,
struct mgp_local_date_time **local_date_time);
/// Copy a mgp_local_date_time.
/// Resulting pointer must be freed with mgp_local_date_time_destroy.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_local_date_time.
enum mgp_error mgp_local_date_time_copy(struct mgp_local_date_time *local_date_time, struct mgp_memory *memory,
struct mgp_local_date_time **result);
/// Free the memory used by a mgp_local_date_time.
void mgp_local_date_time_destroy(struct mgp_local_date_time *local_date_time);
/// Result is non-zero if given local date-times are equal, otherwise 0.
enum mgp_error mgp_local_date_time_equal(struct mgp_local_date_time *first, struct mgp_local_date_time *second,
int *result);
/// Get the year property of the local date-time.
enum mgp_error mgp_local_date_time_get_year(struct mgp_local_date_time *local_date_time, int *year);
/// Get the month property of the local date-time.
enum mgp_error mgp_local_date_time_get_month(struct mgp_local_date_time *local_date_time, int *month);
/// Get the day property of the local date-time.
enum mgp_error mgp_local_date_time_get_day(struct mgp_local_date_time *local_date_time, int *day);
/// Get the hour property of the local date-time.
enum mgp_error mgp_local_date_time_get_hour(struct mgp_local_date_time *local_date_time, int *hour);
/// Get the minute property of the local date-time.
enum mgp_error mgp_local_date_time_get_minute(struct mgp_local_date_time *local_date_time, int *minute);
/// Get the second property of the local date-time.
enum mgp_error mgp_local_date_time_get_second(struct mgp_local_date_time *local_date_time, int *second);
/// Get the milisecond property of the local date-time.
enum mgp_error mgp_local_date_time_get_millisecond(struct mgp_local_date_time *local_date_time, int *millisecond);
/// Get the microsecond property of the local date-time.
enum mgp_error mgp_local_date_time_get_microsecond(struct mgp_local_date_time *local_date_time, int *microsecond);
/// Get the local date-time as microseconds from Unix epoch.
enum mgp_error mgp_local_date_time_timestamp(struct mgp_local_date_time *local_date_time, int64_t *timestamp);
/// Get the local date-time representing current date and time.
/// Resulting local date-time must be freed with mgp_local_date_time_destroy.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_local_date_time.
enum mgp_error mgp_local_date_time_now(struct mgp_memory *memory, struct mgp_local_date_time **local_date_time);
/// Add a duration to the local date-time.
/// Resulting local date-time must be freed with mgp_local_date_time_destroy.
/// Return MGP_ERROR_INVALID_ARGUMENT if the operation results in an invalid local date-time.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_local_date_time.
enum mgp_error mgp_local_date_time_add_duration(struct mgp_local_date_time *local_date_time, struct mgp_duration *dur,
struct mgp_memory *memory, struct mgp_local_date_time **result);
/// Subtract a duration from the local date-time.
/// Resulting local date-time must be freed with mgp_local_date_time_destroy.
/// Return MGP_ERROR_INVALID_ARGUMENT if the operation results in an invalid local date-time.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_local_date_time.
enum mgp_error mgp_local_date_time_sub_duration(struct mgp_local_date_time *local_date_time, struct mgp_duration *dur,
struct mgp_memory *memory, struct mgp_local_date_time **result);
/// Get a duration between two local date-times.
/// Resulting duration must be freed with mgp_duration_destroy.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_local_date_time.
enum mgp_error mgp_local_date_time_diff(struct mgp_local_date_time *first, struct mgp_local_date_time *second,
struct mgp_memory *memory, struct mgp_duration **result);
struct mgp_duration_parameters {
double day;
double hour;
double minute;
double second;
double millisecond;
double microsecond;
};
/// Create a duration from a string following the ISO 8601 format.
/// Resulting duration must be freed with mgp_duration_destroy.
/// Return MGP_ERROR_INVALID_ARGUMENT if the string cannot be parsed correctly.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_duration.
enum mgp_error mgp_duration_from_string(const char *string, struct mgp_memory *memory, struct mgp_duration **duration);
/// Create a duration from mgp_duration_parameters.
/// Resulting duration must be freed with mgp_duration_destroy.
/// Return MGP_ERROR_INVALID_ARGUMENT if the parameters cannot be parsed correctly.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_duration.
enum mgp_error mgp_duration_from_parameters(struct mgp_duration_parameters *parameters, struct mgp_memory *memory,
struct mgp_duration **duration);
/// Create a duration from microseconds.
/// Resulting duration must be freed with mgp_duration_destroy.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_duration.
enum mgp_error mgp_duration_from_microseconds(int64_t microseconds, struct mgp_memory *memory,
struct mgp_duration **duration);
/// Copy a mgp_duration.
/// Resulting pointer must be freed with mgp_duration_destroy.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_duration.
enum mgp_error mgp_duration_copy(struct mgp_duration *duration, struct mgp_memory *memory,
struct mgp_duration **result);
/// Free the memory used by a mgp_duration.
void mgp_duration_destroy(struct mgp_duration *duration);
/// Result is non-zero if given durations are equal, otherwise 0.
enum mgp_error mgp_duration_equal(struct mgp_duration *first, struct mgp_duration *second, int *result);
/// Get the duration as microseconds.
enum mgp_error mgp_duration_get_microseconds(struct mgp_duration *duration, int64_t *microseconds);
/// Apply unary minus operator to the duration.
/// Resulting pointer must be freed with mgp_duration_destroy.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_duration.
enum mgp_error mgp_duration_neg(struct mgp_duration *dur, struct mgp_memory *memory, struct mgp_duration **result);
/// Add two durations.
/// Resulting pointer must be freed with mgp_duration_destroy.
/// Return MGP_ERROR_INVALID_ARGUMENT if the operation results in an invalid duration.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_duration.
enum mgp_error mgp_duration_add(struct mgp_duration *first, struct mgp_duration *second, struct mgp_memory *memory,
struct mgp_duration **result);
/// Subtract two durations.
/// Resulting pointer must be freed with mgp_duration_destroy.
/// Return MGP_ERROR_INVALID_ARGUMENT if the operation results in an invalid duration.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate a mgp_duration.
enum mgp_error mgp_duration_sub(struct mgp_duration *first, struct mgp_duration *second, struct mgp_memory *memory,
struct mgp_duration **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.
@ -857,6 +1237,22 @@ enum mgp_error mgp_type_path(struct mgp_type **result);
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate the new type.
enum mgp_error mgp_type_list(struct mgp_type *element_type, struct mgp_type **result);
/// Get the type representing a date.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate the new type.
enum mgp_error mgp_type_date(struct mgp_type **result);
/// Get the type representing a local time.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate the new type.
enum mgp_error mgp_type_local_time(struct mgp_type **result);
/// Get the type representing a local date-time.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate the new type.
enum mgp_error mgp_type_local_date_time(struct mgp_type **result);
/// Get the type representing a duration.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate the new type.
enum mgp_error mgp_type_duration(struct mgp_type **result);
/// Build a type representing either a `null` value or a value of given `type`.
///
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate the new type.

View File

@ -21,6 +21,7 @@ from functools import wraps
import inspect
import sys
import typing
import datetime
import _mgp
@ -951,7 +952,15 @@ Number = typing.Union[int, float]
Map = typing.Union[dict, Edge, Vertex]
Any = typing.Union[bool, str, Number, Map, Path, list]
Date = datetime.date
LocalTime = datetime.time
LocalDateTime = datetime.datetime
Duration = datetime.timedelta
Any = typing.Union[bool, str, Number, Map, Path, list, Date, LocalTime, LocalDateTime, Duration]
List = typing.List
@ -980,7 +989,11 @@ def _typing_to_cypher_type(type_):
Map: _mgp.type_map(),
Vertex: _mgp.type_node(),
Edge: _mgp.type_relationship(),
Path: _mgp.type_path()
Path: _mgp.type_path(),
Date: _mgp.type_date(),
LocalTime: _mgp.type_local_time(),
LocalDateTime: _mgp.type_local_date_time(),
Duration: _mgp.type_duration()
}
try:
return simple_types[type_]

View File

@ -129,8 +129,6 @@ class PathType : public CypherType {
bool SatisfiesType(const query::TypedValue &value) const override { return value.IsPath(); }
};
// TODO: There's also Temporal Types, but we currently do not support those.
// You'd think that MapType would be a composite type like ListType, but nope.
// Why? No-one really knows. It's defined like that in "CIP2015-09-16 Public
// Type System and Type Annotations"
@ -149,6 +147,44 @@ class MapType : public CypherType {
}
};
// Temporal Types
class DateType : public CypherType {
public:
std::string_view GetPresentableName() const override { return "DATE"; }
bool SatisfiesType(const mgp_value &value) const override { return value.type == MGP_VALUE_TYPE_DATE; }
bool SatisfiesType(const query::TypedValue &value) const override { return value.IsDate(); }
};
class LocalTimeType : public CypherType {
public:
std::string_view GetPresentableName() const override { return "LOCAL_TIME"; }
bool SatisfiesType(const mgp_value &value) const override { return value.type == MGP_VALUE_TYPE_LOCAL_TIME; }
bool SatisfiesType(const query::TypedValue &value) const override { return value.IsLocalTime(); }
};
class LocalDateTimeType : public CypherType {
public:
std::string_view GetPresentableName() const override { return "LOCAL_DATE_TIME"; }
bool SatisfiesType(const mgp_value &value) const override { return value.type == MGP_VALUE_TYPE_LOCAL_DATE_TIME; }
bool SatisfiesType(const query::TypedValue &value) const override { return value.IsLocalDateTime(); }
};
class DurationType : public CypherType {
public:
std::string_view GetPresentableName() const override { return "DURATION"; }
bool SatisfiesType(const mgp_value &value) const override { return value.type == MGP_VALUE_TYPE_DURATION; }
bool SatisfiesType(const query::TypedValue &value) const override { return value.IsDuration(); }
};
// Composite Types
class ListType : public CypherType {

View File

@ -23,6 +23,7 @@
#include "utils/math.hpp"
#include "utils/memory.hpp"
#include "utils/string.hpp"
#include "utils/temporal.hpp"
// This file contains implementation of top level C API functions, but this is
// all actually part of query::procedure. So use that namespace for simplicity.
@ -163,6 +164,9 @@ template <typename TFunc, typename... Args>
} catch (const std::exception &e) {
spdlog::error("Unexpected error during mg API call: {}", e.what());
return MGP_ERROR_UNKNOWN_ERROR;
} catch (const utils::temporal::InvalidArgumentException &e) {
spdlog::error("Invalid argument was sent to an mg API call for temporal types: {}", e.what());
return MGP_ERROR_INVALID_ARGUMENT;
} catch (...) {
spdlog::error("Unexpected error during mg API call");
return MGP_ERROR_UNKNOWN_ERROR;
@ -262,8 +266,15 @@ mgp_value_type FromTypedValueType(query::TypedValue::Type type) {
return MGP_VALUE_TYPE_EDGE;
case query::TypedValue::Type::Path:
return MGP_VALUE_TYPE_PATH;
case query::TypedValue::Type::Date:
return MGP_VALUE_TYPE_DATE;
case query::TypedValue::Type::LocalTime:
return MGP_VALUE_TYPE_LOCAL_TIME;
case query::TypedValue::Type::LocalDateTime:
return MGP_VALUE_TYPE_LOCAL_DATE_TIME;
case query::TypedValue::Type::Duration:
return MGP_VALUE_TYPE_DURATION;
default:
// TODO(antonio2368): Implement this when we add mgp temporal types
LOG_FATAL("Unsupported value in the procedures");
}
}
@ -312,6 +323,14 @@ query::TypedValue ToTypedValue(const mgp_value &val, utils::MemoryResource *memo
}
return query::TypedValue(std::move(tv_path));
}
case MGP_VALUE_TYPE_DATE:
return query::TypedValue(val.date_v->date, memory);
case MGP_VALUE_TYPE_LOCAL_TIME:
return query::TypedValue(val.local_time_v->local_time, memory);
case MGP_VALUE_TYPE_LOCAL_DATE_TIME:
return query::TypedValue(val.local_date_time_v->local_date_time, memory);
case MGP_VALUE_TYPE_DURATION:
return query::TypedValue(val.duration_v->duration, memory);
}
}
@ -355,6 +374,26 @@ mgp_value::mgp_value(mgp_path *val, utils::MemoryResource *m) noexcept
MG_ASSERT(val->GetMemoryResource() == m, "Unable to take ownership of a pointer with different allocator.");
}
mgp_value::mgp_value(mgp_date *val, utils::MemoryResource *m) noexcept
: type(MGP_VALUE_TYPE_DATE), memory(m), date_v(val) {
MG_ASSERT(val->GetMemoryResource() == m, "Unable to take ownership of a pointer with different allocator.");
}
mgp_value::mgp_value(mgp_local_time *val, utils::MemoryResource *m) noexcept
: type(MGP_VALUE_TYPE_LOCAL_TIME), memory(m), local_time_v(val) {
MG_ASSERT(val->GetMemoryResource() == m, "Unable to take ownership of a pointer with different allocator.");
}
mgp_value::mgp_value(mgp_local_date_time *val, utils::MemoryResource *m) noexcept
: type(MGP_VALUE_TYPE_LOCAL_DATE_TIME), memory(m), local_date_time_v(val) {
MG_ASSERT(val->GetMemoryResource() == m, "Unable to take ownership of a pointer with different allocator.");
}
mgp_value::mgp_value(mgp_duration *val, utils::MemoryResource *m) noexcept
: type(MGP_VALUE_TYPE_DURATION), memory(m), duration_v(val) {
MG_ASSERT(val->GetMemoryResource() == m, "Unable to take ownership of a pointer with different allocator.");
}
mgp_value::mgp_value(const query::TypedValue &tv, mgp_graph *graph, utils::MemoryResource *m)
: type(FromTypedValueType(tv.type())), memory(m) {
switch (type) {
@ -427,6 +466,26 @@ mgp_value::mgp_value(const query::TypedValue &tv, mgp_graph *graph, utils::Memor
path_v = allocator.new_object<mgp_path>(std::move(tmp_path));
break;
}
case MGP_VALUE_TYPE_DATE: {
utils::Allocator<mgp_date> allocator(m);
date_v = allocator.new_object<mgp_date>(tv.ValueDate());
break;
}
case MGP_VALUE_TYPE_LOCAL_TIME: {
utils::Allocator<mgp_local_time> allocator(m);
local_time_v = allocator.new_object<mgp_local_time>(tv.ValueLocalTime());
break;
}
case MGP_VALUE_TYPE_LOCAL_DATE_TIME: {
utils::Allocator<mgp_local_date_time> allocator(m);
local_date_time_v = allocator.new_object<mgp_local_date_time>(tv.ValueLocalDateTime());
break;
}
case MGP_VALUE_TYPE_DURATION: {
utils::Allocator<mgp_duration> allocator(m);
duration_v = allocator.new_object<mgp_duration>(tv.ValueDuration());
break;
}
}
}
@ -481,8 +540,33 @@ mgp_value::mgp_value(const storage::PropertyValue &pv, utils::MemoryResource *m)
break;
}
case storage::PropertyValue::Type::TemporalData: {
// TODO(antonio2368): Add support for temporala data types
LOG_FATAL("Unsupported type");
const auto &temporal_data = pv.ValueTemporalData();
switch (temporal_data.type) {
case storage::TemporalType::Date: {
type = MGP_VALUE_TYPE_DATE;
utils::Allocator<mgp_date> allocator(m);
date_v = allocator.new_object<mgp_date>(temporal_data.microseconds);
break;
}
case storage::TemporalType::LocalTime: {
type = MGP_VALUE_TYPE_LOCAL_TIME;
utils::Allocator<mgp_local_time> allocator(m);
local_time_v = allocator.new_object<mgp_local_time>(temporal_data.microseconds);
break;
}
case storage::TemporalType::LocalDateTime: {
type = MGP_VALUE_TYPE_LOCAL_DATE_TIME;
utils::Allocator<mgp_local_date_time> allocator(m);
local_date_time_v = allocator.new_object<mgp_local_date_time>(temporal_data.microseconds);
break;
}
case storage::TemporalType::Duration: {
type = MGP_VALUE_TYPE_DURATION;
utils::Allocator<mgp_duration> allocator(m);
duration_v = allocator.new_object<mgp_duration>(temporal_data.microseconds);
break;
}
}
}
}
}
@ -528,6 +612,26 @@ mgp_value::mgp_value(const mgp_value &other, utils::MemoryResource *m) : type(ot
path_v = allocator.new_object<mgp_path>(*other.path_v);
break;
}
case MGP_VALUE_TYPE_DATE: {
utils::Allocator<mgp_date> allocator(m);
date_v = allocator.new_object<mgp_date>(*other.date_v);
break;
}
case MGP_VALUE_TYPE_LOCAL_TIME: {
utils::Allocator<mgp_local_time> allocator(m);
local_time_v = allocator.new_object<mgp_local_time>(*other.local_time_v);
break;
}
case MGP_VALUE_TYPE_LOCAL_DATE_TIME: {
utils::Allocator<mgp_local_date_time> allocator(m);
local_date_time_v = allocator.new_object<mgp_local_date_time>(*other.local_date_time_v);
break;
}
case MGP_VALUE_TYPE_DURATION: {
utils::Allocator<mgp_duration> allocator(m);
duration_v = allocator.new_object<mgp_duration>(*other.duration_v);
break;
}
}
}
@ -561,6 +665,18 @@ void DeleteValueMember(mgp_value *value) noexcept {
case MGP_VALUE_TYPE_PATH:
allocator.delete_object(value->path_v);
return;
case MGP_VALUE_TYPE_DATE:
allocator.delete_object(value->date_v);
return;
case MGP_VALUE_TYPE_LOCAL_TIME:
allocator.delete_object(value->local_time_v);
return;
case MGP_VALUE_TYPE_LOCAL_DATE_TIME:
allocator.delete_object(value->local_date_time_v);
return;
case MGP_VALUE_TYPE_DURATION:
allocator.delete_object(value->duration_v);
return;
}
}
@ -632,6 +748,47 @@ mgp_value::mgp_value(mgp_value &&other, utils::MemoryResource *m) : type(other.t
path_v = allocator.new_object<mgp_path>(std::move(*other.path_v));
}
break;
case MGP_VALUE_TYPE_DATE:
static_assert(std::is_pointer_v<decltype(date_v)>, "Expected to move date_v by copying pointers.");
if (*other.GetMemoryResource() == *m) {
date_v = other.date_v;
other.type = MGP_VALUE_TYPE_NULL;
} else {
utils::Allocator<mgp_date> allocator(m);
date_v = allocator.new_object<mgp_date>(*other.date_v);
}
break;
case MGP_VALUE_TYPE_LOCAL_TIME:
static_assert(std::is_pointer_v<decltype(local_time_v)>, "Expected to move local_time_v by copying pointers.");
if (*other.GetMemoryResource() == *m) {
local_time_v = other.local_time_v;
other.type = MGP_VALUE_TYPE_NULL;
} else {
utils::Allocator<mgp_local_time> allocator(m);
local_time_v = allocator.new_object<mgp_local_time>(*other.local_time_v);
}
break;
case MGP_VALUE_TYPE_LOCAL_DATE_TIME:
static_assert(std::is_pointer_v<decltype(local_date_time_v)>,
"Expected to move local_date_time_v by copying pointers.");
if (*other.GetMemoryResource() == *m) {
local_date_time_v = other.local_date_time_v;
other.type = MGP_VALUE_TYPE_NULL;
} else {
utils::Allocator<mgp_local_date_time> allocator(m);
local_date_time_v = allocator.new_object<mgp_local_date_time>(*other.local_date_time_v);
}
break;
case MGP_VALUE_TYPE_DURATION:
static_assert(std::is_pointer_v<decltype(duration_v)>, "Expected to move duration_v by copying pointers.");
if (*other.GetMemoryResource() == *m) {
duration_v = other.duration_v;
other.type = MGP_VALUE_TYPE_NULL;
} else {
utils::Allocator<mgp_duration> allocator(m);
duration_v = allocator.new_object<mgp_duration>(*other.duration_v);
}
break;
}
DeleteValueMember(&other);
other.type = MGP_VALUE_TYPE_NULL;
@ -675,6 +832,10 @@ DEFINE_MGP_VALUE_MAKE(map)
DEFINE_MGP_VALUE_MAKE(vertex)
DEFINE_MGP_VALUE_MAKE(edge)
DEFINE_MGP_VALUE_MAKE(path)
DEFINE_MGP_VALUE_MAKE(date)
DEFINE_MGP_VALUE_MAKE(local_time)
DEFINE_MGP_VALUE_MAKE(local_date_time)
DEFINE_MGP_VALUE_MAKE(duration)
namespace {
mgp_value_type MgpValueGetType(const mgp_value &val) noexcept { return val.type; }
@ -704,6 +865,10 @@ DEFINE_MGP_VALUE_IS(map, MAP)
DEFINE_MGP_VALUE_IS(vertex, VERTEX)
DEFINE_MGP_VALUE_IS(edge, EDGE)
DEFINE_MGP_VALUE_IS(path, PATH)
DEFINE_MGP_VALUE_IS(date, DATE)
DEFINE_MGP_VALUE_IS(local_time, LOCAL_TIME)
DEFINE_MGP_VALUE_IS(local_date_time, LOCAL_DATE_TIME)
DEFINE_MGP_VALUE_IS(duration, DURATION)
mgp_error mgp_value_get_bool(mgp_value *val, int *result) {
*result = val->bool_v ? 1 : 0;
@ -735,6 +900,10 @@ DEFINE_MGP_VALUE_GET(map)
DEFINE_MGP_VALUE_GET(vertex)
DEFINE_MGP_VALUE_GET(edge)
DEFINE_MGP_VALUE_GET(path)
DEFINE_MGP_VALUE_GET(date)
DEFINE_MGP_VALUE_GET(local_time)
DEFINE_MGP_VALUE_GET(local_date_time)
DEFINE_MGP_VALUE_GET(duration)
mgp_error mgp_list_make_empty(size_t capacity, mgp_memory *memory, mgp_list **result) {
return WrapExceptions(
@ -975,6 +1144,274 @@ mgp_error mgp_path_equal(mgp_path *p1, mgp_path *p2, int *result) {
result);
}
mgp_error mgp_date_from_string(const char *string, mgp_memory *memory, mgp_date **date) {
return WrapExceptions([string, memory] { return NewRawMgpObject<mgp_date>(memory, string); }, date);
}
mgp_error mgp_date_from_parameters(mgp_date_parameters *parameters, mgp_memory *memory, mgp_date **date) {
return WrapExceptions([parameters, memory] { return NewRawMgpObject<mgp_date>(memory, parameters); }, date);
}
mgp_error mgp_date_copy(mgp_date *date, mgp_memory *memory, mgp_date **result) {
return WrapExceptions([date, memory] { return NewRawMgpObject<mgp_date>(memory, *date); }, result);
}
void mgp_date_destroy(mgp_date *date) { DeleteRawMgpObject(date); }
mgp_error mgp_date_equal(mgp_date *first, mgp_date *second, int *result) {
return WrapExceptions([first, second] { return first->date == second->date; }, result);
}
mgp_error mgp_date_get_year(mgp_date *date, int *year) {
return WrapExceptions([date] { return date->date.years; }, year);
}
mgp_error mgp_date_get_month(mgp_date *date, int *month) {
return WrapExceptions([date] { return date->date.months; }, month);
}
mgp_error mgp_date_get_day(mgp_date *date, int *day) {
return WrapExceptions([date] { return date->date.days; }, day);
}
mgp_error mgp_date_timestamp(mgp_date *date, int64_t *timestamp) {
return WrapExceptions([date] { return static_cast<int>(date->date.MicrosecondsSinceEpoch()); }, timestamp);
}
mgp_error mgp_date_now(mgp_memory *memory, mgp_date **date) {
return WrapExceptions([memory] { return NewRawMgpObject<mgp_date>(memory, utils::UtcToday()); }, date);
}
mgp_error mgp_date_add_duration(mgp_date *date, mgp_duration *dur, mgp_memory *memory, mgp_date **result) {
return WrapExceptions([date, dur, memory] { return NewRawMgpObject<mgp_date>(memory, date->date + dur->duration); },
result);
}
mgp_error mgp_date_sub_duration(mgp_date *date, mgp_duration *dur, mgp_memory *memory, mgp_date **result) {
return WrapExceptions([date, dur, memory] { return NewRawMgpObject<mgp_date>(memory, date->date - dur->duration); },
result);
}
mgp_error mgp_date_diff(mgp_date *first, mgp_date *second, mgp_memory *memory, mgp_duration **result) {
return WrapExceptions(
[first, second, memory] { return NewRawMgpObject<mgp_duration>(memory, first->date - second->date); }, result);
}
mgp_error mgp_local_time_from_string(const char *string, mgp_memory *memory, mgp_local_time **local_time) {
return WrapExceptions([string, memory] { return NewRawMgpObject<mgp_local_time>(memory, string); }, local_time);
}
mgp_error mgp_local_time_from_parameters(mgp_local_time_parameters *parameters, mgp_memory *memory,
mgp_local_time **local_time) {
return WrapExceptions([parameters, memory] { return NewRawMgpObject<mgp_local_time>(memory, parameters); },
local_time);
}
mgp_error mgp_local_time_copy(mgp_local_time *local_time, mgp_memory *memory, mgp_local_time **result) {
return WrapExceptions([local_time, memory] { return NewRawMgpObject<mgp_local_time>(memory, *local_time); }, result);
}
void mgp_local_time_destroy(mgp_local_time *local_time) { DeleteRawMgpObject(local_time); }
mgp_error mgp_local_time_equal(mgp_local_time *first, mgp_local_time *second, int *result) {
return WrapExceptions([first, second] { return first->local_time == second->local_time; }, result);
}
mgp_error mgp_local_time_get_hour(mgp_local_time *local_time, int *hour) {
return WrapExceptions([local_time] { return local_time->local_time.hours; }, hour);
}
mgp_error mgp_local_time_get_minue(mgp_local_time *local_time, int *minute) {
return WrapExceptions([local_time] { return local_time->local_time.minutes; }, minute);
}
mgp_error mgp_local_time_get_second(mgp_local_time *local_time, int *second) {
return WrapExceptions([local_time] { return local_time->local_time.seconds; }, second);
}
mgp_error mgp_local_time_get_millisecond(mgp_local_time *local_time, int *millisecond) {
return WrapExceptions([local_time] { return local_time->local_time.milliseconds; }, millisecond);
}
mgp_error mgp_local_time_get_microsecond(mgp_local_time *local_time, int *microsecond) {
return WrapExceptions([local_time] { return local_time->local_time.microseconds; }, microsecond);
}
mgp_error mgp_local_time_timestamp(mgp_local_time *local_time, int64_t *timestamp) {
return WrapExceptions([local_time] { return static_cast<int>(local_time->local_time.MicrosecondsSinceEpoch()); },
timestamp);
}
mgp_error mgp_local_time_now(mgp_memory *memory, mgp_local_time **local_time) {
return WrapExceptions([memory] { return NewRawMgpObject<mgp_local_time>(memory, utils::UtcLocalTime()); },
local_time);
}
mgp_error mgp_local_time_add_duration(mgp_local_time *local_time, mgp_duration *dur, mgp_memory *memory,
mgp_local_time **result) {
return WrapExceptions(
[local_time, dur, memory] {
return NewRawMgpObject<mgp_local_time>(memory, local_time->local_time + dur->duration);
},
result);
}
mgp_error mgp_local_time_sub_duration(mgp_local_time *local_time, mgp_duration *dur, mgp_memory *memory,
mgp_local_time **result) {
return WrapExceptions(
[local_time, dur, memory] {
return NewRawMgpObject<mgp_local_time>(memory, local_time->local_time - dur->duration);
},
result);
}
mgp_error mgp_local_time_diff(mgp_local_time *first, mgp_local_time *second, mgp_memory *memory,
mgp_duration **result) {
return WrapExceptions(
[first, second, memory] { return NewRawMgpObject<mgp_duration>(memory, first->local_time - second->local_time); },
result);
}
mgp_error mgp_local_date_time_from_string(const char *string, mgp_memory *memory,
mgp_local_date_time **local_date_time) {
return WrapExceptions([string, memory] { return NewRawMgpObject<mgp_local_date_time>(memory, string); },
local_date_time);
}
mgp_error mgp_local_date_time_from_parameters(mgp_local_date_time_parameters *parameters, mgp_memory *memory,
mgp_local_date_time **local_date_time) {
return WrapExceptions([parameters, memory] { return NewRawMgpObject<mgp_local_date_time>(memory, parameters); },
local_date_time);
}
mgp_error mgp_local_date_time_copy(mgp_local_date_time *local_date_time, mgp_memory *memory,
mgp_local_date_time **result) {
return WrapExceptions(
[local_date_time, memory] { return NewRawMgpObject<mgp_local_date_time>(memory, *local_date_time); }, result);
}
void mgp_local_date_time_destroy(mgp_local_date_time *local_date_time) { DeleteRawMgpObject(local_date_time); }
mgp_error mgp_local_date_time_equal(mgp_local_date_time *first, mgp_local_date_time *second, int *result) {
return WrapExceptions([first, second] { return first->local_date_time == second->local_date_time; }, result);
}
mgp_error mgp_local_date_time_get_year(mgp_local_date_time *local_date_time, int *year) {
return WrapExceptions([local_date_time] { return local_date_time->local_date_time.date.years; }, year);
}
mgp_error mgp_local_date_time_get_month(mgp_local_date_time *local_date_time, int *month) {
return WrapExceptions([local_date_time] { return local_date_time->local_date_time.date.months; }, month);
}
mgp_error mgp_local_date_time_get_day(mgp_local_date_time *local_date_time, int *day) {
return WrapExceptions([local_date_time] { return local_date_time->local_date_time.date.days; }, day);
}
mgp_error mgp_local_date_time_get_hour(mgp_local_date_time *local_date_time, int *hour) {
return WrapExceptions([local_date_time] { return local_date_time->local_date_time.local_time.hours; }, hour);
}
mgp_error mgp_local_date_time_get_minute(mgp_local_date_time *local_date_time, int *minute) {
return WrapExceptions([local_date_time] { return local_date_time->local_date_time.local_time.minutes; }, minute);
}
mgp_error mgp_local_date_time_get_second(mgp_local_date_time *local_date_time, int *second) {
return WrapExceptions([local_date_time] { return local_date_time->local_date_time.local_time.seconds; }, second);
}
mgp_error mgp_local_date_time_get_millisecond(mgp_local_date_time *local_date_time, int *millisecond) {
return WrapExceptions([local_date_time] { return local_date_time->local_date_time.local_time.milliseconds; },
millisecond);
}
mgp_error mgp_local_date_time_get_microsecond(mgp_local_date_time *local_date_time, int *microsecond) {
return WrapExceptions([local_date_time] { return local_date_time->local_date_time.local_time.microseconds; },
microsecond);
}
mgp_error mgp_local_date_time_timestamp(mgp_local_date_time *local_date_time, int64_t *timestamp) {
return WrapExceptions(
[local_date_time] { return static_cast<int>(local_date_time->local_date_time.MicrosecondsSinceEpoch()); },
timestamp);
}
mgp_error mgp_local_date_time_now(mgp_memory *memory, mgp_local_date_time **local_date_time) {
return WrapExceptions([memory] { return NewRawMgpObject<mgp_local_date_time>(memory, utils::UtcLocalDateTime()); },
local_date_time);
}
mgp_error mgp_local_date_time_add_duration(mgp_local_date_time *local_date_time, mgp_duration *dur, mgp_memory *memory,
mgp_local_date_time **result) {
return WrapExceptions(
[local_date_time, dur, memory] {
return NewRawMgpObject<mgp_local_date_time>(memory, local_date_time->local_date_time + dur->duration);
},
result);
}
mgp_error mgp_local_date_time_sub_duration(mgp_local_date_time *local_date_time, mgp_duration *dur, mgp_memory *memory,
mgp_local_date_time **result) {
return WrapExceptions(
[local_date_time, dur, memory] {
return NewRawMgpObject<mgp_local_date_time>(memory, local_date_time->local_date_time - dur->duration);
},
result);
}
mgp_error mgp_local_date_time_diff(mgp_local_date_time *first, mgp_local_date_time *second, mgp_memory *memory,
mgp_duration **result) {
return WrapExceptions(
[first, second, memory] {
return NewRawMgpObject<mgp_duration>(memory, first->local_date_time - second->local_date_time);
},
result);
}
mgp_error mgp_duration_from_string(const char *string, mgp_memory *memory, mgp_duration **duration) {
return WrapExceptions([memory, string] { return NewRawMgpObject<mgp_duration>(memory, string); }, duration);
}
mgp_error mgp_duration_from_parameters(mgp_duration_parameters *parameters, mgp_memory *memory,
mgp_duration **duration) {
return WrapExceptions([memory, parameters] { return NewRawMgpObject<mgp_duration>(memory, parameters); }, duration);
}
mgp_error mgp_duration_from_microseconds(int64_t microseconds, mgp_memory *memory, mgp_duration **duration) {
return WrapExceptions([microseconds, memory] { return NewRawMgpObject<mgp_duration>(memory, microseconds); },
duration);
}
mgp_error mgp_duration_copy(mgp_duration *duration, mgp_memory *memory, mgp_duration **result) {
return WrapExceptions([duration, memory] { return NewRawMgpObject<mgp_duration>(memory, *duration); }, result);
}
void mgp_duration_destroy(mgp_duration *duration) { DeleteRawMgpObject(duration); }
mgp_error mgp_duration_get_microseconds(mgp_duration *duration, int64_t *microseconds) {
return WrapExceptions([duration] { return duration->duration.microseconds; }, microseconds);
}
mgp_error mgp_duration_equal(mgp_duration *first, mgp_duration *second, int *result) {
return WrapExceptions([first, second] { return first->duration == second->duration; }, result);
}
mgp_error mgp_duration_neg(mgp_duration *dur, mgp_memory *memory, mgp_duration **result) {
return WrapExceptions([memory, dur] { return NewRawMgpObject<mgp_duration>(memory, -dur->duration); }, result);
}
mgp_error mgp_duration_add(mgp_duration *first, mgp_duration *second, mgp_memory *memory, mgp_duration **result) {
return WrapExceptions(
[memory, first, second] { return NewRawMgpObject<mgp_duration>(memory, first->duration + second->duration); },
result);
}
mgp_error mgp_duration_sub(mgp_duration *first, mgp_duration *second, mgp_memory *memory, mgp_duration **result) {
return WrapExceptions(
[memory, first, second] { return NewRawMgpObject<mgp_duration>(memory, first->duration - second->duration); },
result);
}
/// Plugin Result
mgp_error mgp_result_set_error_msg(mgp_result *res, const char *msg) {
@ -1106,6 +1543,18 @@ storage::PropertyValue ToPropertyValue(const mgp_value &value) {
return ToPropertyValue(*value.list_v);
case MGP_VALUE_TYPE_MAP:
return ToPropertyValue(*value.map_v);
case MGP_VALUE_TYPE_DATE:
return storage::PropertyValue{
storage::TemporalData{storage::TemporalType::Date, value.date_v->date.MicrosecondsSinceEpoch()}};
case MGP_VALUE_TYPE_LOCAL_TIME:
return storage::PropertyValue{storage::TemporalData{storage::TemporalType::LocalTime,
value.local_time_v->local_time.MicrosecondsSinceEpoch()}};
case MGP_VALUE_TYPE_LOCAL_DATE_TIME:
return storage::PropertyValue{storage::TemporalData{
storage::TemporalType::LocalDateTime, value.local_date_time_v->local_date_time.MicrosecondsSinceEpoch()}};
case MGP_VALUE_TYPE_DURATION:
return storage::PropertyValue{
storage::TemporalData{storage::TemporalType::Duration, value.duration_v->duration.microseconds}};
case MGP_VALUE_TYPE_VERTEX:
throw ValueConversionException{"A vertex is not a valid property value! "};
case MGP_VALUE_TYPE_EDGE:
@ -1754,6 +2203,10 @@ DEFINE_MGP_TYPE_GETTER(Map, map);
DEFINE_MGP_TYPE_GETTER(Node, node);
DEFINE_MGP_TYPE_GETTER(Relationship, relationship);
DEFINE_MGP_TYPE_GETTER(Path, path);
DEFINE_MGP_TYPE_GETTER(Date, date);
DEFINE_MGP_TYPE_GETTER(LocalTime, local_time);
DEFINE_MGP_TYPE_GETTER(LocalDateTime, local_date_time);
DEFINE_MGP_TYPE_GETTER(Duration, duration);
mgp_error mgp_type_list(mgp_type *type, mgp_type **result) {
return WrapExceptions(
@ -1850,6 +2303,10 @@ mgp_error mgp_proc_add_opt_arg(mgp_proc *proc, const char *name, mgp_type *type,
case MGP_VALUE_TYPE_STRING:
case MGP_VALUE_TYPE_LIST:
case MGP_VALUE_TYPE_MAP:
case MGP_VALUE_TYPE_DATE:
case MGP_VALUE_TYPE_LOCAL_TIME:
case MGP_VALUE_TYPE_LOCAL_DATE_TIME:
case MGP_VALUE_TYPE_DURATION:
break;
}
// Default value must be of required `type`.
@ -1941,16 +2398,18 @@ std::ostream &PrintValue(const TypedValue &value, std::ostream *stream) {
PrintValue(item.second, &stream);
});
return (*stream) << "}";
case TypedValue::Type::Date:
return (*stream) << value.ValueDate();
case TypedValue::Type::LocalTime:
return (*stream) << value.ValueLocalTime();
case TypedValue::Type::LocalDateTime:
return (*stream) << value.ValueLocalDateTime();
case TypedValue::Type::Duration:
return (*stream) << value.ValueDuration();
case TypedValue::Type::Vertex:
case TypedValue::Type::Edge:
case TypedValue::Type::Path:
LOG_FATAL("value must not be a graph element");
case TypedValue::Type::Date:
case TypedValue::Type::LocalTime:
case TypedValue::Type::LocalDateTime:
case TypedValue::Type::Duration:
// TODO(antonio2368): Check how to print out nicely temporal types
LOG_FATAL("Temporal types not imlemented yet");
}
}

View File

@ -18,6 +18,7 @@
#include "utils/pmr/map.hpp"
#include "utils/pmr/string.hpp"
#include "utils/pmr/vector.hpp"
#include "utils/temporal.hpp"
/// Wraps memory resource used in custom procedures.
///
/// This should have been `using mgp_memory = utils::MemoryResource`, but that's
@ -53,6 +54,11 @@ struct mgp_value {
/// Take ownership of the mgp_path, MemoryResource must match.
mgp_value(mgp_path *, utils::MemoryResource *) noexcept;
mgp_value(mgp_date *, utils::MemoryResource *) noexcept;
mgp_value(mgp_local_time *, utils::MemoryResource *) noexcept;
mgp_value(mgp_local_date_time *, utils::MemoryResource *) noexcept;
mgp_value(mgp_duration *, utils::MemoryResource *) noexcept;
/// Construct by copying query::TypedValue using utils::MemoryResource.
/// mgp_graph is needed to construct mgp_vertex and mgp_edge.
/// @throw std::bad_alloc
@ -102,9 +108,214 @@ struct mgp_value {
mgp_vertex *vertex_v;
mgp_edge *edge_v;
mgp_path *path_v;
mgp_date *date_v;
mgp_local_time *local_time_v;
mgp_local_date_time *local_date_time_v;
mgp_duration *duration_v;
};
};
inline utils::DateParameters MapDateParameters(const mgp_date_parameters *parameters) {
return {.years = parameters->year, .months = parameters->month, .days = parameters->day};
}
struct mgp_date {
/// Allocator type so that STL containers are aware that we need one.
/// We don't actually need this, but it simplifies the C API, because we store
/// the allocator which was used to allocate `this`.
using allocator_type = utils::Allocator<mgp_date>;
// Hopefully utils::Date copy constructor remains noexcept, so that we can
// have everything noexcept here.
static_assert(std::is_nothrow_copy_constructible_v<utils::Date>);
mgp_date(const utils::Date &date, utils::MemoryResource *memory) noexcept : memory(memory), date(date) {}
mgp_date(const std::string_view string, utils::MemoryResource *memory) noexcept
: memory(memory), date(utils::ParseDateParameters(string).first) {}
mgp_date(const mgp_date_parameters *parameters, utils::MemoryResource *memory) noexcept
: memory(memory), date(MapDateParameters(parameters)) {}
mgp_date(const int64_t microseconds, utils::MemoryResource *memory) noexcept : memory(memory), date(microseconds) {}
mgp_date(const mgp_date &other, utils::MemoryResource *memory) noexcept : memory(memory), date(other.date) {}
mgp_date(mgp_date &&other, utils::MemoryResource *memory) noexcept : memory(memory), date(other.date) {}
mgp_date(mgp_date &&other) noexcept : memory(other.memory), date(other.date) {}
/// Copy construction without utils::MemoryResource is not allowed.
mgp_date(const mgp_date &) = delete;
mgp_date &operator=(const mgp_date &) = delete;
mgp_date &operator=(mgp_date &&) = delete;
~mgp_date() = default;
utils::MemoryResource *GetMemoryResource() const noexcept { return memory; }
utils::MemoryResource *memory;
utils::Date date;
};
inline utils::LocalTimeParameters MapLocalTimeParameters(const mgp_local_time_parameters *parameters) {
return {.hours = parameters->hour,
.minutes = parameters->minute,
.seconds = parameters->second,
.milliseconds = parameters->millisecond,
.microseconds = parameters->microsecond};
}
struct mgp_local_time {
/// Allocator type so that STL containers are aware that we need one.
/// We don't actually need this, but it simplifies the C API, because we store
/// the allocator which was used to allocate `this`.
using allocator_type = utils::Allocator<mgp_local_time>;
// Hopefully utils::LocalTime copy constructor remains noexcept, so that we can
// have everything noexcept here.
static_assert(std::is_nothrow_copy_constructible_v<utils::LocalTime>);
mgp_local_time(const std::string_view string, utils::MemoryResource *memory) noexcept
: memory(memory), local_time(utils::ParseLocalTimeParameters(string).first) {}
mgp_local_time(const mgp_local_time_parameters *parameters, utils::MemoryResource *memory) noexcept
: memory(memory), local_time(MapLocalTimeParameters(parameters)) {}
mgp_local_time(const utils::LocalTime &local_time, utils::MemoryResource *memory) noexcept
: memory(memory), local_time(local_time) {}
mgp_local_time(const int64_t microseconds, utils::MemoryResource *memory) noexcept
: memory(memory), local_time(microseconds) {}
mgp_local_time(const mgp_local_time &other, utils::MemoryResource *memory) noexcept
: memory(memory), local_time(other.local_time) {}
mgp_local_time(mgp_local_time &&other, utils::MemoryResource *memory) noexcept
: memory(memory), local_time(other.local_time) {}
mgp_local_time(mgp_local_time &&other) noexcept : memory(other.memory), local_time(other.local_time) {}
/// Copy construction without utils::MemoryResource is not allowed.
mgp_local_time(const mgp_local_time &) = delete;
mgp_local_time &operator=(const mgp_local_time &) = delete;
mgp_local_time &operator=(mgp_local_time &&) = delete;
~mgp_local_time() = default;
utils::MemoryResource *GetMemoryResource() const noexcept { return memory; }
utils::MemoryResource *memory;
utils::LocalTime local_time;
};
inline utils::LocalDateTime CreateLocalDateTimeFromString(const std::string_view string) {
const auto &[date_parameters, local_time_parameters] = utils::ParseLocalDateTimeParameters(string);
return utils::LocalDateTime{date_parameters, local_time_parameters};
}
struct mgp_local_date_time {
/// Allocator type so that STL containers are aware that we need one.
/// We don't actually need this, but it simplifies the C API, because we store
/// the allocator which was used to allocate `this`.
using allocator_type = utils::Allocator<mgp_local_date_time>;
// Hopefully utils::LocalDateTime copy constructor remains noexcept, so that we can
// have everything noexcept here.
static_assert(std::is_nothrow_copy_constructible_v<utils::LocalDateTime>);
mgp_local_date_time(const utils::LocalDateTime &local_date_time, utils::MemoryResource *memory) noexcept
: memory(memory), local_date_time(local_date_time) {}
mgp_local_date_time(const std::string_view string, utils::MemoryResource *memory) noexcept
: memory(memory), local_date_time(CreateLocalDateTimeFromString(string)) {}
mgp_local_date_time(const mgp_local_date_time_parameters *parameters, utils::MemoryResource *memory) noexcept
: memory(memory),
local_date_time(MapDateParameters(parameters->date_parameters),
MapLocalTimeParameters(parameters->local_time_parameters)) {}
mgp_local_date_time(const int64_t microseconds, utils::MemoryResource *memory) noexcept
: memory(memory), local_date_time(microseconds) {}
mgp_local_date_time(const mgp_local_date_time &other, utils::MemoryResource *memory) noexcept
: memory(memory), local_date_time(other.local_date_time) {}
mgp_local_date_time(mgp_local_date_time &&other, utils::MemoryResource *memory) noexcept
: memory(memory), local_date_time(other.local_date_time) {}
mgp_local_date_time(mgp_local_date_time &&other) noexcept
: memory(other.memory), local_date_time(other.local_date_time) {}
/// Copy construction without utils::MemoryResource is not allowed.
mgp_local_date_time(const mgp_local_date_time &) = delete;
mgp_local_date_time &operator=(const mgp_local_date_time &) = delete;
mgp_local_date_time &operator=(mgp_local_date_time &&) = delete;
~mgp_local_date_time() = default;
utils::MemoryResource *GetMemoryResource() const noexcept { return memory; }
utils::MemoryResource *memory;
utils::LocalDateTime local_date_time;
};
inline utils::DurationParameters MapDurationParameters(const mgp_duration_parameters *parameters) {
return {.days = parameters->day,
.hours = parameters->hour,
.minutes = parameters->minute,
.seconds = parameters->second,
.milliseconds = parameters->millisecond,
.microseconds = parameters->microsecond};
}
struct mgp_duration {
/// Allocator type so that STL containers are aware that we need one.
/// We don't actually need this, but it simplifies the C API, because we store
/// the allocator which was used to allocate `this`.
using allocator_type = utils::Allocator<mgp_duration>;
// Hopefully utils::Duration copy constructor remains noexcept, so that we can
// have everything noexcept here.
static_assert(std::is_nothrow_copy_constructible_v<utils::Duration>);
mgp_duration(const std::string_view string, utils::MemoryResource *memory) noexcept
: memory(memory), duration(utils::ParseDurationParameters(string)) {}
mgp_duration(const mgp_duration_parameters *parameters, utils::MemoryResource *memory) noexcept
: memory(memory), duration(MapDurationParameters(parameters)) {}
mgp_duration(const utils::Duration &duration, utils::MemoryResource *memory) noexcept
: memory(memory), duration(duration) {}
mgp_duration(const int64_t microseconds, utils::MemoryResource *memory) noexcept
: memory(memory), duration(microseconds) {}
mgp_duration(const mgp_duration &other, utils::MemoryResource *memory) noexcept
: memory(memory), duration(other.duration) {}
mgp_duration(mgp_duration &&other, utils::MemoryResource *memory) noexcept
: memory(memory), duration(other.duration) {}
mgp_duration(mgp_duration &&other) noexcept : memory(other.memory), duration(other.duration) {}
/// Copy construction without utils::MemoryResource is not allowed.
mgp_duration(const mgp_duration &) = delete;
mgp_duration &operator=(const mgp_duration &) = delete;
mgp_duration &operator=(mgp_duration &&) = delete;
~mgp_duration() = default;
utils::MemoryResource *GetMemoryResource() const noexcept { return memory; }
utils::MemoryResource *memory;
utils::Duration duration;
};
struct mgp_list {
/// Allocator type so that STL containers are aware that we need one.
using allocator_type = utils::Allocator<mgp_list>;

View File

@ -1,5 +1,6 @@
#include "query/procedure/py_module.hpp"
#include <datetime.h>
#include <pyerrors.h>
#include <array>
#include <sstream>
@ -9,6 +10,7 @@
#include "query/procedure/mg_procedure_helpers.hpp"
#include "query/procedure/mg_procedure_impl.hpp"
#include "utils/memory.hpp"
#include "utils/on_scope_exit.hpp"
#include "utils/pmr/vector.hpp"
@ -1127,6 +1129,10 @@ DEFINE_PY_MGP_MODULE_TYPE(Map, map);
DEFINE_PY_MGP_MODULE_TYPE(Node, node);
DEFINE_PY_MGP_MODULE_TYPE(Relationship, relationship);
DEFINE_PY_MGP_MODULE_TYPE(Path, path);
DEFINE_PY_MGP_MODULE_TYPE(Date, date);
DEFINE_PY_MGP_MODULE_TYPE(LocalTime, local_time);
DEFINE_PY_MGP_MODULE_TYPE(LocalDateTime, local_date_time);
DEFINE_PY_MGP_MODULE_TYPE(Duration, duration);
static PyMethodDef PyMgpModuleMethods[] = {
{"type_nullable", PyMgpModuleTypeNullable, METH_O,
@ -1145,6 +1151,10 @@ static PyMethodDef PyMgpModuleMethods[] = {
"Get the type representing graph relationship values."},
{"type_path", PyMgpModuleTypePath, METH_NOARGS,
"Get the type representing a graph path (walk) from one node to another."},
{"type_date", PyMgpModuleTypeDate, METH_NOARGS, "Get the type representing a Date."},
{"type_local_time", PyMgpModuleTypeLocalTime, METH_NOARGS, "Get the type representing a LocalTime."},
{"type_local_date_time", PyMgpModuleTypeLocalDateTime, METH_NOARGS, "Get the type representing a LocalDateTime."},
{"type_duration", PyMgpModuleTypeDuration, METH_NOARGS, "Get the type representing a Duration."},
{nullptr},
};
@ -1956,6 +1966,10 @@ PyObject *PyInitMgpModule() {
}
}
clean_up.Disable();
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
PyDateTime_IMPORT;
return mgp;
}
@ -2055,6 +2069,30 @@ py::Object MgpValueToPyObject(const mgp_value &value, PyGraph *py_graph) {
py::Object py_path(reinterpret_cast<PyObject *>(MakePyPath(*p, py_graph)));
return py_mgp.CallMethod("Path", py_path);
}
case MGP_VALUE_TYPE_DATE: {
const auto &date = value.date_v->date;
py::Object py_date(PyDate_FromDate(date.years, date.months, date.days));
return py_date;
}
case MGP_VALUE_TYPE_LOCAL_TIME: {
const auto &local_time = value.local_time_v->local_time;
py::Object py_local_time(PyTime_FromTime(local_time.hours, local_time.minutes, local_time.seconds,
local_time.milliseconds * 1000 + local_time.microseconds));
return py_local_time;
}
case MGP_VALUE_TYPE_LOCAL_DATE_TIME: {
const auto &local_time = value.local_date_time_v->local_date_time.local_time;
const auto &date = value.local_date_time_v->local_date_time.date;
py::Object py_local_date_time(
PyDateTime_FromDateAndTime(date.years, date.months, date.days, local_time.hours, local_time.minutes,
local_time.seconds, local_time.milliseconds * 1000 + local_time.microseconds));
return py_local_date_time;
}
case MGP_VALUE_TYPE_DURATION: {
const auto &duration = value.duration_v->duration;
py::Object py_duration(PyDelta_FromDSU(0, 0, duration.microseconds));
return py_duration;
}
}
}
@ -2247,6 +2285,108 @@ mgp_value *PyObjectToMgpValue(PyObject *o, mgp_memory *memory) {
throw std::invalid_argument("'mgp.Path' is missing '_path' attribute");
}
return PyObjectToMgpValue(path.Ptr(), memory);
} else if (PyDate_CheckExact(o)) {
mgp_date_parameters parameters{
.year = PyDateTime_GET_YEAR(o), // NOLINT(cppcoreguidelines-pro-type-cstyle-cast,hicpp-signed-bitwise)
.month = PyDateTime_GET_MONTH(o), // NOLINT(cppcoreguidelines-pro-type-cstyle-cast,hicpp-signed-bitwise)
.day = PyDateTime_GET_DAY(o)}; // NOLINT(cppcoreguidelines-pro-type-cstyle-cast,hicpp-signed-bitwise)
MgpUniquePtr<mgp_date> date{nullptr, mgp_date_destroy};
if (const auto err = CreateMgpObject(date, mgp_date_from_parameters, &parameters, memory);
err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
throw std::bad_alloc{};
} else if (err != MGP_ERROR_NO_ERROR) {
throw std::runtime_error{"Unexpected error while creating mgp_date"};
}
if (const auto err = mgp_value_make_date(date.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 while creating mgp_value"};
}
static_cast<void>(date.release());
} else if (PyTime_CheckExact(o)) {
mgp_local_time_parameters parameters{
.hour = PyDateTime_TIME_GET_HOUR(o), // NOLINT(cppcoreguidelines-pro-type-cstyle-cast,hicpp-signed-bitwise)
.minute = PyDateTime_TIME_GET_MINUTE(o), // NOLINT(cppcoreguidelines-pro-type-cstyle-cast,hicpp-signed-bitwise)
.second = PyDateTime_TIME_GET_SECOND(o), // NOLINT(cppcoreguidelines-pro-type-cstyle-cast,hicpp-signed-bitwise)
.millisecond =
PyDateTime_TIME_GET_MICROSECOND(o) / // NOLINT(cppcoreguidelines-pro-type-cstyle-cast,hicpp-signed-bitwise)
1000,
.microsecond =
PyDateTime_TIME_GET_MICROSECOND(o) % // NOLINT(cppcoreguidelines-pro-type-cstyle-cast,hicpp-signed-bitwise)
1000};
MgpUniquePtr<mgp_local_time> local_time{nullptr, mgp_local_time_destroy};
if (const auto err = CreateMgpObject(local_time, mgp_local_time_from_parameters, &parameters, memory);
err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
throw std::bad_alloc{};
} else if (err != MGP_ERROR_NO_ERROR) {
throw std::runtime_error{"Unexpected error while creating mgp_local_time"};
}
if (const auto err = mgp_value_make_local_time(local_time.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 while creating mgp_value"};
}
static_cast<void>(local_time.release());
} else if (PyDateTime_CheckExact(o)) {
mgp_date_parameters date_parameters{
.year = PyDateTime_GET_YEAR(o), // NOLINT(cppcoreguidelines-pro-type-cstyle-cast,hicpp-signed-bitwise)
.month = PyDateTime_GET_MONTH(o), // NOLINT(cppcoreguidelines-pro-type-cstyle-cast,hicpp-signed-bitwise)
.day = PyDateTime_GET_DAY(o)}; // NOLINT(cppcoreguidelines-pro-type-cstyle-cast,hicpp-signed-bitwise)
mgp_local_time_parameters local_time_parameters{
.hour = PyDateTime_DATE_GET_HOUR(o), // NOLINT(cppcoreguidelines-pro-type-cstyle-cast,hicpp-signed-bitwise)
.minute = PyDateTime_DATE_GET_MINUTE(o), // NOLINT(cppcoreguidelines-pro-type-cstyle-cast,hicpp-signed-bitwise)
.second = PyDateTime_DATE_GET_SECOND(o), // NOLINT(cppcoreguidelines-pro-type-cstyle-cast,hicpp-signed-bitwise)
.millisecond =
PyDateTime_DATE_GET_MICROSECOND(o) / // NOLINT(cppcoreguidelines-pro-type-cstyle-cast,hicpp-signed-bitwise)
1000,
.microsecond =
PyDateTime_DATE_GET_MICROSECOND(o) % // NOLINT(cppcoreguidelines-pro-type-cstyle-cast,hicpp-signed-bitwise)
1000};
mgp_local_date_time_parameters parameters{&date_parameters, &local_time_parameters};
MgpUniquePtr<mgp_local_date_time> local_date_time{nullptr, mgp_local_date_time_destroy};
if (const auto err = CreateMgpObject(local_date_time, mgp_local_date_time_from_parameters, &parameters, memory);
err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
throw std::bad_alloc{};
} else if (err != MGP_ERROR_NO_ERROR) {
throw std::runtime_error{"Unexpected error while creating mgp_local_date_time"};
}
if (const auto err = mgp_value_make_local_date_time(local_date_time.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 while creating mgp_value"};
}
static_cast<void>(local_date_time.release());
} else if (PyDelta_CheckExact(o)) {
constexpr int64_t microseconds_in_days = static_cast<std::chrono::microseconds>(std::chrono::days{1}).count();
const auto days =
PyDateTime_DELTA_GET_DAYS(o); // NOLINT(cppcoreguidelines-pro-type-cstyle-cast,hicpp-signed-bitwise)
auto microseconds =
std::abs(days) * microseconds_in_days +
PyDateTime_DELTA_GET_SECONDS(o) * 1000 * // NOLINT(cppcoreguidelines-pro-type-cstyle-cast,hicpp-signed-bitwise)
1000 +
PyDateTime_DELTA_GET_MICROSECONDS(o); // NOLINT(cppcoreguidelines-pro-type-cstyle-cast,hicpp-signed-bitwise)
microseconds *= days < 0 ? -1 : 1;
MgpUniquePtr<mgp_duration> duration{nullptr, mgp_duration_destroy};
if (const auto err = CreateMgpObject(duration, mgp_duration_from_microseconds, microseconds, memory);
err == MGP_ERROR_UNABLE_TO_ALLOCATE) {
throw std::bad_alloc{};
} else if (err != MGP_ERROR_NO_ERROR) {
throw std::runtime_error{"Unexpected error while creating mgp_duration"};
}
if (const auto err = mgp_value_make_duration(duration.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 while creating mgp_value"};
}
static_cast<void>(duration.release());
} else {
throw std::invalid_argument("Unsupported PyObject conversion");
}

View File

@ -47,18 +47,18 @@ Date::Date(const int64_t microseconds) {
Date::Date(const DateParameters &date_parameters) {
if (!IsInBounds(0, 9999, date_parameters.years)) {
throw utils::BasicException(
throw temporal::InvalidArgumentException(
"Creating a Date with invalid year parameter. The value should be an integer between 0 and 9999.");
}
if (!IsInBounds(1, 12, date_parameters.months)) {
throw utils::BasicException(
throw temporal::InvalidArgumentException(
"Creating a Date with invalid month parameter. The value should be an integer between 1 and 12.");
}
if (!IsInBounds(1, 31, date_parameters.days) ||
!IsValidDay(date_parameters.days, date_parameters.months, date_parameters.years)) {
throw utils::BasicException(
throw temporal::InvalidArgumentException(
"Creating a Date with invalid day parameter. The value should be an integer between 1 and 31, depending on the "
"month and year.");
}
@ -74,7 +74,7 @@ tm GetUtcFromSystemClockOrThrow() {
const auto today = chrono::system_clock::to_time_t(chrono::system_clock::now());
tm utc_today;
if (!gmtime_r(&today, &utc_today)) {
throw utils::BasicException("Can't access clock's UTC time");
throw temporal::InvalidArgumentException("Can't access clock's UTC time");
}
return utc_today;
}
@ -132,13 +132,13 @@ std::pair<DateParameters, bool> ParseDateParameters(std::string_view date_string
if (!std::any_of(
valid_sizes.begin(), valid_sizes.end(),
[date_string_size = date_string.size()](const auto valid_size) { return valid_size == date_string_size; })) {
throw utils::BasicException("Invalid string for date. {}", kSupportedDateFormatsHelpMessage);
throw temporal::InvalidArgumentException("Invalid string for date. {}", kSupportedDateFormatsHelpMessage);
}
DateParameters date_parameters;
auto maybe_year = ParseNumber<int64_t>(date_string, 4);
if (!maybe_year) {
throw utils::BasicException("Invalid year in the string. {}", kSupportedDateFormatsHelpMessage);
throw temporal::InvalidArgumentException("Invalid year in the string. {}", kSupportedDateFormatsHelpMessage);
}
date_parameters.years = *maybe_year;
date_string.remove_prefix(4);
@ -151,7 +151,7 @@ std::pair<DateParameters, bool> ParseDateParameters(std::string_view date_string
auto maybe_month = ParseNumber<int64_t>(date_string, 2);
if (!maybe_month) {
throw utils::BasicException("Invalid month in the string. {}", kSupportedDateFormatsHelpMessage);
throw temporal::InvalidArgumentException("Invalid month in the string. {}", kSupportedDateFormatsHelpMessage);
}
date_parameters.months = *maybe_month;
date_string.remove_prefix(2);
@ -159,21 +159,21 @@ std::pair<DateParameters, bool> ParseDateParameters(std::string_view date_string
if (!date_string.empty()) {
if (date_string.front() == '-') {
if (!is_extended_format) {
throw utils::BasicException("Invalid format for the date. {}", kSupportedDateFormatsHelpMessage);
throw temporal::InvalidArgumentException("Invalid format for the date. {}", kSupportedDateFormatsHelpMessage);
}
date_string.remove_prefix(1);
}
auto maybe_day = ParseNumber<int64_t>(date_string, 2);
if (!maybe_day) {
throw utils::BasicException("Invalid month in the string. {}", kSupportedDateFormatsHelpMessage);
throw temporal::InvalidArgumentException("Invalid month in the string. {}", kSupportedDateFormatsHelpMessage);
}
date_parameters.days = *maybe_day;
date_string.remove_prefix(2);
}
if (!date_string.empty()) {
throw utils::BasicException("Invalid format for the date. {}", kSupportedDateFormatsHelpMessage);
throw temporal::InvalidArgumentException("Invalid format for the date. {}", kSupportedDateFormatsHelpMessage);
}
return {date_parameters, is_extended_format};
@ -242,7 +242,7 @@ std::pair<LocalTimeParameters, bool> ParseLocalTimeParameters(std::string_view l
}
if (*using_colon ^ has_colon) {
throw utils::BasicException(
throw temporal::InvalidArgumentException(
"Invalid format for the local time. A separator should be used consistently or not at all. {}",
kSupportedTimeFormatsHelpMessage);
}
@ -252,7 +252,8 @@ std::pair<LocalTimeParameters, bool> ParseLocalTimeParameters(std::string_view l
}
if (local_time_string.empty()) {
throw utils::BasicException("Invalid format for the local time. {}", kSupportedTimeFormatsHelpMessage);
throw temporal::InvalidArgumentException("Invalid format for the local time. {}",
kSupportedTimeFormatsHelpMessage);
}
};
@ -260,7 +261,7 @@ std::pair<LocalTimeParameters, bool> ParseLocalTimeParameters(std::string_view l
const auto maybe_hour = ParseNumber<int64_t>(local_time_string, 2);
if (!maybe_hour) {
throw utils::BasicException("Invalid hour in the string. {}", kSupportedTimeFormatsHelpMessage);
throw temporal::InvalidArgumentException("Invalid hour in the string. {}", kSupportedTimeFormatsHelpMessage);
}
local_time_parameters.hours = *maybe_hour;
local_time_string.remove_prefix(2);
@ -273,7 +274,7 @@ std::pair<LocalTimeParameters, bool> ParseLocalTimeParameters(std::string_view l
const auto maybe_minute = ParseNumber<int64_t>(local_time_string, 2);
if (!maybe_minute) {
throw utils::BasicException("Invalid minutes in the string. {}", kSupportedTimeFormatsHelpMessage);
throw temporal::InvalidArgumentException("Invalid minutes in the string. {}", kSupportedTimeFormatsHelpMessage);
}
local_time_parameters.minutes = *maybe_minute;
local_time_string.remove_prefix(2);
@ -286,7 +287,7 @@ std::pair<LocalTimeParameters, bool> ParseLocalTimeParameters(std::string_view l
const auto maybe_seconds = ParseNumber<int64_t>(local_time_string, 2);
if (!maybe_seconds) {
throw utils::BasicException("Invalid seconds in the string. {}", kSupportedTimeFormatsHelpMessage);
throw temporal::InvalidArgumentException("Invalid seconds in the string. {}", kSupportedTimeFormatsHelpMessage);
}
local_time_parameters.seconds = *maybe_seconds;
local_time_string.remove_prefix(2);
@ -296,13 +297,14 @@ std::pair<LocalTimeParameters, bool> ParseLocalTimeParameters(std::string_view l
}
if (local_time_string.front() != '.') {
throw utils::BasicException("Invalid format for local time. {}", kSupportedTimeFormatsHelpMessage);
throw temporal::InvalidArgumentException("Invalid format for local time. {}", kSupportedTimeFormatsHelpMessage);
}
local_time_string.remove_prefix(1);
const auto maybe_milliseconds = ParseNumber<int64_t>(local_time_string, 3);
if (!maybe_milliseconds) {
throw utils::BasicException("Invalid milliseconds in the string. {}", kSupportedTimeFormatsHelpMessage);
throw temporal::InvalidArgumentException("Invalid milliseconds in the string. {}",
kSupportedTimeFormatsHelpMessage);
}
local_time_parameters.milliseconds = *maybe_milliseconds;
local_time_string.remove_prefix(3);
@ -313,13 +315,14 @@ std::pair<LocalTimeParameters, bool> ParseLocalTimeParameters(std::string_view l
const auto maybe_microseconds = ParseNumber<int64_t>(local_time_string, 3);
if (!maybe_microseconds) {
throw utils::BasicException("Invalid microseconds in the string. {}", kSupportedTimeFormatsHelpMessage);
throw temporal::InvalidArgumentException("Invalid microseconds in the string. {}",
kSupportedTimeFormatsHelpMessage);
}
local_time_parameters.microseconds = *maybe_microseconds;
local_time_string.remove_prefix(3);
if (!local_time_string.empty()) {
throw utils::BasicException("Extra characters present at the end of the string.");
throw temporal::InvalidArgumentException("Extra characters present at the end of the string.");
}
return {local_time_parameters, *using_colon};
@ -328,12 +331,12 @@ std::pair<LocalTimeParameters, bool> ParseLocalTimeParameters(std::string_view l
LocalTime::LocalTime(const int64_t microseconds) {
auto chrono_microseconds = std::chrono::microseconds(microseconds);
if (chrono_microseconds.count() < 0) {
throw utils::BasicException("Negative LocalTime specified in microseconds");
throw temporal::InvalidArgumentException("Negative LocalTime specified in microseconds");
}
const auto parsed_hours = GetAndSubtractDuration<std::chrono::hours>(chrono_microseconds);
if (parsed_hours > 23) {
throw utils::BasicException("Invalid LocalTime specified in microseconds");
throw temporal::InvalidArgumentException("Invalid LocalTime specified in microseconds");
}
hours = parsed_hours;
@ -345,24 +348,24 @@ LocalTime::LocalTime(const int64_t microseconds) {
LocalTime::LocalTime(const LocalTimeParameters &local_time_parameters) {
if (!IsInBounds(0, 23, local_time_parameters.hours)) {
throw utils::BasicException("Creating a LocalTime with invalid hour parameter.");
throw temporal::InvalidArgumentException("Creating a LocalTime with invalid hour parameter.");
}
if (!IsInBounds(0, 59, local_time_parameters.minutes)) {
throw utils::BasicException("Creating a LocalTime with invalid minutes parameter.");
throw temporal::InvalidArgumentException("Creating a LocalTime with invalid minutes parameter.");
}
// ISO 8601 supports leap seconds, but we ignore it for now to simplify the implementation
if (!IsInBounds(0, 59, local_time_parameters.seconds)) {
throw utils::BasicException("Creating a LocalTime with invalid seconds parameter.");
throw temporal::InvalidArgumentException("Creating a LocalTime with invalid seconds parameter.");
}
if (!IsInBounds(0, 999, local_time_parameters.milliseconds)) {
throw utils::BasicException("Creating a LocalTime with invalid milliseconds parameter.");
throw temporal::InvalidArgumentException("Creating a LocalTime with invalid milliseconds parameter.");
}
if (!IsInBounds(0, 999, local_time_parameters.microseconds)) {
throw utils::BasicException("Creating a LocalTime with invalid microseconds parameter.");
throw temporal::InvalidArgumentException("Creating a LocalTime with invalid microseconds parameter.");
}
hours = local_time_parameters.hours;
@ -433,7 +436,8 @@ or both parts should be written in their basic forms without the separators.)hel
std::pair<DateParameters, LocalTimeParameters> ParseLocalDateTimeParameters(std::string_view string) {
auto t_position = string.find('T');
if (t_position == std::string_view::npos) {
throw utils::BasicException("Invalid LocalDateTime format. {}", kSupportedLocalDateTimeFormatsHelpMessage);
throw temporal::InvalidArgumentException("Invalid LocalDateTime format. {}",
kSupportedLocalDateTimeFormatsHelpMessage);
}
try {
@ -444,20 +448,22 @@ std::pair<DateParameters, LocalTimeParameters> ParseLocalDateTimeParameters(std:
// which denotes the basic format. The opposite case also aplies.
auto local_time_substring = string.substr(t_position + 1);
if (local_time_substring.empty()) {
throw utils::BasicException("Invalid LocalDateTime format. {}", kSupportedLocalDateTimeFormatsHelpMessage);
throw temporal::InvalidArgumentException("Invalid LocalDateTime format. {}",
kSupportedLocalDateTimeFormatsHelpMessage);
}
auto [local_time_parameters, extended_time_format] = ParseLocalTimeParameters(local_time_substring);
if (extended_date_format ^ extended_time_format) {
throw utils::BasicException(
throw temporal::InvalidArgumentException(
"Invalid LocalDateTime format. Both date and time should be in the basic or extended format. {}",
kSupportedLocalDateTimeFormatsHelpMessage);
}
return {date_parameters, local_time_parameters};
} catch (const utils::BasicException &e) {
throw utils::BasicException("Invalid LocalDateTime format. {}", kSupportedLocalDateTimeFormatsHelpMessage);
} catch (const temporal::InvalidArgumentException &e) {
throw temporal::InvalidArgumentException("Invalid LocalDateTime format. {}",
kSupportedLocalDateTimeFormatsHelpMessage);
}
}
@ -630,7 +636,7 @@ DurationParameters ParseDurationParameters(std::string_view string) {
// The string needs to start with P followed by one of the two options:
// - string in a duration specific format
if (string.empty() || string.front() != 'P') {
throw utils::BasicException("Duration string is empty.");
throw temporal::InvalidArgumentException("Duration string is empty.");
}
if (auto maybe_duration_parameters = TryParseDurationString(string); maybe_duration_parameters) {
@ -705,7 +711,7 @@ int64_t Duration::SubSecondsAsNanoseconds() const {
Duration Duration::operator-() const {
if (microseconds == std::numeric_limits<decltype(microseconds)>::min()) [[unlikely]] {
throw utils::BasicException("Duration arithmetic overflows");
throw temporal::InvalidArgumentException("Duration arithmetic overflows");
}
Duration result{-microseconds};
return result;

View File

@ -40,6 +40,12 @@ bool Underflows(const TType &lhs, const TType &rhs) {
return false;
}
namespace temporal {
struct InvalidArgumentException : public utils::BasicException {
using utils::BasicException::BasicException;
};
} // namespace temporal
struct DurationParameters {
double days{0};
double hours{0};