diff --git a/include/_mgp.hpp b/include/_mgp.hpp
index e04dea129..39cbedb4e 100644
--- a/include/_mgp.hpp
+++ b/include/_mgp.hpp
@@ -22,7 +22,7 @@
 namespace mgp {
 
 namespace {
-void MgExceptionHandle(mgp_error result_code) {
+inline void MgExceptionHandle(mgp_error result_code) {
   switch (result_code) {
     case mgp_error::MGP_ERROR_UNKNOWN_ERROR:
       throw mg_exception::UnknownException();
@@ -62,7 +62,7 @@ TResult MgInvoke(TFunc func, TArgs... args) {
 }
 
 template <typename TFunc, typename... TArgs>
-void MgInvokeVoid(TFunc func, TArgs... args) {
+inline void MgInvokeVoid(TFunc func, TArgs... args) {
   auto result_code = func(args...);
   MgExceptionHandle(result_code);
 }
@@ -72,211 +72,221 @@ void MgInvokeVoid(TFunc func, TArgs... args) {
 
 // Make value
 
-mgp_value *value_make_null(mgp_memory *memory) { return MgInvoke<mgp_value *>(mgp_value_make_null, memory); }
+inline mgp_value *value_make_null(mgp_memory *memory) { return MgInvoke<mgp_value *>(mgp_value_make_null, memory); }
 
-mgp_value *value_make_bool(int val, mgp_memory *memory) {
+inline mgp_value *value_make_bool(int val, mgp_memory *memory) {
   return MgInvoke<mgp_value *>(mgp_value_make_bool, val, memory);
 }
 
-mgp_value *value_make_int(int64_t val, mgp_memory *memory) {
+inline mgp_value *value_make_int(int64_t val, mgp_memory *memory) {
   return MgInvoke<mgp_value *>(mgp_value_make_int, val, memory);
 }
 
-mgp_value *value_make_double(double val, mgp_memory *memory) {
+inline mgp_value *value_make_double(double val, mgp_memory *memory) {
   return MgInvoke<mgp_value *>(mgp_value_make_double, val, memory);
 }
 
-mgp_value *value_make_string(const char *val, mgp_memory *memory) {
+inline mgp_value *value_make_string(const char *val, mgp_memory *memory) {
   return MgInvoke<mgp_value *>(mgp_value_make_string, val, memory);
 }
 
-mgp_value *value_make_list(mgp_list *val) { return MgInvoke<mgp_value *>(mgp_value_make_list, val); }
+inline mgp_value *value_make_list(mgp_list *val) { return MgInvoke<mgp_value *>(mgp_value_make_list, val); }
 
-mgp_value *value_make_map(mgp_map *val) { return MgInvoke<mgp_value *>(mgp_value_make_map, val); }
+inline mgp_value *value_make_map(mgp_map *val) { return MgInvoke<mgp_value *>(mgp_value_make_map, val); }
 
-mgp_value *value_make_vertex(mgp_vertex *val) { return MgInvoke<mgp_value *>(mgp_value_make_vertex, val); }
+inline mgp_value *value_make_vertex(mgp_vertex *val) { return MgInvoke<mgp_value *>(mgp_value_make_vertex, val); }
 
-mgp_value *value_make_edge(mgp_edge *val) { return MgInvoke<mgp_value *>(mgp_value_make_edge, val); }
+inline mgp_value *value_make_edge(mgp_edge *val) { return MgInvoke<mgp_value *>(mgp_value_make_edge, val); }
 
-mgp_value *value_make_path(mgp_path *val) { return MgInvoke<mgp_value *>(mgp_value_make_path, val); }
+inline mgp_value *value_make_path(mgp_path *val) { return MgInvoke<mgp_value *>(mgp_value_make_path, val); }
 
-mgp_value *value_make_date(mgp_date *val) { return MgInvoke<mgp_value *>(mgp_value_make_date, val); }
+inline mgp_value *value_make_date(mgp_date *val) { return MgInvoke<mgp_value *>(mgp_value_make_date, val); }
 
-mgp_value *value_make_local_time(mgp_local_time *val) { return MgInvoke<mgp_value *>(mgp_value_make_local_time, val); }
+inline mgp_value *value_make_local_time(mgp_local_time *val) {
+  return MgInvoke<mgp_value *>(mgp_value_make_local_time, val);
+}
 
-mgp_value *value_make_local_date_time(mgp_local_date_time *val) {
+inline mgp_value *value_make_local_date_time(mgp_local_date_time *val) {
   return MgInvoke<mgp_value *>(mgp_value_make_local_date_time, val);
 }
 
-mgp_value *value_make_duration(mgp_duration *val) { return MgInvoke<mgp_value *>(mgp_value_make_duration, val); }
+inline mgp_value *value_make_duration(mgp_duration *val) { return MgInvoke<mgp_value *>(mgp_value_make_duration, val); }
 
 // Copy value
 
 // TODO: implement within MGP API
 // with primitive types ({bool, int, double, string}), create a new identical value
 // otherwise call mgp_##TYPE_copy and convert tpye
-mgp_value *value_copy(mgp_value *val, mgp_memory *memory) { return MgInvoke<mgp_value *>(mgp_value_copy, val, memory); }
+inline mgp_value *value_copy(mgp_value *val, mgp_memory *memory) {
+  return MgInvoke<mgp_value *>(mgp_value_copy, val, memory);
+}
 
 // Destroy value
 
-void value_destroy(mgp_value *val) { mgp_value_destroy(val); }
+inline void value_destroy(mgp_value *val) { mgp_value_destroy(val); }
 
 // Get value of type
 
-mgp_value_type value_get_type(mgp_value *val) { return MgInvoke<mgp_value_type>(mgp_value_get_type, val); }
+inline mgp_value_type value_get_type(mgp_value *val) { return MgInvoke<mgp_value_type>(mgp_value_get_type, val); }
 
-bool value_get_bool(mgp_value *val) { return MgInvoke<int>(mgp_value_get_bool, val); }
+inline bool value_get_bool(mgp_value *val) { return MgInvoke<int>(mgp_value_get_bool, val); }
 
-int64_t value_get_int(mgp_value *val) { return MgInvoke<int64_t>(mgp_value_get_int, val); }
+inline int64_t value_get_int(mgp_value *val) { return MgInvoke<int64_t>(mgp_value_get_int, val); }
 
-double value_get_double(mgp_value *val) { return MgInvoke<double>(mgp_value_get_double, val); }
+inline double value_get_double(mgp_value *val) { return MgInvoke<double>(mgp_value_get_double, val); }
 
-const char *value_get_string(mgp_value *val) { return MgInvoke<const char *>(mgp_value_get_string, val); }
+inline const char *value_get_string(mgp_value *val) { return MgInvoke<const char *>(mgp_value_get_string, val); }
 
-mgp_list *value_get_list(mgp_value *val) { return MgInvoke<mgp_list *>(mgp_value_get_list, val); }
+inline mgp_list *value_get_list(mgp_value *val) { return MgInvoke<mgp_list *>(mgp_value_get_list, val); }
 
-mgp_map *value_get_map(mgp_value *val) { return MgInvoke<mgp_map *>(mgp_value_get_map, val); }
+inline mgp_map *value_get_map(mgp_value *val) { return MgInvoke<mgp_map *>(mgp_value_get_map, val); }
 
-mgp_vertex *value_get_vertex(mgp_value *val) { return MgInvoke<mgp_vertex *>(mgp_value_get_vertex, val); }
+inline mgp_vertex *value_get_vertex(mgp_value *val) { return MgInvoke<mgp_vertex *>(mgp_value_get_vertex, val); }
 
-mgp_edge *value_get_edge(mgp_value *val) { return MgInvoke<mgp_edge *>(mgp_value_get_edge, val); }
+inline mgp_edge *value_get_edge(mgp_value *val) { return MgInvoke<mgp_edge *>(mgp_value_get_edge, val); }
 
-mgp_path *value_get_path(mgp_value *val) { return MgInvoke<mgp_path *>(mgp_value_get_path, val); }
+inline mgp_path *value_get_path(mgp_value *val) { return MgInvoke<mgp_path *>(mgp_value_get_path, val); }
 
-mgp_date *value_get_date(mgp_value *val) { return MgInvoke<mgp_date *>(mgp_value_get_date, val); }
+inline mgp_date *value_get_date(mgp_value *val) { return MgInvoke<mgp_date *>(mgp_value_get_date, val); }
 
-mgp_local_time *value_get_local_time(mgp_value *val) {
+inline mgp_local_time *value_get_local_time(mgp_value *val) {
   return MgInvoke<mgp_local_time *>(mgp_value_get_local_time, val);
 }
 
-mgp_local_date_time *value_get_local_date_time(mgp_value *val) {
+inline mgp_local_date_time *value_get_local_date_time(mgp_value *val) {
   return MgInvoke<mgp_local_date_time *>(mgp_value_get_local_date_time, val);
 }
 
-mgp_duration *value_get_duration(mgp_value *val) { return MgInvoke<mgp_duration *>(mgp_value_get_duration, val); }
+inline mgp_duration *value_get_duration(mgp_value *val) {
+  return MgInvoke<mgp_duration *>(mgp_value_get_duration, val);
+}
 
 // Check type of value
 
-bool value_is_null(mgp_value *val) { return MgInvoke<int>(mgp_value_is_null, val); }
+inline bool value_is_null(mgp_value *val) { return MgInvoke<int>(mgp_value_is_null, val); }
 
-bool value_is_bool(mgp_value *val) { return MgInvoke<int>(mgp_value_is_bool, val); }
+inline bool value_is_bool(mgp_value *val) { return MgInvoke<int>(mgp_value_is_bool, val); }
 
-bool value_is_int(mgp_value *val) { return MgInvoke<int>(mgp_value_is_int, val); }
+inline bool value_is_int(mgp_value *val) { return MgInvoke<int>(mgp_value_is_int, val); }
 
-bool value_is_double(mgp_value *val) { return MgInvoke<int>(mgp_value_is_double, val); }
+inline bool value_is_double(mgp_value *val) { return MgInvoke<int>(mgp_value_is_double, val); }
 
-bool value_is_string(mgp_value *val) { return MgInvoke<int>(mgp_value_is_string, val); }
+inline bool value_is_string(mgp_value *val) { return MgInvoke<int>(mgp_value_is_string, val); }
 
-bool value_is_list(mgp_value *val) { return MgInvoke<int>(mgp_value_is_list, val); }
+inline bool value_is_list(mgp_value *val) { return MgInvoke<int>(mgp_value_is_list, val); }
 
-bool value_is_map(mgp_value *val) { return MgInvoke<int>(mgp_value_is_map, val); }
+inline bool value_is_map(mgp_value *val) { return MgInvoke<int>(mgp_value_is_map, val); }
 
-bool value_is_vertex(mgp_value *val) { return MgInvoke<int>(mgp_value_is_vertex, val); }
+inline bool value_is_vertex(mgp_value *val) { return MgInvoke<int>(mgp_value_is_vertex, val); }
 
-bool value_is_edge(mgp_value *val) { return MgInvoke<int>(mgp_value_is_edge, val); }
+inline bool value_is_edge(mgp_value *val) { return MgInvoke<int>(mgp_value_is_edge, val); }
 
-bool value_is_path(mgp_value *val) { return MgInvoke<int>(mgp_value_is_path, val); }
+inline bool value_is_path(mgp_value *val) { return MgInvoke<int>(mgp_value_is_path, val); }
 
-bool value_is_date(mgp_value *val) { return MgInvoke<int>(mgp_value_is_date, val); }
+inline bool value_is_date(mgp_value *val) { return MgInvoke<int>(mgp_value_is_date, val); }
 
-bool value_is_local_time(mgp_value *val) { return MgInvoke<int>(mgp_value_is_local_time, val); }
+inline bool value_is_local_time(mgp_value *val) { return MgInvoke<int>(mgp_value_is_local_time, val); }
 
-bool value_is_local_date_time(mgp_value *val) { return MgInvoke<int>(mgp_value_is_local_date_time, val); }
+inline bool value_is_local_date_time(mgp_value *val) { return MgInvoke<int>(mgp_value_is_local_date_time, val); }
 
-bool value_is_duration(mgp_value *val) { return MgInvoke<int>(mgp_value_is_duration, val); }
+inline bool value_is_duration(mgp_value *val) { return MgInvoke<int>(mgp_value_is_duration, val); }
 
 // Get type
 
-mgp_type *type_any() { return MgInvoke<mgp_type *>(mgp_type_any); }
+inline mgp_type *type_any() { return MgInvoke<mgp_type *>(mgp_type_any); }
 
-mgp_type *type_bool() { return MgInvoke<mgp_type *>(mgp_type_bool); }
+inline mgp_type *type_bool() { return MgInvoke<mgp_type *>(mgp_type_bool); }
 
-mgp_type *type_string() { return MgInvoke<mgp_type *>(mgp_type_string); }
+inline mgp_type *type_string() { return MgInvoke<mgp_type *>(mgp_type_string); }
 
-mgp_type *type_int() { return MgInvoke<mgp_type *>(mgp_type_int); }
+inline mgp_type *type_int() { return MgInvoke<mgp_type *>(mgp_type_int); }
 
-mgp_type *type_float() { return MgInvoke<mgp_type *>(mgp_type_float); }
+inline mgp_type *type_float() { return MgInvoke<mgp_type *>(mgp_type_float); }
 
-mgp_type *type_number() { return MgInvoke<mgp_type *>(mgp_type_number); }
+inline mgp_type *type_number() { return MgInvoke<mgp_type *>(mgp_type_number); }
 
-mgp_type *type_list(mgp_type *element_type) { return MgInvoke<mgp_type *>(mgp_type_list, element_type); }
+inline mgp_type *type_list(mgp_type *element_type) { return MgInvoke<mgp_type *>(mgp_type_list, element_type); }
 
-mgp_type *type_map() { return MgInvoke<mgp_type *>(mgp_type_map); }
+inline mgp_type *type_map() { return MgInvoke<mgp_type *>(mgp_type_map); }
 
-mgp_type *type_node() { return MgInvoke<mgp_type *>(mgp_type_node); }
+inline mgp_type *type_node() { return MgInvoke<mgp_type *>(mgp_type_node); }
 
-mgp_type *type_relationship() { return MgInvoke<mgp_type *>(mgp_type_relationship); }
+inline mgp_type *type_relationship() { return MgInvoke<mgp_type *>(mgp_type_relationship); }
 
-mgp_type *type_path() { return MgInvoke<mgp_type *>(mgp_type_path); }
+inline mgp_type *type_path() { return MgInvoke<mgp_type *>(mgp_type_path); }
 
-mgp_type *type_date() { return MgInvoke<mgp_type *>(mgp_type_date); }
+inline mgp_type *type_date() { return MgInvoke<mgp_type *>(mgp_type_date); }
 
-mgp_type *type_local_time() { return MgInvoke<mgp_type *>(mgp_type_local_time); }
+inline mgp_type *type_local_time() { return MgInvoke<mgp_type *>(mgp_type_local_time); }
 
-mgp_type *type_local_date_time() { return MgInvoke<mgp_type *>(mgp_type_local_date_time); }
+inline mgp_type *type_local_date_time() { return MgInvoke<mgp_type *>(mgp_type_local_date_time); }
 
-mgp_type *type_duration() { return MgInvoke<mgp_type *>(mgp_type_duration); }
+inline mgp_type *type_duration() { return MgInvoke<mgp_type *>(mgp_type_duration); }
 
-mgp_type *type_nullable(mgp_type *type) { return MgInvoke<mgp_type *>(mgp_type_nullable, type); }
+inline mgp_type *type_nullable(mgp_type *type) { return MgInvoke<mgp_type *>(mgp_type_nullable, type); }
 
 // mgp_graph
 
-bool graph_is_mutable(mgp_graph *graph) { return MgInvoke<int>(mgp_graph_is_mutable, graph); }
+inline bool graph_is_mutable(mgp_graph *graph) { return MgInvoke<int>(mgp_graph_is_mutable, graph); }
 
-mgp_vertex *graph_create_vertex(mgp_graph *graph, mgp_memory *memory) {
+inline mgp_vertex *graph_create_vertex(mgp_graph *graph, mgp_memory *memory) {
   return MgInvoke<mgp_vertex *>(mgp_graph_create_vertex, graph, memory);
 }
 
-void graph_delete_vertex(mgp_graph *graph, mgp_vertex *vertex) { MgInvokeVoid(mgp_graph_delete_vertex, graph, vertex); }
+inline void graph_delete_vertex(mgp_graph *graph, mgp_vertex *vertex) {
+  MgInvokeVoid(mgp_graph_delete_vertex, graph, vertex);
+}
 
-void graph_detach_delete_vertex(mgp_graph *graph, mgp_vertex *vertex) {
+inline void graph_detach_delete_vertex(mgp_graph *graph, mgp_vertex *vertex) {
   MgInvokeVoid(mgp_graph_detach_delete_vertex, graph, vertex);
 }
 
-mgp_edge *graph_create_edge(mgp_graph *graph, mgp_vertex *from, mgp_vertex *to, mgp_edge_type type,
-                            mgp_memory *memory) {
+inline mgp_edge *graph_create_edge(mgp_graph *graph, mgp_vertex *from, mgp_vertex *to, mgp_edge_type type,
+                                   mgp_memory *memory) {
   return MgInvoke<mgp_edge *>(mgp_graph_create_edge, graph, from, to, type, memory);
 }
 
-void graph_delete_edge(mgp_graph *graph, mgp_edge *edge) { MgInvokeVoid(mgp_graph_delete_edge, graph, edge); }
+inline void graph_delete_edge(mgp_graph *graph, mgp_edge *edge) { MgInvokeVoid(mgp_graph_delete_edge, graph, edge); }
 
-mgp_vertex *graph_get_vertex_by_id(mgp_graph *g, mgp_vertex_id id, mgp_memory *memory) {
+inline mgp_vertex *graph_get_vertex_by_id(mgp_graph *g, mgp_vertex_id id, mgp_memory *memory) {
   return MgInvoke<mgp_vertex *>(mgp_graph_get_vertex_by_id, g, id, memory);
 }
 
-mgp_vertices_iterator *graph_iter_vertices(mgp_graph *g, mgp_memory *memory) {
+inline mgp_vertices_iterator *graph_iter_vertices(mgp_graph *g, mgp_memory *memory) {
   return MgInvoke<mgp_vertices_iterator *>(mgp_graph_iter_vertices, g, memory);
 }
 
 // mgp_vertices_iterator
 
-void vertices_iterator_destroy(mgp_vertices_iterator *it) { mgp_vertices_iterator_destroy(it); }
+inline void vertices_iterator_destroy(mgp_vertices_iterator *it) { mgp_vertices_iterator_destroy(it); }
 
-mgp_vertex *vertices_iterator_get(mgp_vertices_iterator *it) {
+inline mgp_vertex *vertices_iterator_get(mgp_vertices_iterator *it) {
   return MgInvoke<mgp_vertex *>(mgp_vertices_iterator_get, it);
 }
 
-mgp_vertex *vertices_iterator_next(mgp_vertices_iterator *it) {
+inline mgp_vertex *vertices_iterator_next(mgp_vertices_iterator *it) {
   return MgInvoke<mgp_vertex *>(mgp_vertices_iterator_next, it);
 }
 
 // mgp_edges_iterator
 
-void edges_iterator_destroy(mgp_edges_iterator *it) { mgp_edges_iterator_destroy(it); }
+inline void edges_iterator_destroy(mgp_edges_iterator *it) { mgp_edges_iterator_destroy(it); }
 
-mgp_edge *edges_iterator_get(mgp_edges_iterator *it) { return MgInvoke<mgp_edge *>(mgp_edges_iterator_get, it); }
+inline mgp_edge *edges_iterator_get(mgp_edges_iterator *it) { return MgInvoke<mgp_edge *>(mgp_edges_iterator_get, it); }
 
-mgp_edge *edges_iterator_next(mgp_edges_iterator *it) { return MgInvoke<mgp_edge *>(mgp_edges_iterator_next, it); }
+inline mgp_edge *edges_iterator_next(mgp_edges_iterator *it) {
+  return MgInvoke<mgp_edge *>(mgp_edges_iterator_next, it);
+}
 
 // mgp_properties_iterator
 
-void properties_iterator_destroy(mgp_properties_iterator *it) { mgp_properties_iterator_destroy(it); }
+inline void properties_iterator_destroy(mgp_properties_iterator *it) { mgp_properties_iterator_destroy(it); }
 
-mgp_property *properties_iterator_get(mgp_properties_iterator *it) {
+inline mgp_property *properties_iterator_get(mgp_properties_iterator *it) {
   return MgInvoke<mgp_property *>(mgp_properties_iterator_get, it);
 }
 
-mgp_property *properties_iterator_next(mgp_properties_iterator *it) {
+inline mgp_property *properties_iterator_next(mgp_properties_iterator *it) {
   return MgInvoke<mgp_property *>(mgp_properties_iterator_next, it);
 }
 
@@ -284,409 +294,432 @@ mgp_property *properties_iterator_next(mgp_properties_iterator *it) {
 
 // mgp_list
 
-mgp_list *list_make_empty(size_t capacity, mgp_memory *memory) {
+inline mgp_list *list_make_empty(size_t capacity, mgp_memory *memory) {
   return MgInvoke<mgp_list *>(mgp_list_make_empty, capacity, memory);
 }
 
-mgp_list *list_copy(mgp_list *list, mgp_memory *memory) { return MgInvoke<mgp_list *>(mgp_list_copy, list, memory); }
+inline mgp_list *list_copy(mgp_list *list, mgp_memory *memory) {
+  return MgInvoke<mgp_list *>(mgp_list_copy, list, memory);
+}
 
-void list_destroy(mgp_list *list) { mgp_list_destroy(list); }
+inline void list_destroy(mgp_list *list) { mgp_list_destroy(list); }
 
-void list_append(mgp_list *list, mgp_value *val) { MgInvokeVoid(mgp_list_append, list, val); }
+inline void list_append(mgp_list *list, mgp_value *val) { MgInvokeVoid(mgp_list_append, list, val); }
 
-void list_append_extend(mgp_list *list, mgp_value *val) { MgInvokeVoid(mgp_list_append_extend, list, val); }
+inline void list_append_extend(mgp_list *list, mgp_value *val) { MgInvokeVoid(mgp_list_append_extend, list, val); }
 
-size_t list_size(mgp_list *list) { return MgInvoke<size_t>(mgp_list_size, list); }
+inline size_t list_size(mgp_list *list) { return MgInvoke<size_t>(mgp_list_size, list); }
 
-size_t list_capacity(mgp_list *list) { return MgInvoke<size_t>(mgp_list_capacity, list); }
+inline size_t list_capacity(mgp_list *list) { return MgInvoke<size_t>(mgp_list_capacity, list); }
 
-mgp_value *list_at(mgp_list *list, size_t index) { return MgInvoke<mgp_value *>(mgp_list_at, list, index); }
+inline mgp_value *list_at(mgp_list *list, size_t index) { return MgInvoke<mgp_value *>(mgp_list_at, list, index); }
 
 // mgp_map
 
-mgp_map *map_make_empty(mgp_memory *memory) { return MgInvoke<mgp_map *>(mgp_map_make_empty, memory); }
+inline mgp_map *map_make_empty(mgp_memory *memory) { return MgInvoke<mgp_map *>(mgp_map_make_empty, memory); }
 
-mgp_map *map_copy(mgp_map *map, mgp_memory *memory) { return MgInvoke<mgp_map *>(mgp_map_copy, map, memory); }
+inline mgp_map *map_copy(mgp_map *map, mgp_memory *memory) { return MgInvoke<mgp_map *>(mgp_map_copy, map, memory); }
 
-void map_destroy(mgp_map *map) { mgp_map_destroy(map); }
+inline void map_destroy(mgp_map *map) { mgp_map_destroy(map); }
 
-void map_insert(mgp_map *map, const char *key, mgp_value *value) { MgInvokeVoid(mgp_map_insert, map, key, value); }
+inline void map_insert(mgp_map *map, const char *key, mgp_value *value) {
+  MgInvokeVoid(mgp_map_insert, map, key, value);
+}
 
-size_t map_size(mgp_map *map) { return MgInvoke<size_t>(mgp_map_size, map); }
+inline size_t map_size(mgp_map *map) { return MgInvoke<size_t>(mgp_map_size, map); }
 
-mgp_value *map_at(mgp_map *map, const char *key) { return MgInvoke<mgp_value *>(mgp_map_at, map, key); }
+inline mgp_value *map_at(mgp_map *map, const char *key) { return MgInvoke<mgp_value *>(mgp_map_at, map, key); }
 
-const char *map_item_key(mgp_map_item *item) { return MgInvoke<const char *>(mgp_map_item_key, item); }
+inline const char *map_item_key(mgp_map_item *item) { return MgInvoke<const char *>(mgp_map_item_key, item); }
 
-mgp_value *map_item_value(mgp_map_item *item) { return MgInvoke<mgp_value *>(mgp_map_item_value, item); }
+inline mgp_value *map_item_value(mgp_map_item *item) { return MgInvoke<mgp_value *>(mgp_map_item_value, item); }
 
-mgp_map_items_iterator *map_iter_items(mgp_map *map, mgp_memory *memory) {
+inline mgp_map_items_iterator *map_iter_items(mgp_map *map, mgp_memory *memory) {
   return MgInvoke<mgp_map_items_iterator *>(mgp_map_iter_items, map, memory);
 }
 
-void map_items_iterator_destroy(mgp_map_items_iterator *it) { mgp_map_items_iterator_destroy(it); }
+inline void map_items_iterator_destroy(mgp_map_items_iterator *it) { mgp_map_items_iterator_destroy(it); }
 
-mgp_map_item *map_items_iterator_get(mgp_map_items_iterator *it) {
+inline mgp_map_item *map_items_iterator_get(mgp_map_items_iterator *it) {
   return MgInvoke<mgp_map_item *>(mgp_map_items_iterator_get, it);
 }
 
-mgp_map_item *map_items_iterator_next(mgp_map_items_iterator *it) {
+inline mgp_map_item *map_items_iterator_next(mgp_map_items_iterator *it) {
   return MgInvoke<mgp_map_item *>(mgp_map_items_iterator_next, it);
 }
 
 // mgp_vertex
 
-mgp_vertex_id vertex_get_id(mgp_vertex *v) { return MgInvoke<mgp_vertex_id>(mgp_vertex_get_id, v); }
+inline mgp_vertex_id vertex_get_id(mgp_vertex *v) { return MgInvoke<mgp_vertex_id>(mgp_vertex_get_id, v); }
 
-mgp_vertex *vertex_copy(mgp_vertex *v, mgp_memory *memory) {
+inline mgp_vertex *vertex_copy(mgp_vertex *v, mgp_memory *memory) {
   return MgInvoke<mgp_vertex *>(mgp_vertex_copy, v, memory);
 }
 
-void vertex_destroy(mgp_vertex *v) { mgp_vertex_destroy(v); }
+inline void vertex_destroy(mgp_vertex *v) { mgp_vertex_destroy(v); }
 
-bool vertex_equal(mgp_vertex *v1, mgp_vertex *v2) { return MgInvoke<int>(mgp_vertex_equal, v1, v2); }
+inline bool vertex_equal(mgp_vertex *v1, mgp_vertex *v2) { return MgInvoke<int>(mgp_vertex_equal, v1, v2); }
 
-size_t vertex_labels_count(mgp_vertex *v) { return MgInvoke<size_t>(mgp_vertex_labels_count, v); }
+inline size_t vertex_labels_count(mgp_vertex *v) { return MgInvoke<size_t>(mgp_vertex_labels_count, v); }
 
-mgp_label vertex_label_at(mgp_vertex *v, size_t index) { return MgInvoke<mgp_label>(mgp_vertex_label_at, v, index); }
+inline mgp_label vertex_label_at(mgp_vertex *v, size_t index) {
+  return MgInvoke<mgp_label>(mgp_vertex_label_at, v, index);
+}
 
-bool vertex_has_label(mgp_vertex *v, mgp_label label) { return MgInvoke<int>(mgp_vertex_has_label, v, label); }
+inline bool vertex_has_label(mgp_vertex *v, mgp_label label) { return MgInvoke<int>(mgp_vertex_has_label, v, label); }
 
-bool vertex_has_label_named(mgp_vertex *v, const char *label_name) {
+inline bool vertex_has_label_named(mgp_vertex *v, const char *label_name) {
   return MgInvoke<int>(mgp_vertex_has_label_named, v, label_name);
 }
 
-void vertex_add_label(mgp_vertex *vertex, mgp_label label) { MgInvokeVoid(mgp_vertex_add_label, vertex, label); }
+inline void vertex_add_label(mgp_vertex *vertex, mgp_label label) { MgInvokeVoid(mgp_vertex_add_label, vertex, label); }
 
-mgp_value *vertex_get_property(mgp_vertex *v, const char *property_name, mgp_memory *memory) {
+inline mgp_value *vertex_get_property(mgp_vertex *v, const char *property_name, mgp_memory *memory) {
   return MgInvoke<mgp_value *>(mgp_vertex_get_property, v, property_name, memory);
 }
 
-mgp_properties_iterator *vertex_iter_properties(mgp_vertex *v, mgp_memory *memory) {
+inline mgp_properties_iterator *vertex_iter_properties(mgp_vertex *v, mgp_memory *memory) {
   return MgInvoke<mgp_properties_iterator *>(mgp_vertex_iter_properties, v, memory);
 }
 
-mgp_edges_iterator *vertex_iter_in_edges(mgp_vertex *v, mgp_memory *memory) {
+inline mgp_edges_iterator *vertex_iter_in_edges(mgp_vertex *v, mgp_memory *memory) {
   return MgInvoke<mgp_edges_iterator *>(mgp_vertex_iter_in_edges, v, memory);
 }
 
-mgp_edges_iterator *vertex_iter_out_edges(mgp_vertex *v, mgp_memory *memory) {
+inline mgp_edges_iterator *vertex_iter_out_edges(mgp_vertex *v, mgp_memory *memory) {
   return MgInvoke<mgp_edges_iterator *>(mgp_vertex_iter_out_edges, v, memory);
 }
 
 // mgp_edge
 
-mgp_edge_id edge_get_id(mgp_edge *e) { return MgInvoke<mgp_edge_id>(mgp_edge_get_id, e); }
+inline mgp_edge_id edge_get_id(mgp_edge *e) { return MgInvoke<mgp_edge_id>(mgp_edge_get_id, e); }
 
-mgp_edge *edge_copy(mgp_edge *e, mgp_memory *memory) { return MgInvoke<mgp_edge *>(mgp_edge_copy, e, memory); }
+inline mgp_edge *edge_copy(mgp_edge *e, mgp_memory *memory) { return MgInvoke<mgp_edge *>(mgp_edge_copy, e, memory); }
 
-void edge_destroy(mgp_edge *e) { mgp_edge_destroy(e); }
+inline void edge_destroy(mgp_edge *e) { mgp_edge_destroy(e); }
 
-bool edge_equal(mgp_edge *e1, mgp_edge *e2) { return MgInvoke<int>(mgp_edge_equal, e1, e2); }
+inline bool edge_equal(mgp_edge *e1, mgp_edge *e2) { return MgInvoke<int>(mgp_edge_equal, e1, e2); }
 
-mgp_edge_type edge_get_type(mgp_edge *e) { return MgInvoke<mgp_edge_type>(mgp_edge_get_type, e); }
+inline mgp_edge_type edge_get_type(mgp_edge *e) { return MgInvoke<mgp_edge_type>(mgp_edge_get_type, e); }
 
-mgp_vertex *edge_get_from(mgp_edge *e) { return MgInvoke<mgp_vertex *>(mgp_edge_get_from, e); }
+inline mgp_vertex *edge_get_from(mgp_edge *e) { return MgInvoke<mgp_vertex *>(mgp_edge_get_from, e); }
 
-mgp_vertex *edge_get_to(mgp_edge *e) { return MgInvoke<mgp_vertex *>(mgp_edge_get_to, e); }
+inline mgp_vertex *edge_get_to(mgp_edge *e) { return MgInvoke<mgp_vertex *>(mgp_edge_get_to, e); }
 
-mgp_value *edge_get_property(mgp_edge *e, const char *property_name, mgp_memory *memory) {
+inline mgp_value *edge_get_property(mgp_edge *e, const char *property_name, mgp_memory *memory) {
   return MgInvoke<mgp_value *>(mgp_edge_get_property, e, property_name, memory);
 }
 
-mgp_properties_iterator *edge_iter_properties(mgp_edge *e, mgp_memory *memory) {
+inline mgp_properties_iterator *edge_iter_properties(mgp_edge *e, mgp_memory *memory) {
   return MgInvoke<mgp_properties_iterator *>(mgp_edge_iter_properties, e, memory);
 }
 
 // mgp_path
 
-mgp_path *path_make_with_start(mgp_vertex *vertex, mgp_memory *memory) {
+inline mgp_path *path_make_with_start(mgp_vertex *vertex, mgp_memory *memory) {
   return MgInvoke<mgp_path *>(mgp_path_make_with_start, vertex, memory);
 }
 
-mgp_path *path_copy(mgp_path *path, mgp_memory *memory) { return MgInvoke<mgp_path *>(mgp_path_copy, path, memory); }
+inline mgp_path *path_copy(mgp_path *path, mgp_memory *memory) {
+  return MgInvoke<mgp_path *>(mgp_path_copy, path, memory);
+}
 
-void path_destroy(mgp_path *path) { mgp_path_destroy(path); }
+inline void path_destroy(mgp_path *path) { mgp_path_destroy(path); }
 
-void path_expand(mgp_path *path, mgp_edge *edge) { MgInvokeVoid(mgp_path_expand, path, edge); }
+inline void path_expand(mgp_path *path, mgp_edge *edge) { MgInvokeVoid(mgp_path_expand, path, edge); }
 
-size_t path_size(mgp_path *path) { return MgInvoke<size_t>(mgp_path_size, path); }
+inline size_t path_size(mgp_path *path) { return MgInvoke<size_t>(mgp_path_size, path); }
 
-mgp_vertex *path_vertex_at(mgp_path *path, size_t index) {
+inline mgp_vertex *path_vertex_at(mgp_path *path, size_t index) {
   return MgInvoke<mgp_vertex *>(mgp_path_vertex_at, path, index);
 }
 
-mgp_edge *path_edge_at(mgp_path *path, size_t index) { return MgInvoke<mgp_edge *>(mgp_path_edge_at, path, index); }
+inline mgp_edge *path_edge_at(mgp_path *path, size_t index) {
+  return MgInvoke<mgp_edge *>(mgp_path_edge_at, path, index);
+}
 
-bool path_equal(mgp_path *p1, mgp_path *p2) { return MgInvoke<int>(mgp_path_equal, p1, p2); }
+inline bool path_equal(mgp_path *p1, mgp_path *p2) { return MgInvoke<int>(mgp_path_equal, p1, p2); }
 
 // Temporal type {mgp_date, mgp_local_time, mgp_local_date_time, mgp_duration} methods
 
 // mgp_date
 
-mgp_date *date_from_string(const char *string, mgp_memory *memory) {
+inline mgp_date *date_from_string(const char *string, mgp_memory *memory) {
   return MgInvoke<mgp_date *>(mgp_date_from_string, string, memory);
 }
 
-mgp_date *date_from_parameters(mgp_date_parameters *parameters, mgp_memory *memory) {
+inline mgp_date *date_from_parameters(mgp_date_parameters *parameters, mgp_memory *memory) {
   return MgInvoke<mgp_date *>(mgp_date_from_parameters, parameters, memory);
 }
 
-mgp_date *date_copy(mgp_date *date, mgp_memory *memory) { return MgInvoke<mgp_date *>(mgp_date_copy, date, memory); }
+inline mgp_date *date_copy(mgp_date *date, mgp_memory *memory) {
+  return MgInvoke<mgp_date *>(mgp_date_copy, date, memory);
+}
 
-void date_destroy(mgp_date *date) { mgp_date_destroy(date); }
+inline void date_destroy(mgp_date *date) { mgp_date_destroy(date); }
 
-bool date_equal(mgp_date *first, mgp_date *second) { return MgInvoke<int>(mgp_date_equal, first, second); }
+inline bool date_equal(mgp_date *first, mgp_date *second) { return MgInvoke<int>(mgp_date_equal, first, second); }
 
-int date_get_year(mgp_date *date) { return MgInvoke<int>(mgp_date_get_year, date); }
+inline int date_get_year(mgp_date *date) { return MgInvoke<int>(mgp_date_get_year, date); }
 
-int date_get_month(mgp_date *date) { return MgInvoke<int>(mgp_date_get_month, date); }
+inline int date_get_month(mgp_date *date) { return MgInvoke<int>(mgp_date_get_month, date); }
 
-int date_get_day(mgp_date *date) { return MgInvoke<int>(mgp_date_get_day, date); }
+inline int date_get_day(mgp_date *date) { return MgInvoke<int>(mgp_date_get_day, date); }
 
-int64_t date_timestamp(mgp_date *date) { return MgInvoke<int64_t>(mgp_date_timestamp, date); }
+inline int64_t date_timestamp(mgp_date *date) { return MgInvoke<int64_t>(mgp_date_timestamp, date); }
 
-mgp_date *date_now(mgp_memory *memory) { return MgInvoke<mgp_date *>(mgp_date_now, memory); }
+inline mgp_date *date_now(mgp_memory *memory) { return MgInvoke<mgp_date *>(mgp_date_now, memory); }
 
-mgp_date *date_add_duration(mgp_date *date, mgp_duration *dur, mgp_memory *memory) {
+inline mgp_date *date_add_duration(mgp_date *date, mgp_duration *dur, mgp_memory *memory) {
   return MgInvoke<mgp_date *>(mgp_date_add_duration, date, dur, memory);
 }
 
-mgp_date *date_sub_duration(mgp_date *date, mgp_duration *dur, mgp_memory *memory) {
+inline mgp_date *date_sub_duration(mgp_date *date, mgp_duration *dur, mgp_memory *memory) {
   return MgInvoke<mgp_date *>(mgp_date_sub_duration, date, dur, memory);
 }
 
-mgp_duration *date_diff(mgp_date *first, mgp_date *second, mgp_memory *memory) {
+inline mgp_duration *date_diff(mgp_date *first, mgp_date *second, mgp_memory *memory) {
   return MgInvoke<mgp_duration *>(mgp_date_diff, first, second, memory);
 }
 
 // mgp_local_time
 
-mgp_local_time *local_time_from_string(const char *string, mgp_memory *memory) {
+inline mgp_local_time *local_time_from_string(const char *string, mgp_memory *memory) {
   return MgInvoke<mgp_local_time *>(mgp_local_time_from_string, string, memory);
 }
 
-mgp_local_time *local_time_from_parameters(mgp_local_time_parameters *parameters, mgp_memory *memory) {
+inline mgp_local_time *local_time_from_parameters(mgp_local_time_parameters *parameters, mgp_memory *memory) {
   return MgInvoke<mgp_local_time *>(mgp_local_time_from_parameters, parameters, memory);
 }
 
-mgp_local_time *local_time_copy(mgp_local_time *local_time, mgp_memory *memory) {
+inline mgp_local_time *local_time_copy(mgp_local_time *local_time, mgp_memory *memory) {
   return MgInvoke<mgp_local_time *>(mgp_local_time_copy, local_time, memory);
 }
 
-void local_time_destroy(mgp_local_time *local_time) { mgp_local_time_destroy(local_time); }
+inline void local_time_destroy(mgp_local_time *local_time) { mgp_local_time_destroy(local_time); }
 
-bool local_time_equal(mgp_local_time *first, mgp_local_time *second) {
+inline bool local_time_equal(mgp_local_time *first, mgp_local_time *second) {
   return MgInvoke<int>(mgp_local_time_equal, first, second);
 }
 
-int local_time_get_hour(mgp_local_time *local_time) { return MgInvoke<int>(mgp_local_time_get_hour, local_time); }
+inline int local_time_get_hour(mgp_local_time *local_time) {
+  return MgInvoke<int>(mgp_local_time_get_hour, local_time);
+}
 
-int local_time_get_minute(mgp_local_time *local_time) { return MgInvoke<int>(mgp_local_time_get_minute, local_time); }
+inline int local_time_get_minute(mgp_local_time *local_time) {
+  return MgInvoke<int>(mgp_local_time_get_minute, local_time);
+}
 
-int local_time_get_second(mgp_local_time *local_time) { return MgInvoke<int>(mgp_local_time_get_second, local_time); }
+inline int local_time_get_second(mgp_local_time *local_time) {
+  return MgInvoke<int>(mgp_local_time_get_second, local_time);
+}
 
-int local_time_get_millisecond(mgp_local_time *local_time) {
+inline int local_time_get_millisecond(mgp_local_time *local_time) {
   return MgInvoke<int>(mgp_local_time_get_millisecond, local_time);
 }
 
-int local_time_get_microsecond(mgp_local_time *local_time) {
+inline int local_time_get_microsecond(mgp_local_time *local_time) {
   return MgInvoke<int>(mgp_local_time_get_microsecond, local_time);
 }
 
-int64_t local_time_timestamp(mgp_local_time *local_time) {
+inline int64_t local_time_timestamp(mgp_local_time *local_time) {
   return MgInvoke<int64_t>(mgp_local_time_timestamp, local_time);
 }
 
-mgp_local_time *local_time_now(mgp_memory *memory) { return MgInvoke<mgp_local_time *>(mgp_local_time_now, memory); }
+inline mgp_local_time *local_time_now(mgp_memory *memory) {
+  return MgInvoke<mgp_local_time *>(mgp_local_time_now, memory);
+}
 
-mgp_local_time *local_time_add_duration(mgp_local_time *local_time, mgp_duration *dur, mgp_memory *memory) {
+inline mgp_local_time *local_time_add_duration(mgp_local_time *local_time, mgp_duration *dur, mgp_memory *memory) {
   return MgInvoke<mgp_local_time *>(mgp_local_time_add_duration, local_time, dur, memory);
 }
 
-mgp_local_time *local_time_sub_duration(mgp_local_time *local_time, mgp_duration *dur, mgp_memory *memory) {
+inline mgp_local_time *local_time_sub_duration(mgp_local_time *local_time, mgp_duration *dur, mgp_memory *memory) {
   return MgInvoke<mgp_local_time *>(mgp_local_time_sub_duration, local_time, dur, memory);
 }
 
-mgp_duration *local_time_diff(mgp_local_time *first, mgp_local_time *second, mgp_memory *memory) {
+inline mgp_duration *local_time_diff(mgp_local_time *first, mgp_local_time *second, mgp_memory *memory) {
   return MgInvoke<mgp_duration *>(mgp_local_time_diff, first, second, memory);
 }
 
 // mgp_local_date_time
 
-mgp_local_date_time *local_date_time_from_string(const char *string, mgp_memory *memory) {
+inline mgp_local_date_time *local_date_time_from_string(const char *string, mgp_memory *memory) {
   return MgInvoke<mgp_local_date_time *>(mgp_local_date_time_from_string, string, memory);
 }
 
-mgp_local_date_time *local_date_time_from_parameters(mgp_local_date_time_parameters *parameters, mgp_memory *memory) {
+inline mgp_local_date_time *local_date_time_from_parameters(mgp_local_date_time_parameters *parameters,
+                                                            mgp_memory *memory) {
   return MgInvoke<mgp_local_date_time *>(mgp_local_date_time_from_parameters, parameters, memory);
 }
 
-mgp_local_date_time *local_date_time_copy(mgp_local_date_time *local_date_time, mgp_memory *memory) {
+inline mgp_local_date_time *local_date_time_copy(mgp_local_date_time *local_date_time, mgp_memory *memory) {
   return MgInvoke<mgp_local_date_time *>(mgp_local_date_time_copy, local_date_time, memory);
 }
 
-void local_date_time_destroy(mgp_local_date_time *local_date_time) { mgp_local_date_time_destroy(local_date_time); }
+inline void local_date_time_destroy(mgp_local_date_time *local_date_time) {
+  mgp_local_date_time_destroy(local_date_time);
+}
 
-bool local_date_time_equal(mgp_local_date_time *first, mgp_local_date_time *second) {
+inline bool local_date_time_equal(mgp_local_date_time *first, mgp_local_date_time *second) {
   return MgInvoke<int>(mgp_local_date_time_equal, first, second);
 }
 
-int local_date_time_get_year(mgp_local_date_time *local_date_time) {
+inline int local_date_time_get_year(mgp_local_date_time *local_date_time) {
   return MgInvoke<int>(mgp_local_date_time_get_year, local_date_time);
 }
 
-int local_date_time_get_month(mgp_local_date_time *local_date_time) {
+inline int local_date_time_get_month(mgp_local_date_time *local_date_time) {
   return MgInvoke<int>(mgp_local_date_time_get_month, local_date_time);
 }
 
-int local_date_time_get_day(mgp_local_date_time *local_date_time) {
+inline int local_date_time_get_day(mgp_local_date_time *local_date_time) {
   return MgInvoke<int>(mgp_local_date_time_get_day, local_date_time);
 }
 
-int local_date_time_get_hour(mgp_local_date_time *local_date_time) {
+inline int local_date_time_get_hour(mgp_local_date_time *local_date_time) {
   return MgInvoke<int>(mgp_local_date_time_get_hour, local_date_time);
 }
 
-int local_date_time_get_minute(mgp_local_date_time *local_date_time) {
+inline int local_date_time_get_minute(mgp_local_date_time *local_date_time) {
   return MgInvoke<int>(mgp_local_date_time_get_minute, local_date_time);
 }
 
-int local_date_time_get_second(mgp_local_date_time *local_date_time) {
+inline int local_date_time_get_second(mgp_local_date_time *local_date_time) {
   return MgInvoke<int>(mgp_local_date_time_get_second, local_date_time);
 }
 
-int local_date_time_get_millisecond(mgp_local_date_time *local_date_time) {
+inline int local_date_time_get_millisecond(mgp_local_date_time *local_date_time) {
   return MgInvoke<int>(mgp_local_date_time_get_millisecond, local_date_time);
 }
 
-int local_date_time_get_microsecond(mgp_local_date_time *local_date_time) {
+inline int local_date_time_get_microsecond(mgp_local_date_time *local_date_time) {
   return MgInvoke<int>(mgp_local_date_time_get_microsecond, local_date_time);
 }
 
-int64_t local_date_time_timestamp(mgp_local_date_time *local_date_time) {
+inline int64_t local_date_time_timestamp(mgp_local_date_time *local_date_time) {
   return MgInvoke<int64_t>(mgp_local_date_time_timestamp, local_date_time);
 }
 
-mgp_local_date_time *local_date_time_now(mgp_memory *memory) {
+inline mgp_local_date_time *local_date_time_now(mgp_memory *memory) {
   return MgInvoke<mgp_local_date_time *>(mgp_local_date_time_now, memory);
 }
 
-mgp_local_date_time *local_date_time_add_duration(mgp_local_date_time *local_date_time, mgp_duration *dur,
-                                                  mgp_memory *memory) {
+inline mgp_local_date_time *local_date_time_add_duration(mgp_local_date_time *local_date_time, mgp_duration *dur,
+                                                         mgp_memory *memory) {
   return MgInvoke<mgp_local_date_time *>(mgp_local_date_time_add_duration, local_date_time, dur, memory);
 }
 
-mgp_local_date_time *local_date_time_sub_duration(mgp_local_date_time *local_date_time, mgp_duration *dur,
-                                                  mgp_memory *memory) {
+inline mgp_local_date_time *local_date_time_sub_duration(mgp_local_date_time *local_date_time, mgp_duration *dur,
+                                                         mgp_memory *memory) {
   return MgInvoke<mgp_local_date_time *>(mgp_local_date_time_sub_duration, local_date_time, dur, memory);
 }
 
-mgp_duration *local_date_time_diff(mgp_local_date_time *first, mgp_local_date_time *second, mgp_memory *memory) {
+inline mgp_duration *local_date_time_diff(mgp_local_date_time *first, mgp_local_date_time *second, mgp_memory *memory) {
   return MgInvoke<mgp_duration *>(mgp_local_date_time_diff, first, second, memory);
 }
 
 // mgp_duration
 
-mgp_duration *duration_from_string(const char *string, mgp_memory *memory) {
+inline mgp_duration *duration_from_string(const char *string, mgp_memory *memory) {
   return MgInvoke<mgp_duration *>(mgp_duration_from_string, string, memory);
 }
 
-mgp_duration *duration_from_parameters(mgp_duration_parameters *parameters, mgp_memory *memory) {
+inline mgp_duration *duration_from_parameters(mgp_duration_parameters *parameters, mgp_memory *memory) {
   return MgInvoke<mgp_duration *>(mgp_duration_from_parameters, parameters, memory);
 }
 
-mgp_duration *duration_from_microseconds(int64_t microseconds, mgp_memory *memory) {
+inline mgp_duration *duration_from_microseconds(int64_t microseconds, mgp_memory *memory) {
   return MgInvoke<mgp_duration *>(mgp_duration_from_microseconds, microseconds, memory);
 }
 
-mgp_duration *duration_copy(mgp_duration *duration, mgp_memory *memory) {
+inline mgp_duration *duration_copy(mgp_duration *duration, mgp_memory *memory) {
   return MgInvoke<mgp_duration *>(mgp_duration_copy, duration, memory);
 }
 
-void duration_destroy(mgp_duration *duration) { mgp_duration_destroy(duration); }
+inline void duration_destroy(mgp_duration *duration) { mgp_duration_destroy(duration); }
 
-int64_t duration_get_microseconds(mgp_duration *duration) {
+inline int64_t duration_get_microseconds(mgp_duration *duration) {
   return MgInvoke<int64_t>(mgp_duration_get_microseconds, duration);
 }
 
-bool duration_equal(mgp_duration *first, mgp_duration *second) {
+inline bool duration_equal(mgp_duration *first, mgp_duration *second) {
   return MgInvoke<int>(mgp_duration_equal, first, second);
 }
 
-mgp_duration *duration_neg(mgp_duration *duration, mgp_memory *memory) {
+inline mgp_duration *duration_neg(mgp_duration *duration, mgp_memory *memory) {
   return MgInvoke<mgp_duration *>(mgp_duration_neg, duration, memory);
 }
 
-mgp_duration *duration_add(mgp_duration *first, mgp_duration *second, mgp_memory *memory) {
+inline mgp_duration *duration_add(mgp_duration *first, mgp_duration *second, mgp_memory *memory) {
   return MgInvoke<mgp_duration *>(mgp_duration_add, first, second, memory);
 }
 
-mgp_duration *duration_sub(mgp_duration *first, mgp_duration *second, mgp_memory *memory) {
+inline mgp_duration *duration_sub(mgp_duration *first, mgp_duration *second, mgp_memory *memory) {
   return MgInvoke<mgp_duration *>(mgp_duration_sub, first, second, memory);
 }
 
 // Procedure
 
-mgp_proc *module_add_read_procedure(mgp_module *module, const char *name, mgp_proc_cb cb) {
+inline mgp_proc *module_add_read_procedure(mgp_module *module, const char *name, mgp_proc_cb cb) {
   return MgInvoke<mgp_proc *>(mgp_module_add_read_procedure, module, name, cb);
 }
 
-mgp_proc *module_add_write_procedure(mgp_module *module, const char *name, mgp_proc_cb cb) {
+inline mgp_proc *module_add_write_procedure(mgp_module *module, const char *name, mgp_proc_cb cb) {
   return MgInvoke<mgp_proc *>(mgp_module_add_write_procedure, module, name, cb);
 }
 
-void proc_add_arg(mgp_proc *proc, const char *name, mgp_type *type) {
+inline void proc_add_arg(mgp_proc *proc, const char *name, mgp_type *type) {
   MgInvokeVoid(mgp_proc_add_arg, proc, name, type);
 }
 
-void proc_add_opt_arg(mgp_proc *proc, const char *name, mgp_type *type, mgp_value *default_value) {
+inline void proc_add_opt_arg(mgp_proc *proc, const char *name, mgp_type *type, mgp_value *default_value) {
   MgInvokeVoid(mgp_proc_add_opt_arg, proc, name, type, default_value);
 }
 
-void proc_add_result(mgp_proc *proc, const char *name, mgp_type *type) {
+inline void proc_add_result(mgp_proc *proc, const char *name, mgp_type *type) {
   MgInvokeVoid(mgp_proc_add_result, proc, name, type);
 }
 
-void proc_add_deprecated_result(mgp_proc *proc, const char *name, mgp_type *type) {
+inline void proc_add_deprecated_result(mgp_proc *proc, const char *name, mgp_type *type) {
   MgInvokeVoid(mgp_proc_add_deprecated_result, proc, name, type);
 }
 
-bool must_abort(mgp_graph *graph) { return mgp_must_abort(graph); }
+inline bool must_abort(mgp_graph *graph) { return mgp_must_abort(graph); }
 
 // mgp_result
 
-void result_set_error_msg(mgp_result *res, const char *error_msg) {
+inline void result_set_error_msg(mgp_result *res, const char *error_msg) {
   MgInvokeVoid(mgp_result_set_error_msg, res, error_msg);
 }
 
-mgp_result_record *result_new_record(mgp_result *res) {
+inline mgp_result_record *result_new_record(mgp_result *res) {
   return MgInvoke<mgp_result_record *>(mgp_result_new_record, res);
 }
 
-void result_record_insert(mgp_result_record *record, const char *field_name, mgp_value *val) {
+inline void result_record_insert(mgp_result_record *record, const char *field_name, mgp_value *val) {
   MgInvokeVoid(mgp_result_record_insert, record, field_name, val);
 }
 
 // Function
 
-mgp_func *module_add_function(mgp_module *module, const char *name, mgp_func_cb cb) {
+inline mgp_func *module_add_function(mgp_module *module, const char *name, mgp_func_cb cb) {
   return MgInvoke<mgp_func *>(mgp_module_add_function, module, name, cb);
 }
 
-void func_add_arg(mgp_func *func, const char *name, mgp_type *type) {
+inline void func_add_arg(mgp_func *func, const char *name, mgp_type *type) {
   MgInvokeVoid(mgp_func_add_arg, func, name, type);
 }
 
-void func_add_opt_arg(mgp_func *func, const char *name, mgp_type *type, mgp_value *default_value) {
+inline void func_add_opt_arg(mgp_func *func, const char *name, mgp_type *type, mgp_value *default_value) {
   MgInvokeVoid(mgp_func_add_opt_arg, func, name, type, default_value);
 }
 
-void func_result_set_error_msg(mgp_func_result *res, const char *msg, mgp_memory *memory) {
+inline void func_result_set_error_msg(mgp_func_result *res, const char *msg, mgp_memory *memory) {
   MgInvokeVoid(mgp_func_result_set_error_msg, res, msg, memory);
 }
 
-void func_result_set_value(mgp_func_result *res, mgp_value *value, mgp_memory *memory) {
+inline void func_result_set_value(mgp_func_result *res, mgp_value *value, mgp_memory *memory) {
   MgInvokeVoid(mgp_func_result_set_value, res, value, memory);
 }
 
diff --git a/include/mgp.hpp b/include/mgp.hpp
index bf2e27c50..e18f18961 100644
--- a/include/mgp.hpp
+++ b/include/mgp.hpp
@@ -55,21 +55,6 @@ class NotEnoughMemoryException : public std::exception {
   const char *what() const throw() { return "Not enough memory!"; }
 };
 
-namespace util {
-// uint to int conversion in C++ is a bit tricky. Take a look here
-// https://stackoverflow.com/questions/14623266/why-cant-i-reinterpret-cast-uint-to-int
-// for more details.
-template <typename TDest, typename TSrc>
-TDest MemcpyCast(TSrc src) {
-  TDest dest;
-  static_assert(sizeof(dest) == sizeof(src), "MemcpyCast expects source and destination to be of the same size");
-  static_assert(std::is_arithmetic<TSrc>::value, "MemcpyCast expects source to be an arithmetic type");
-  static_assert(std::is_arithmetic<TDest>::value, "MemcpyCast expects destination to be an arithmetic type");
-  std::memcpy(&dest, &src, sizeof(src));
-  return dest;
-}
-}  // namespace util
-
 // Forward declarations
 class Nodes;
 using GraphNodes = Nodes;
@@ -81,7 +66,7 @@ struct MapItem;
 class Duration;
 class Value;
 
-mgp_memory *memory;
+inline mgp_memory *memory{nullptr};
 
 /* #region Graph (Id, Graph, Nodes, GraphRelationships, Relationships, Properties & Labels) */
 
@@ -91,20 +76,20 @@ class Id {
   Id() = default;
 
   /// Construct Id from uint64_t
-  static Id FromUint(uint64_t id) { return Id(util::MemcpyCast<int64_t>(id)); }
+  static Id FromUint(uint64_t id);
   /// Construct Id from int64_t
-  static Id FromInt(int64_t id) { return Id(id); }
+  static Id FromInt(int64_t id);
 
-  int64_t AsInt() const noexcept { return id_; }
-  uint64_t AsUint() const { return util::MemcpyCast<uint64_t>(id_); }
+  int64_t AsInt() const;
+  uint64_t AsUint() const;
 
-  bool operator==(const Id &other) const { return id_ == other.id_; }
-  bool operator!=(const Id &other) const { return !(*this == other); }
+  bool operator==(const Id &other) const;
+  bool operator!=(const Id &other) const;
 
-  bool operator<(const Id &other) const { return id_ < other.id_; }
+  bool operator<(const Id &other) const;
 
  private:
-  explicit Id(int64_t id) : id_(id) {}
+  explicit Id(int64_t id);
 
   int64_t id_;
 };
@@ -116,7 +101,7 @@ class Graph {
   friend class Relationship;
 
  public:
-  explicit Graph(mgp_graph *graph) : graph_(graph) {}
+  explicit Graph(mgp_graph *graph);
 
   /// @brief Returns the graph order (number of nodes).
   int64_t Order() const;
@@ -141,7 +126,7 @@ class Graph {
   bool ContainsRelationship(const Relationship &relationship) const;
 
   /// @brief Returns whether the graph is mutable.
-  bool IsMutable() const { return mgp::graph_is_mutable(graph_); }
+  bool IsMutable() const;
   /// @brief Creates a node and adds it to the graph.
   Node CreateNode();
   /// @brief Deletes a node from the graph.
@@ -160,7 +145,7 @@ class Graph {
 /// @brief View of graph nodes; wrapper class for @ref mgp_vertices_iterator.
 class Nodes {
  public:
-  explicit Nodes(mgp_vertices_iterator *nodes_iterator) : nodes_iterator_(nodes_iterator) {}
+  explicit Nodes(mgp_vertices_iterator *nodes_iterator);
 
   class Iterator {
    public:
@@ -172,58 +157,19 @@ class Nodes {
     using pointer = value_type *;
     using reference = value_type &;
 
-    explicit Iterator(mgp_vertices_iterator *nodes_iterator) : nodes_iterator_(nodes_iterator) {
-      if (nodes_iterator_ == nullptr) {
-        return;
-      }
-
-      if (mgp::vertices_iterator_get(nodes_iterator_) == nullptr) {
-        mgp::vertices_iterator_destroy(nodes_iterator_);
-        nodes_iterator_ = nullptr;
-      }
-    }
-
-    Iterator(const Iterator &other) : Iterator(other.nodes_iterator_) {}
+    explicit Iterator(mgp_vertices_iterator *nodes_iterator);
 
+    Iterator(const Iterator &other);
     Iterator &operator=(const Iterator &other) = delete;
 
-    ~Iterator() {
-      if (nodes_iterator_ != nullptr) {
-        mgp::vertices_iterator_destroy(nodes_iterator_);
-      }
-    }
+    ~Iterator();
 
-    Iterator &operator++() {
-      if (nodes_iterator_ != nullptr) {
-        auto next = mgp::vertices_iterator_next(nodes_iterator_);
+    Iterator &operator++();
 
-        if (next == nullptr) {
-          mgp::vertices_iterator_destroy(nodes_iterator_);
-          nodes_iterator_ = nullptr;
-          return *this;
-        }
-        index_++;
-      }
-      return *this;
-    }
-    Iterator operator++(int) {
-      auto retval = *this;
-      ++*this;
-      return retval;
-    }
+    Iterator operator++(int);
 
-    bool operator==(Iterator other) const {
-      if (nodes_iterator_ == nullptr && other.nodes_iterator_ == nullptr) {
-        return true;
-      }
-      if (nodes_iterator_ == nullptr || other.nodes_iterator_ == nullptr) {
-        return false;
-      }
-      return mgp::vertex_equal(mgp::vertices_iterator_get(nodes_iterator_),
-                               mgp::vertices_iterator_get(other.nodes_iterator_)) &&
-             index_ == other.index_;
-    }
-    bool operator!=(Iterator other) const { return !(*this == other); }
+    bool operator==(Iterator other) const;
+    bool operator!=(Iterator other) const;
 
     const Node operator*() const;
 
@@ -232,11 +178,11 @@ class Nodes {
     size_t index_ = 0;
   };
 
-  Iterator begin() const { return Iterator(nodes_iterator_); }
-  Iterator end() const { return Iterator(nullptr); }
+  Iterator begin() const;
+  Iterator end() const;
 
-  Iterator cbegin() const { return Iterator(nodes_iterator_); }
-  Iterator cend() const { return Iterator(nullptr); }
+  Iterator cbegin() const;
+  Iterator cend() const;
 
  private:
   mgp_vertices_iterator *nodes_iterator_ = nullptr;
@@ -247,7 +193,7 @@ class Nodes {
 // relationships.
 class GraphRelationships {
  public:
-  explicit GraphRelationships(mgp_graph *graph) : graph_(graph) {}
+  explicit GraphRelationships(mgp_graph *graph);
 
   class Iterator {
    public:
@@ -259,107 +205,18 @@ class GraphRelationships {
     using pointer = value_type *;
     using reference = value_type &;
 
-    explicit Iterator(mgp_vertices_iterator *nodes_iterator) : nodes_iterator_(nodes_iterator) {
-      // Positions the iterator over the first existing relationship
-
-      if (nodes_iterator_ == nullptr) {
-        return;
-      }
-
-      // Go through each graph node’s adjacent nodes
-      for (auto node = mgp::vertices_iterator_get(nodes_iterator_); node;
-           node = mgp::vertices_iterator_next(nodes_iterator_)) {
-        // Check if node exists
-        if (node == nullptr) {
-          mgp::vertices_iterator_destroy(nodes_iterator_);
-          nodes_iterator_ = nullptr;
-          return;
-        }
-
-        // Check if node has out-relationships
-        out_relationships_iterator_ = mgp::vertex_iter_out_edges(node, memory);
-        auto relationship = mgp::edges_iterator_get(out_relationships_iterator_);
-        if (relationship != nullptr) {
-          return;
-        }
-
-        mgp::edges_iterator_destroy(out_relationships_iterator_);
-        out_relationships_iterator_ = nullptr;
-      }
-    }
-
-    Iterator(const Iterator &other) : Iterator(other.nodes_iterator_) {}
+    explicit Iterator(mgp_vertices_iterator *nodes_iterator);
 
+    Iterator(const Iterator &other);
     Iterator &operator=(const Iterator &other) = delete;
 
-    ~Iterator() {
-      if (nodes_iterator_ != nullptr) {
-        mgp::vertices_iterator_destroy(nodes_iterator_);
-      }
-      if (out_relationships_iterator_ != nullptr) {
-        mgp::edges_iterator_destroy(out_relationships_iterator_);
-      }
-    }
+    ~Iterator();
 
-    Iterator &operator++() {
-      // Moves the iterator onto the next existing relationship
+    Iterator &operator++();
+    Iterator operator++(int);
 
-      // 1. Check if the current node has remaining relationships to iterate over
-
-      if (out_relationships_iterator_ != nullptr) {
-        auto next = mgp::edges_iterator_next(out_relationships_iterator_);
-
-        if (next == nullptr) {
-          mgp::edges_iterator_destroy(out_relationships_iterator_);
-          out_relationships_iterator_ = nullptr;
-        }
-      }
-
-      // 2. Move onto the next nodes
-
-      if (nodes_iterator_ != nullptr) {
-        for (auto node = mgp::vertices_iterator_next(nodes_iterator_); node;
-             node = mgp::vertices_iterator_next(nodes_iterator_)) {
-          // Check if node exists - if it doesn’t, we’ve reached the end of the iterator
-          if (node == nullptr) {
-            mgp::vertices_iterator_destroy(nodes_iterator_);
-            nodes_iterator_ = nullptr;
-            return *this;
-          }
-
-          // Check if node has out-relationships
-          out_relationships_iterator_ = mgp::vertex_iter_out_edges(node, memory);
-          auto relationship = mgp::edges_iterator_get(out_relationships_iterator_);
-          if (relationship != nullptr) {
-            return *this;
-          }
-
-          mgp::edges_iterator_destroy(out_relationships_iterator_);
-          out_relationships_iterator_ = nullptr;
-        }
-      }
-      mgp::vertices_iterator_destroy(nodes_iterator_);
-      nodes_iterator_ = nullptr;
-      return *this;
-    }
-    Iterator operator++(int) {
-      auto retval = *this;
-      ++*this;
-      return retval;
-    }
-
-    bool operator==(Iterator other) const {
-      if (out_relationships_iterator_ == nullptr && other.out_relationships_iterator_ == nullptr) {
-        return true;
-      }
-      if (out_relationships_iterator_ == nullptr || other.out_relationships_iterator_ == nullptr) {
-        return false;
-      }
-      return mgp::edge_equal(mgp::edges_iterator_get(out_relationships_iterator_),
-                             mgp::edges_iterator_get(other.out_relationships_iterator_)) &&
-             index_ == other.index_;
-    }
-    bool operator!=(Iterator other) const { return !(*this == other); }
+    bool operator==(Iterator other) const;
+    bool operator!=(Iterator other) const;
 
     const Relationship operator*() const;
 
@@ -369,11 +226,11 @@ class GraphRelationships {
     size_t index_ = 0;
   };
 
-  Iterator begin() const { return Iterator(mgp::graph_iter_vertices(graph_, memory)); }
-  Iterator end() const { return Iterator(nullptr); }
+  Iterator begin() const;
+  Iterator end() const;
 
-  Iterator cbegin() const { return Iterator(mgp::graph_iter_vertices(graph_, memory)); }
-  Iterator cend() const { return Iterator(nullptr); }
+  Iterator cbegin() const;
+  Iterator cend() const;
 
  private:
   mgp_graph *graph_;
@@ -382,8 +239,7 @@ class GraphRelationships {
 /// @brief Wrapper class for @ref mgp_edges_iterator.
 class Relationships {
  public:
-  explicit Relationships(mgp_edges_iterator *relationships_iterator)
-      : relationships_iterator_(relationships_iterator) {}
+  explicit Relationships(mgp_edges_iterator *relationships_iterator);
 
   class Iterator {
    public:
@@ -395,57 +251,18 @@ class Relationships {
     using pointer = value_type *;
     using reference = value_type &;
 
-    explicit Iterator(mgp_edges_iterator *relationships_iterator) : relationships_iterator_(relationships_iterator) {
-      if (relationships_iterator_ == nullptr) {
-        return;
-      }
-      if (mgp::edges_iterator_get(relationships_iterator_) == nullptr) {
-        mgp::edges_iterator_destroy(relationships_iterator_);
-        relationships_iterator_ = nullptr;
-      }
-    }
-
-    Iterator(const Iterator &other) : Iterator(other.relationships_iterator_) {}
+    explicit Iterator(mgp_edges_iterator *relationships_iterator);
 
+    Iterator(const Iterator &other);
     Iterator &operator=(const Iterator &other) = delete;
 
-    ~Iterator() {
-      if (relationships_iterator_ != nullptr) {
-        mgp::edges_iterator_destroy(relationships_iterator_);
-      }
-    }
+    ~Iterator();
 
-    Iterator &operator++() {
-      if (relationships_iterator_ != nullptr) {
-        auto next = mgp::edges_iterator_next(relationships_iterator_);
+    Iterator &operator++();
+    Iterator operator++(int);
 
-        if (next == nullptr) {
-          mgp::edges_iterator_destroy(relationships_iterator_);
-          relationships_iterator_ = nullptr;
-          return *this;
-        }
-        index_++;
-      }
-      return *this;
-    }
-    Iterator operator++(int) {
-      auto retval = *this;
-      ++*this;
-      return retval;
-    }
-
-    bool operator==(Iterator other) const {
-      if (relationships_iterator_ == nullptr && other.relationships_iterator_ == nullptr) {
-        return true;
-      }
-      if (relationships_iterator_ == nullptr || other.relationships_iterator_ == nullptr) {
-        return false;
-      }
-      return mgp::edge_equal(mgp::edges_iterator_get(relationships_iterator_),
-                             mgp::edges_iterator_get(other.relationships_iterator_)) &&
-             index_ == other.index_;
-    }
-    bool operator!=(Iterator other) const { return !(*this == other); }
+    bool operator==(Iterator other) const;
+    bool operator!=(Iterator other) const;
 
     const Relationship operator*() const;
 
@@ -454,11 +271,11 @@ class Relationships {
     size_t index_ = 0;
   };
 
-  Iterator begin() const { return Iterator(relationships_iterator_); }
-  Iterator end() const { return Iterator(nullptr); }
+  Iterator begin() const;
+  Iterator end() const;
 
-  Iterator cbegin() const { return Iterator(relationships_iterator_); }
-  Iterator cend() const { return Iterator(nullptr); }
+  Iterator cbegin() const;
+  Iterator cend() const;
 
  private:
   mgp_edges_iterator *relationships_iterator_ = nullptr;
@@ -470,31 +287,29 @@ class Properties {
   explicit Properties(mgp_properties_iterator *properties_iterator);
 
   /// @brief Returns the size of the properties map.
-  size_t Size() const { return property_map_.size(); }
+  size_t Size() const;
   /// @brief Returns whether the properties map is empty.
-  bool Empty() const { return Size() == 0; }
+  bool Empty() const;
 
   /// @brief Returns the value associated with the given `key`. If there’s no such value, the behavior is undefined.
   /// @note Each key-value pair needs to be checked, ensuing O(n) time complexity.
   Value operator[](const std::string_view key) const;
 
-  std::map<std::string_view, Value>::const_iterator begin() const { return property_map_.begin(); }
-  std::map<std::string_view, Value>::const_iterator end() const { return property_map_.end(); }
+  std::map<std::string_view, Value>::const_iterator begin() const;
+  std::map<std::string_view, Value>::const_iterator end() const;
 
-  std::map<std::string_view, Value>::const_iterator cbegin() const { return property_map_.cbegin(); }
-  std::map<std::string_view, Value>::const_iterator cend() const { return property_map_.cend(); }
+  std::map<std::string_view, Value>::const_iterator cbegin() const;
+  std::map<std::string_view, Value>::const_iterator cend() const;
 
   /// @brief Returns the key-value iterator for the given `key`. If there’s no such pair, returns the end of the
   /// iterator.
   /// @note Each key-value pair needs to be checked, ensuing O(n) time complexity.
-  std::map<std::string_view, Value>::const_iterator find(const std::string_view key) const {
-    return property_map_.find(key);
-  }
+  std::map<std::string_view, Value>::const_iterator find(const std::string_view key) const;
 
   /// @exception std::runtime_error Map contains value(s) of unknown type.
   bool operator==(const Properties &other) const;
   /// @exception std::runtime_error Map contains value(s) of unknown type.
-  bool operator!=(const Properties &other) const { return !(*this == other); }
+  bool operator!=(const Properties &other) const;
 
  private:
   std::map<const std::string_view, Value> property_map_;
@@ -503,10 +318,18 @@ class Properties {
 /// @brief View of node labels.
 class Labels {
  public:
-  explicit Labels(mgp_vertex *node_ptr) : node_ptr_(node_ptr) {}
+  explicit Labels(mgp_vertex *node_ptr);
+
+  Labels(const Labels &other);
+  Labels(Labels &&other) noexcept;
+
+  Labels &operator=(const Labels &other) noexcept;
+  Labels &operator=(Labels &&other) noexcept;
+
+  ~Labels();
 
   /// @brief Returns the number of the labels, i.e. the size of their list.
-  size_t Size() const { return mgp::vertex_labels_count(node_ptr_); }
+  size_t Size() const;
 
   /// @brief Return the node’s label at position `index`.
   std::string_view operator[](size_t index) const;
@@ -516,29 +339,26 @@ class Labels {
     friend class Labels;
 
    public:
-    bool operator==(const Iterator &other) const { return iterable_ == other.iterable_ && index_ == other.index_; }
+    bool operator==(const Iterator &other) const;
 
-    bool operator!=(const Iterator &other) const { return !(*this == other); }
+    bool operator!=(const Iterator &other) const;
 
-    Iterator &operator++() {
-      index_++;
-      return *this;
-    }
+    Iterator &operator++();
 
     const std::string_view operator*() const;
 
    private:
-    Iterator(const Labels *iterable, size_t index) : iterable_(iterable), index_(index) {}
+    Iterator(const Labels *iterable, size_t index);
 
     const Labels *iterable_;
     size_t index_;
   };
 
-  Iterator begin() { return Iterator(this, 0); }
-  Iterator end() { return Iterator(this, Size()); }
+  Iterator begin();
+  Iterator end();
 
-  Iterator cbegin() { return Iterator(this, 0); }
-  Iterator cend() { return Iterator(this, Size()); }
+  Iterator cbegin();
+  Iterator cend();
 
  private:
   mgp_vertex *node_ptr_;
@@ -559,15 +379,15 @@ class List {
 
  public:
   /// @brief Creates a List from the copy of the given @ref mgp_list.
-  explicit List(mgp_list *ptr) : ptr_(mgp::list_copy(ptr, memory)) {}
+  explicit List(mgp_list *ptr);
   /// @brief Creates a List from the copy of the given @ref mgp_list.
-  explicit List(const mgp_list *const_ptr) : ptr_(mgp::list_copy(const_cast<mgp_list *>(const_ptr), memory)) {}
+  explicit List(const mgp_list *const_ptr);
 
   /// @brief Creates an empty List.
-  explicit List() : ptr_(mgp::list_make_empty(0, memory)) {}
+  explicit List();
 
   /// @brief Creates a List with the given `capacity`.
-  explicit List(size_t capacity) : ptr_(mgp::list_make_empty(capacity, memory)) {}
+  explicit List(size_t capacity);
 
   /// @brief Creates a List from the given vector.
   explicit List(const std::vector<Value> &values);
@@ -577,18 +397,18 @@ class List {
   /// @brief Creates a List from the given initializer_list.
   explicit List(const std::initializer_list<Value> list);
 
-  List(const List &other) : List(other.ptr_) {}
-  List(List &&other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; }
+  List(const List &other);
+  List(List &&other) noexcept;
 
-  List &operator=(const List &other) = delete;
-  List &operator=(List &&other) = delete;
+  List &operator=(const List &other) noexcept;
+  List &operator=(List &&other) noexcept;
 
   ~List();
 
   /// @brief Returns the size of the list.
-  size_t Size() const { return mgp::list_size(ptr_); }
+  size_t Size() const;
   /// @brief Returns whether the list is empty.
-  bool Empty() const { return Size() == 0; }
+  bool Empty() const;
 
   /// @brief Returns the value at the given `index`.
   const Value operator[](size_t index) const;
@@ -598,29 +418,26 @@ class List {
     friend class List;
 
    public:
-    bool operator==(const Iterator &other) const { return iterable_ == other.iterable_ && index_ == other.index_; }
+    bool operator==(const Iterator &other) const;
 
-    bool operator!=(const Iterator &other) const { return !(*this == other); }
+    bool operator!=(const Iterator &other) const;
 
-    Iterator &operator++() {
-      index_++;
-      return *this;
-    }
+    Iterator &operator++();
 
     const Value operator*() const;
 
    private:
-    Iterator(const List *iterable, size_t index) : iterable_(iterable), index_(index) {}
+    Iterator(const List *iterable, size_t index);
 
     const List *iterable_;
     size_t index_;
   };
 
-  Iterator begin() const { return Iterator(this, 0); }
-  Iterator end() const { return Iterator(this, Size()); }
+  Iterator begin() const;
+  Iterator end() const;
 
-  Iterator cbegin() const { return Iterator(this, 0); }
-  Iterator cend() const { return Iterator(this, Size()); }
+  Iterator cbegin() const;
+  Iterator cend() const;
 
   /// @brief Appends the given `value` to the list. The `value` is copied.
   void Append(const Value &value);
@@ -641,7 +458,7 @@ class List {
   /// @exception std::runtime_error List contains value of unknown type.
   bool operator==(const List &other) const;
   /// @exception std::runtime_error List contains value of unknown type.
-  bool operator!=(const List &other) const { return !(*this == other); }
+  bool operator!=(const List &other) const;
 
  private:
   mgp_list *ptr_;
@@ -657,12 +474,12 @@ class Map {
 
  public:
   /// @brief Creates a Map from the copy of the given @ref mgp_map.
-  explicit Map(mgp_map *ptr) : ptr_(mgp::map_copy(ptr, memory)) {}
+  explicit Map(mgp_map *ptr);
   /// @brief Creates a Map from the copy of the given @ref mgp_map.
-  explicit Map(const mgp_map *const_ptr) : ptr_(mgp::map_copy(const_cast<mgp_map *>(const_ptr), memory)) {}
+  explicit Map(const mgp_map *const_ptr);
 
   /// @brief Creates an empty Map.
-  explicit Map() : ptr_(mgp::map_make_empty(memory)) {}
+  explicit Map();
 
   /// @brief Creates a Map from the given vector.
   explicit Map(const std::map<std::string_view, Value> &items);
@@ -672,18 +489,18 @@ class Map {
   /// @brief Creates a Map from the given initializer_list (map items correspond to initializer list pairs).
   Map(const std::initializer_list<std::pair<std::string_view, Value>> items);
 
-  Map(const Map &other) : Map(other.ptr_) {}
-  Map(Map &&other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; }
+  Map(const Map &other);
+  Map(Map &&other) noexcept;
 
-  Map &operator=(const Map &other) = delete;
-  Map &operator=(Map &&other) = delete;
+  Map &operator=(const Map &other) noexcept;
+  Map &operator=(Map &&other) noexcept;
 
   ~Map();
 
   /// @brief Returns the size of the map.
-  size_t Size() const { return mgp::map_size(ptr_); }
+  size_t Size() const;
   /// @brief Returns whether the map is empty.
-  bool Empty() const { return Size() == 0; }
+  bool Empty() const;
 
   /// @brief Returns the value at the given `key`.
   Value const operator[](std::string_view key) const;
@@ -700,52 +517,18 @@ class Map {
     using pointer = value_type *;
     using reference = value_type &;
 
-    explicit Iterator(mgp_map_items_iterator *map_items_iterator) : map_items_iterator_(map_items_iterator) {
-      if (map_items_iterator_ == nullptr) return;
-      if (mgp::map_items_iterator_get(map_items_iterator_) == nullptr) {
-        mgp::map_items_iterator_destroy(map_items_iterator_);
-        map_items_iterator_ = nullptr;
-      }
-    }
-
-    Iterator(const Iterator &other) : Iterator(other.map_items_iterator_) {}
+    explicit Iterator(mgp_map_items_iterator *map_items_iterator);
 
+    Iterator(const Iterator &other);
     Iterator &operator=(const Iterator &other) = delete;
 
-    ~Iterator() {
-      if (map_items_iterator_ != nullptr) {
-        mgp::map_items_iterator_destroy(map_items_iterator_);
-      }
-    }
+    ~Iterator();
 
-    Iterator &operator++() {
-      if (map_items_iterator_ != nullptr) {
-        auto next = mgp::map_items_iterator_next(map_items_iterator_);
+    Iterator &operator++();
+    Iterator operator++(int);
 
-        if (next == nullptr) {
-          mgp::map_items_iterator_destroy(map_items_iterator_);
-          map_items_iterator_ = nullptr;
-          return *this;
-        }
-      }
-      return *this;
-    }
-    Iterator operator++(int) {
-      auto retval = *this;
-      ++*this;
-      return retval;
-    }
-
-    bool operator==(Iterator other) const {
-      if (map_items_iterator_ == nullptr && other.map_items_iterator_ == nullptr) {
-        return true;
-      }
-      if (map_items_iterator_ == nullptr || other.map_items_iterator_ == nullptr) {
-        return false;
-      }
-      return mgp::map_items_iterator_get(map_items_iterator_) == mgp::map_items_iterator_get(other.map_items_iterator_);
-    }
-    bool operator!=(Iterator other) const { return !(*this == other); }
+    bool operator==(Iterator other) const;
+    bool operator!=(Iterator other) const;
 
     const MapItem operator*() const;
 
@@ -753,11 +536,11 @@ class Map {
     mgp_map_items_iterator *map_items_iterator_ = nullptr;
   };
 
-  Iterator begin() const { return Iterator(mgp::map_iter_items(ptr_, memory)); }
-  Iterator end() const { return Iterator(nullptr); }
+  Iterator begin() const;
+  Iterator end() const;
 
-  Iterator cbegin() const { return Iterator(mgp::map_iter_items(ptr_, memory)); }
-  Iterator cend() const { return Iterator(nullptr); }
+  Iterator cbegin() const;
+  Iterator cend() const;
 
   /// @brief Inserts the given `key`-`value` pair into the map. The `value` is copied.
   void Insert(std::string_view key, const Value &value);
@@ -772,7 +555,7 @@ class Map {
   /// @exception std::runtime_error Map contains value of unknown type.
   bool operator==(const Map &other) const;
   /// @exception std::runtime_error Map contains value of unknown type.
-  bool operator!=(const Map &other) const { return !(*this == other); }
+  bool operator!=(const Map &other) const;
 
  private:
   mgp_map *ptr_;
@@ -791,32 +574,30 @@ class Node {
   friend class Parameter;
 
   /// @brief Creates a Node from the copy of the given @ref mgp_vertex.
-  explicit Node(mgp_vertex *ptr) : ptr_(mgp::vertex_copy(ptr, memory)) {}
+  explicit Node(mgp_vertex *ptr);
   /// @brief Creates a Node from the copy of the given @ref mgp_vertex.
-  explicit Node(const mgp_vertex *const_ptr) : ptr_(mgp::vertex_copy(const_cast<mgp_vertex *>(const_ptr), memory)) {}
+  explicit Node(const mgp_vertex *const_ptr);
 
-  Node(const Node &other) : Node(other.ptr_) {}
-  Node(Node &&other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; }
+  Node(const Node &other);
+  Node(Node &&other) noexcept;
 
-  Node &operator=(const Node &other) = delete;
-  Node &operator=(Node &&other) { return *this; }
+  Node &operator=(const Node &other) noexcept;
+  Node &operator=(Node &&other) noexcept;
 
   ~Node();
 
   /// @brief Returns the node’s ID.
-  mgp::Id Id() const { return Id::FromInt(mgp::vertex_get_id(ptr_).as_int); }
+  mgp::Id Id() const;
 
   /// @brief Returns an iterable & indexable structure of the node’s labels.
-  class Labels Labels() const {
-    return mgp::Labels(ptr_);
-  }
+  class Labels Labels() const;
+
   /// @brief Returns whether the node has the given `label`.
   bool HasLabel(std::string_view label) const;
 
   /// @brief Returns an iterable & indexable structure of the node’s properties.
-  class Properties Properties() const {
-    return mgp::Properties(mgp::vertex_iter_properties(ptr_, memory));
-  }
+  class Properties Properties() const;
+
   /// @brief Returns the value of the node’s `property_name` property.
   Value operator[](const std::string_view property_name) const;
 
@@ -827,12 +608,12 @@ class Node {
   /// @brief Adds a label to the node.
   void AddLabel(const std::string_view label);
 
-  bool operator<(const Node &other) const { return Id() < other.Id(); }
+  bool operator<(const Node &other) const;
 
   /// @exception std::runtime_error Node properties contain value(s) of unknown type.
   bool operator==(const Node &other) const;
   /// @exception std::runtime_error Node properties contain value(s) of unknown type.
-  bool operator!=(const Node &other) const { return !(*this == other); }
+  bool operator!=(const Node &other) const;
 
  private:
   mgp_vertex *ptr_;
@@ -850,42 +631,41 @@ class Relationship {
 
  public:
   /// @brief Creates a Relationship from the copy of the given @ref mgp_edge.
-  explicit Relationship(mgp_edge *ptr) : ptr_(mgp::edge_copy(ptr, memory)) {}
+  explicit Relationship(mgp_edge *ptr);
   /// @brief Creates a Relationship from the copy of the given @ref mgp_edge.
-  explicit Relationship(const mgp_edge *const_ptr) : ptr_(mgp::edge_copy(const_cast<mgp_edge *>(const_ptr), memory)) {}
+  explicit Relationship(const mgp_edge *const_ptr);
 
-  Relationship(const Relationship &other) : Relationship(other.ptr_) {}
-  Relationship(Relationship &&other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; }
+  Relationship(const Relationship &other);
+  Relationship(Relationship &&other) noexcept;
 
-  Relationship &operator=(const Relationship &other) = delete;
-  Relationship &operator=(Relationship &&other) = delete;
+  Relationship &operator=(const Relationship &other) noexcept;
+  Relationship &operator=(Relationship &&other) noexcept;
 
   ~Relationship();
 
   /// @brief Returns the relationship’s ID.
-  mgp::Id Id() const { return Id::FromInt(mgp::edge_get_id(ptr_).as_int); }
+  mgp::Id Id() const;
 
   /// @brief Returns the relationship’s type.
   std::string_view Type() const;
 
   /// @brief Returns an iterable & indexable structure of the relationship’s properties.
-  class Properties Properties() const {
-    return mgp::Properties(mgp::edge_iter_properties(ptr_, memory));
-  }
+  class Properties Properties() const;
+
   /// @brief Returns the value of the relationship’s `property_name` property.
   Value operator[](const std::string_view property_name) const;
 
   /// @brief Returns the relationship’s source node.
-  Node From() const { return Node(mgp::edge_get_from(ptr_)); }
+  Node From() const;
   /// @brief Returns the relationship’s destination node.
-  Node To() const { return Node(mgp::edge_get_to(ptr_)); }
+  Node To() const;
 
-  bool operator<(const Relationship &other) const { return Id() < other.Id(); }
+  bool operator<(const Relationship &other) const;
 
   /// @exception std::runtime_error Relationship properties contain value(s) of unknown type.
   bool operator==(const Relationship &other) const;
   /// @exception std::runtime_error Relationship properties contain value(s) of unknown type.
-  bool operator!=(const Relationship &other) const { return !(*this == other); }
+  bool operator!=(const Relationship &other) const;
 
  private:
   mgp_edge *ptr_;
@@ -901,23 +681,23 @@ class Path {
 
  public:
   /// @brief Creates a Path from the copy of the given @ref mgp_path.
-  explicit Path(mgp_path *ptr) : ptr_(mgp::path_copy(ptr, memory)) {}
+  explicit Path(mgp_path *ptr);
   /// @brief Creates a Path from the copy of the given @ref mgp_path.
-  explicit Path(const mgp_path *const_ptr) : ptr_(mgp::path_copy(const_cast<mgp_path *>(const_ptr), memory)) {}
+  explicit Path(const mgp_path *const_ptr);
 
   /// @brief Creates a Path starting with the given `start_node`.
   explicit Path(const Node &start_node);
 
-  Path(const Path &other) : Path(other.ptr_) {}
-  Path(Path &&other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; }
+  Path(const Path &other);
+  Path(Path &&other) noexcept;
 
-  Path &operator=(const Path &other);
-  Path &operator=(Path &&other);
+  Path &operator=(const Path &other) noexcept;
+  Path &operator=(Path &&other) noexcept;
 
   ~Path();
 
   /// Returns the path length (number of relationships).
-  size_t Length() const { return mgp::path_size(ptr_); }
+  size_t Length() const;
 
   /// @brief Returns the node at the given `index`.
   /// @pre The `index` must be less than or equal to length of the path.
@@ -933,7 +713,7 @@ class Path {
   /// @exception std::runtime_error Path contains element(s) with unknown value.
   bool operator==(const Path &other) const;
   /// @exception std::runtime_error Path contains element(s) with unknown value.
-  bool operator!=(const Path &other) const { return !(*this == other); }
+  bool operator!=(const Path &other) const;
 
  private:
   mgp_path *ptr_;
@@ -953,22 +733,22 @@ class Date {
 
  public:
   /// @brief Creates a Date object from the copy of the given @ref mgp_date.
-  explicit Date(mgp_date *ptr) : ptr_(mgp::date_copy(ptr, memory)) {}
+  explicit Date(mgp_date *ptr);
   /// @brief Creates a Date object from the copy of the given @ref mgp_date.
-  explicit Date(const mgp_date *const_ptr) : ptr_(mgp::date_copy(const_cast<mgp_date *>(const_ptr), memory)) {}
+  explicit Date(const mgp_date *const_ptr);
 
   /// @brief Creates a Date object from the given string representing a date in the ISO 8601 format (`YYYY-MM-DD`,
   /// `YYYYMMDD`, or `YYYY-MM`).
-  explicit Date(std::string_view string) : ptr_(mgp::date_from_string(string.data(), memory)) {}
+  explicit Date(std::string_view string);
 
   /// @brief Creates a Date object with the given `year`, `month`, and `day` properties.
   Date(int year, int month, int day);
 
-  Date(const Date &other) : Date(other.ptr_) {}
-  Date(Date &&other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; }
+  Date(const Date &other);
+  Date(Date &&other) noexcept;
 
-  Date &operator=(const Date &other) = delete;
-  Date &operator=(Date &&other) = delete;
+  Date &operator=(const Date &other) noexcept;
+  Date &operator=(Date &&other) noexcept;
 
   ~Date();
 
@@ -976,14 +756,14 @@ class Date {
   static Date Now();
 
   /// @brief Returns the date’s year property.
-  int Year() const { return mgp::date_get_year(ptr_); }
+  int Year() const;
   /// @brief Returns the date’s month property.
-  int Month() const { return mgp::date_get_month(ptr_); }
+  int Month() const;
   /// @brief Returns the date’s day property.
-  int Day() const { return mgp::date_get_day(ptr_); }
+  int Day() const;
 
   /// @brief Returns the date’s timestamp (microseconds from the Unix epoch).
-  int64_t Timestamp() const { return mgp::date_timestamp(ptr_); }
+  int64_t Timestamp() const;
 
   bool operator==(const Date &other) const;
   Date operator+(const Duration &dur) const;
@@ -1007,24 +787,23 @@ class LocalTime {
 
  public:
   /// @brief Creates a LocalTime object from the copy of the given @ref mgp_local_time.
-  explicit LocalTime(mgp_local_time *ptr) : ptr_(mgp::local_time_copy(ptr, memory)) {}
+  explicit LocalTime(mgp_local_time *ptr);
   /// @brief Creates a LocalTime object from the copy of the given @ref mgp_local_time.
-  explicit LocalTime(const mgp_local_time *const_ptr)
-      : ptr_(mgp::local_time_copy(const_cast<mgp_local_time *>(const_ptr), memory)) {}
+  explicit LocalTime(const mgp_local_time *const_ptr);
 
   /// @brief Creates a LocalTime object from the given string representing a date in the ISO 8601 format ([T]hh:mm:ss,
   /// `[T]hh:mm`, `[T]hhmmss`, `[T]hhmm`, or `[T]hh`).
-  explicit LocalTime(std::string_view string) : ptr_(mgp::local_time_from_string(string.data(), memory)) {}
+  explicit LocalTime(std::string_view string);
 
   /// @brief Creates a LocalTime object with the given `hour`, `minute`, `second`, `millisecond`, and `microsecond`
   /// properties.
   LocalTime(int hour, int minute, int second, int millisecond, int microsecond);
 
-  LocalTime(const LocalTime &other) : LocalTime(other.ptr_) {}
-  LocalTime(LocalTime &&other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; };
+  LocalTime(const LocalTime &other);
+  LocalTime(LocalTime &&other) noexcept;
 
-  LocalTime &operator=(const LocalTime &other) = delete;
-  LocalTime &operator=(LocalTime &&other) = delete;
+  LocalTime &operator=(const LocalTime &other) noexcept;
+  LocalTime &operator=(LocalTime &&other) noexcept;
 
   ~LocalTime();
 
@@ -1032,18 +811,18 @@ class LocalTime {
   static LocalTime Now();
 
   /// @brief Returns the object’s `hour` property.
-  int Hour() const { return mgp::local_time_get_hour(ptr_); }
+  int Hour() const;
   /// @brief Returns the object’s `minute` property.
-  int Minute() const { return mgp::local_time_get_minute(ptr_); }
+  int Minute() const;
   /// @brief Returns the object’s `second` property.
-  int Second() const { return mgp::local_time_get_second(ptr_); }
+  int Second() const;
   /// @brief Returns the object’s `millisecond` property.
-  int Millisecond() const { return mgp::local_time_get_millisecond(ptr_); }
+  int Millisecond() const;
   /// @brief Returns the object’s `microsecond` property.
-  int Microsecond() const { return mgp::local_time_get_microsecond(ptr_); }
+  int Microsecond() const;
 
   /// @brief Returns the object’s timestamp (microseconds from the Unix epoch).
-  int64_t Timestamp() const { return mgp::local_time_timestamp(ptr_); }
+  int64_t Timestamp() const;
 
   bool operator==(const LocalTime &other) const;
   LocalTime operator+(const Duration &dur) const;
@@ -1067,24 +846,23 @@ class LocalDateTime {
 
  public:
   /// @brief Creates a LocalDateTime object from the copy of the given @ref mgp_local_date_time.
-  explicit LocalDateTime(mgp_local_date_time *ptr) : ptr_(mgp::local_date_time_copy(ptr, memory)) {}
+  explicit LocalDateTime(mgp_local_date_time *ptr);
   /// @brief Creates a LocalDateTime object from the copy of the given @ref mgp_local_date_time.
-  explicit LocalDateTime(const mgp_local_date_time *const_ptr)
-      : ptr_(mgp::local_date_time_copy(const_cast<mgp_local_date_time *>(const_ptr), memory)) {}
+  explicit LocalDateTime(const mgp_local_date_time *const_ptr);
 
   /// @brief Creates a LocalDateTime object from the given string representing a date in the ISO 8601 format
   /// (`YYYY-MM-DDThh:mm:ss`, `YYYY-MM-DDThh:mm`, `YYYYMMDDThhmmss`, `YYYYMMDDThhmm`, or `YYYYMMDDThh`).
-  explicit LocalDateTime(std::string_view string) : ptr_(mgp::local_date_time_from_string(string.data(), memory)) {}
+  explicit LocalDateTime(std::string_view string);
 
   /// @brief Creates a LocalDateTime object with the given `year`, `month`, `day`, `hour`, `minute`, `second`,
   /// `millisecond`, and `microsecond` properties.
   LocalDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond);
 
-  LocalDateTime(const LocalDateTime &other) : LocalDateTime(other.ptr_) {}
-  LocalDateTime(LocalDateTime &&other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; };
+  LocalDateTime(const LocalDateTime &other);
+  LocalDateTime(LocalDateTime &&other) noexcept;
 
-  LocalDateTime &operator=(const LocalDateTime &other) = delete;
-  LocalDateTime &operator=(LocalDateTime &&other) = delete;
+  LocalDateTime &operator=(const LocalDateTime &other) noexcept;
+  LocalDateTime &operator=(LocalDateTime &&other) noexcept;
 
   ~LocalDateTime();
 
@@ -1092,24 +870,24 @@ class LocalDateTime {
   static LocalDateTime Now();
 
   /// @brief Returns the object’s `year` property.
-  int Year() const { return mgp::local_date_time_get_year(ptr_); }
+  int Year() const;
   /// @brief Returns the object’s `month` property.
-  int Month() const { return mgp::local_date_time_get_month(ptr_); }
+  int Month() const;
   /// @brief Returns the object’s `day` property.
-  int Day() const { return mgp::local_date_time_get_day(ptr_); }
+  int Day() const;
   /// @brief Returns the object’s `hour` property.
-  int Hour() const { return mgp::local_date_time_get_hour(ptr_); }
+  int Hour() const;
   /// @brief Returns the object’s `minute` property.
-  int Minute() const { return mgp::local_date_time_get_minute(ptr_); }
+  int Minute() const;
   /// @brief Returns the object’s `second` property.
-  int Second() const { return mgp::local_date_time_get_second(ptr_); }
+  int Second() const;
   /// @brief Returns the object’s `millisecond` property.
-  int Millisecond() const { return mgp::local_date_time_get_millisecond(ptr_); }
+  int Millisecond() const;
   /// @brief Returns the object’s `microsecond` property.
-  int Microsecond() const { return mgp::local_date_time_get_microsecond(ptr_); }
+  int Microsecond() const;
 
   /// @brief Returns the object’s timestamp (microseconds from the Unix epoch).
-  int64_t Timestamp() const { return mgp::local_date_time_timestamp(ptr_); }
+  int64_t Timestamp() const;
 
   bool operator==(const LocalDateTime &other) const;
   LocalDateTime operator+(const Duration &dur) const;
@@ -1135,33 +913,32 @@ class Duration {
 
  public:
   /// @brief Creates a Duration from the copy of the given @ref mgp_duration.
-  explicit Duration(mgp_duration *ptr) : ptr_(mgp::duration_copy(ptr, memory)) {}
+  explicit Duration(mgp_duration *ptr);
   /// @brief Creates a Duration from the copy of the given @ref mgp_duration.
-  explicit Duration(const mgp_duration *const_ptr)
-      : ptr_(mgp::duration_copy(const_cast<mgp_duration *>(const_ptr), memory)) {}
+  explicit Duration(const mgp_duration *const_ptr);
 
   /// @brief Creates a Duration object from the given string in the following format: `P[nD]T[nH][nM][nS]`, where (1)
   /// `n` stands for a number, (2) capital letters are used as a separator, (3) each field in `[]` is optional, and (4)
   /// only the last field may be a non-integer.
-  explicit Duration(std::string_view string) : ptr_(mgp::duration_from_string(string.data(), memory)) {}
+  explicit Duration(std::string_view string);
 
   /// @brief Creates a Duration object from the given number of microseconds.
-  explicit Duration(int64_t microseconds) : ptr_(mgp::duration_from_microseconds(microseconds, memory)) {}
+  explicit Duration(int64_t microseconds);
 
   /// @brief Creates a Duration object with the given `day`, `hour`, `minute`, `second`, `millisecond`, and
   /// `microsecond` properties.
   Duration(double day, double hour, double minute, double second, double millisecond, double microsecond);
 
-  Duration(const Duration &other) : Duration(other.ptr_) {}
-  Duration(Duration &&other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; };
+  Duration(const Duration &other);
+  Duration(Duration &&other) noexcept;
 
-  Duration &operator=(const Duration &other) = delete;
-  Duration &operator=(Duration &&other) = delete;
+  Duration &operator=(const Duration &other) noexcept;
+  Duration &operator=(Duration &&other) noexcept;
 
   ~Duration();
 
   /// @brief Returns the duration as microseconds.
-  int64_t Microseconds() const { return mgp::duration_get_microseconds(ptr_); }
+  int64_t Microseconds() const;
 
   bool operator==(const Duration &other) const;
   Duration operator+(const Duration &other) const;
@@ -1207,123 +984,88 @@ class Value {
   friend class Record;
   friend class Result;
 
-  explicit Value(mgp_value *ptr) : ptr_(mgp::value_copy(ptr, memory)) {}
+  explicit Value(mgp_value *ptr);
 
   // Null constructor:
-  explicit Value() : ptr_(mgp::value_make_null(memory)) {}
+  explicit Value();
 
   // Primitive type constructors:
-  explicit Value(const bool value) : ptr_(mgp::value_make_bool(value, memory)) {}
-  explicit Value(const int64_t value) : ptr_(mgp::value_make_int(value, memory)) {}
-  explicit Value(const double value) : ptr_(mgp::value_make_double(value, memory)) {}
+  explicit Value(const bool value);
+  explicit Value(const int64_t value);
+  explicit Value(const double value);
 
   // String constructors:
-  explicit Value(const char *value) : ptr_(mgp::value_make_string(value, memory)) {}
-  explicit Value(const std::string_view value) : ptr_(mgp::value_make_string(value.data(), memory)) {}
-
+  explicit Value(const char *value);
+  explicit Value(const std::string_view value);
   // Container constructors:
 
   /// @brief Constructs a List value from the copy of the given `list`.
-  explicit Value(const List &list) : ptr_(mgp::value_make_list(list.ptr_)) {}
+  explicit Value(const List &list);
   /// @note The behavior of accessing `list` after performing this operation is undefined.
-  explicit Value(List &&list) {
-    ptr_ = mgp::value_make_list(list.ptr_);
-    delete &list;
-    list.ptr_ = nullptr;
-  }
+  explicit Value(List &&list);
 
   /// @brief Constructs a Map value from the copy of the given `map`.
-  explicit Value(const Map &map) : ptr_(mgp::value_make_map(map.ptr_)) {}
+  explicit Value(const Map &map);
   /// @brief Constructs a Map value and takes ownership of the given `map`.
   /// @note The behavior of accessing `map` after performing this operation is undefined.
-  explicit Value(Map &&map) {
-    ptr_ = mgp::value_make_map(map.ptr_);
-    delete &map;
-    map.ptr_ = nullptr;
-  }
+  explicit Value(Map &&map);
 
   // Graph element type constructors:
 
   /// @brief Constructs a Node value from the copy of the given `node`.
-  explicit Value(const Node &node) : ptr_(mgp::value_make_vertex(node.ptr_)) {}
+  explicit Value(const Node &node);
   /// @brief Constructs a Node value and takes ownership of the given `node`.
   /// @note The behavior of accessing `node` after performing this operation is undefined.
-  explicit Value(Node &&node) {
-    ptr_ = mgp::value_make_vertex(const_cast<mgp_vertex *>(node.ptr_));
-    delete &node;
-    node.ptr_ = nullptr;
-  }
+  explicit Value(Node &&node);
 
   /// @brief Constructs a Relationship value from the copy of the given `node`.
-  explicit Value(const Relationship &relationship) : ptr_(mgp::value_make_edge(relationship.ptr_)) {}
+  explicit Value(const Relationship &relationship);
   /// @brief Constructs a Relationship value and takes ownership of the given `relationship`.
   /// @note The behavior of accessing `relationship` after performing this operation is undefined.
-  explicit Value(Relationship &&relationship) {
-    ptr_ = mgp::value_make_edge(relationship.ptr_);
-    delete &relationship;
-    relationship.ptr_ = nullptr;
-  }
+  explicit Value(Relationship &&relationship);
 
   /// @brief Constructs a Path value from the copy of the given `path`.
-  explicit Value(const Path &path) : ptr_(mgp::value_make_path(path.ptr_)) {}
+  explicit Value(const Path &path);
   /// @brief Constructs a Path value and takes ownership of the given `path`.
   /// @note The behavior of accessing `path` after performing this operation is undefined.
-  explicit Value(Path &&path) {
-    ptr_ = mgp::value_make_path(path.ptr_);
-    delete &path;
-    path.ptr_ = nullptr;
-  }
+  explicit Value(Path &&path);
 
   // Temporal type constructors:
 
   /// @brief Constructs a Date value from the copy of the given `date`.
-  explicit Value(const Date &date) : ptr_(mgp::value_make_date(date.ptr_)) {}
+  explicit Value(const Date &date);
   /// @brief Constructs a Date value and takes ownership of the given `path`.
   /// @note The behavior of accessing `date` after performing this operation is undefined.
-  explicit Value(Date &&date) {
-    ptr_ = mgp::value_make_date(date.ptr_);
-    delete &date;
-    date.ptr_ = nullptr;
-  }
+  explicit Value(Date &&date);
 
   /// @brief Constructs a LocalTime value from the copy of the given `local_time`.
-  explicit Value(const LocalTime &local_time) : ptr_(mgp::value_make_local_time(local_time.ptr_)) {}
+  explicit Value(const LocalTime &local_time);
   /// @brief Constructs a LocalTime value and takes ownership of the given `local_time`.
   /// @note The behavior of accessing `local_time` after performing this operation is undefined.
-  explicit Value(LocalTime &&local_time) {
-    ptr_ = mgp::value_make_local_time(local_time.ptr_);
-    delete &local_time;
-    local_time.ptr_ = nullptr;
-  }
+  explicit Value(LocalTime &&local_time);
 
   /// @brief Constructs a LocalDateTime value from the copy of the given `local_date_time`.
-  explicit Value(const LocalDateTime &local_date_time) : ptr_(mgp::value_make_local_date_time(local_date_time.ptr_)) {}
-
+  explicit Value(const LocalDateTime &local_date_time);
   /// @brief Constructs a LocalDateTime value and takes ownership of the given `local_date_time`.
   /// @note The behavior of accessing `local_date_time` after performing this operation is undefined.
-  explicit Value(LocalDateTime &&local_date_time) {
-    ptr_ = mgp::value_make_local_date_time(local_date_time.ptr_);
-    delete &local_date_time;
-    local_date_time.ptr_ = nullptr;
-  }
+  explicit Value(LocalDateTime &&local_date_time);
 
   /// @brief Constructs a Duration value from the copy of the given `duration`.
-  explicit Value(const Duration &duration) : ptr_(mgp::value_make_duration(duration.ptr_)) {}
+  explicit Value(const Duration &duration);
   /// @brief Constructs a Duration value and takes ownership of the given `duration`.
   /// @note The behavior of accessing `duration` after performing this operation is undefined.
-  explicit Value(Duration &&duration) {
-    ptr_ = mgp::value_make_duration(duration.ptr_);
-    delete &duration;
-    duration.ptr_ = nullptr;
-  }
+  explicit Value(Duration &&duration);
 
-  Value(const Value &other) : Value(other.ptr_) {}
-  Value(Value &&other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; }
+  Value(const Value &other);
+  Value(Value &&other) noexcept;
+
+  Value &operator=(const Value &other) noexcept;
+  Value &operator=(Value &&other) noexcept;
 
   ~Value();
 
   /// @brief Returns the pointer to the stored value.
-  mgp_value *ptr() const { return ptr_; }
+  mgp_value *ptr() const;
 
   /// @brief Returns the type of the value.
   /// @exception std::runtime_error The value type is unknown.
@@ -1392,7 +1134,7 @@ class Value {
   /// @exception std::runtime_error Unknown value type.
   bool operator==(const Value &other) const;
   /// @exception std::runtime_error Unknown value type.
-  bool operator!=(const Value &other) const { return !(*this == other); }
+  bool operator!=(const Value &other) const;
 
  private:
   mgp_value *ptr_;
@@ -1406,7 +1148,7 @@ struct MapItem {
   bool operator==(MapItem &other) const;
   bool operator!=(MapItem &other) const;
 
-  bool operator<(const MapItem &other) const { return key < other.key; }
+  bool operator<(const MapItem &other) const;
 };
 
 /* #endregion */
@@ -1416,7 +1158,7 @@ struct MapItem {
 /// @brief Procedure result class
 class Record {
  public:
-  explicit Record(mgp_result_record *record) : record_(record) {}
+  explicit Record(mgp_result_record *record);
 
   /// @brief Inserts a boolean value under field `field_name`.
   void Insert(const char *field_name, bool value);
@@ -1454,12 +1196,13 @@ class Record {
 /// @brief Factory class for @ref Record
 class RecordFactory {
  public:
-  explicit RecordFactory(mgp_result *result) : result_(result) {}
-  RecordFactory(RecordFactory const &) = delete;
+  explicit RecordFactory(mgp_result *result);
 
-  const mgp::Record NewRecord() const;
+  const Record NewRecord() const;
 
-  void operator=(RecordFactory const &) = delete;
+  void SetErrorMessage(const std::string_view error_msg) const;
+
+  void SetErrorMessage(const char *error_msg) const;
 
  private:
   mgp_result *result_;
@@ -1468,8 +1211,7 @@ class RecordFactory {
 /// @brief Function result class
 class Result {
  public:
-  explicit Result(mgp_func_result *result) : result_(result) {}
-  Result(Result const &) = delete;
+  explicit Result(mgp_func_result *result);
 
   /// @brief Sets a boolean value to be returned.
   inline void SetValue(bool value);
@@ -1500,7 +1242,9 @@ class Result {
   /// @brief Sets a @ref Duration value to be returned.
   inline void SetValue(const Duration &duration);
 
-  void operator=(Result const &) = delete;
+  void SetErrorMessage(const std::string_view error_msg) const;
+
+  void SetErrorMessage(const char *error_msg) const;
 
  private:
   mgp_func_result *result_;
@@ -1522,43 +1266,31 @@ class Parameter {
   Value default_value;
 
   /// @brief Creates a non-optional parameter with the given `name` and `type`.
-  Parameter(std::string_view name, Type type) : name(name), type_(type) {}
+  Parameter(std::string_view name, Type type);
 
   /// @brief Creates an optional boolean parameter with the given `name` and `default_value`.
-  Parameter(std::string_view name, Type type, bool default_value)
-      : name(name), type_(type), optional(true), default_value(Value(default_value)) {}
+  Parameter(std::string_view name, Type type, bool default_value);
 
   /// @brief Creates an optional integer parameter with the given `name` and `default_value`.
-  Parameter(std::string_view name, Type type, int64_t default_value)
-      : name(name), type_(type), optional(true), default_value(Value(default_value)) {}
+  Parameter(std::string_view name, Type type, int64_t default_value);
 
   /// @brief Creates an optional floating-point parameter with the given `name` and `default_value`.
-  Parameter(std::string_view name, Type type, double default_value)
-      : name(name), type_(type), optional(true), default_value(Value(default_value)) {}
+  Parameter(std::string_view name, Type type, double default_value);
 
   /// @brief Creates an optional string parameter with the given `name` and `default_value`.
-  Parameter(std::string_view name, Type type, std::string_view default_value)
-      : name(name), type_(type), optional(true), default_value(Value(default_value)) {}
+  Parameter(std::string_view name, Type type, std::string_view default_value);
 
   /// @brief Creates an optional string parameter with the given `name` and `default_value`.
-  Parameter(std::string_view name, Type type, const char *default_value)
-      : name(name), type_(type), optional(true), default_value(Value(default_value)) {}
+  Parameter(std::string_view name, Type type, const char *default_value);
 
   /// @brief Creates an optional parameter with the given `name` and `default_value`.
-  Parameter(std::string_view name, Type type, mgp::Value default_value)
-      : name(name), type_(type), optional(true), default_value(default_value) {}
+  Parameter(std::string_view name, Type type, Value default_value);
 
   /// @brief Creates a non-optional ListParameter with the given `name` and `item_type`.
-  Parameter(std::string_view name, std::pair<Type, Type> list_type)
-      : name(name), type_(list_type.first), list_item_type_(list_type.second) {}
+  Parameter(std::string_view name, std::pair<Type, Type> list_type);
 
   /// @brief Creates an optional List parameter with the given `name`, `item_type`, and `default_value`.
-  Parameter(std::string_view name, std::pair<Type, Type> list_type, mgp::Value default_value)
-      : name(name),
-        type_(list_type.first),
-        list_item_type_(list_type.second),
-        optional(true),
-        default_value(default_value) {}
+  Parameter(std::string_view name, std::pair<Type, Type> list_type, Value default_value);
 
   mgp_type *GetMGPType() const;
 };
@@ -1571,15 +1303,14 @@ class Return {
   Type list_item_type_;
 
   /// @brief Creates a return value with the given `name` and `type`.
-  Return(std::string_view name, mgp::Type type) : name(name), type_(type) {}
+  Return(std::string_view name, Type type);
 
-  Return(std::string_view name, std::pair<Type, Type> list_type)
-      : name(name), type_(list_type.first), list_item_type_(list_type.second) {}
+  Return(std::string_view name, std::pair<Type, Type> list_type);
 
   mgp_type *GetMGPType() const;
 };
 
-enum class ProdecureType : uint8_t {
+enum class ProcedureType : uint8_t {
   Read,
   Write,
 };
@@ -1592,9 +1323,9 @@ enum class ProdecureType : uint8_t {
 /// @param returns - procedure return values
 /// @param module - the query module that the procedure is added to
 /// @param memory - access to memory
-void AddProcedure(mgp_proc_cb callback, std::string_view name, ProdecureType proc_type,
-                  std::vector<mgp::Parameter> parameters, std::vector<Return> returns, mgp_module *module,
-                  mgp_memory *memory);
+inline void AddProcedure(mgp_proc_cb callback, std::string_view name, ProcedureType proc_type,
+                         std::vector<Parameter> parameters, std::vector<Return> returns, mgp_module *module,
+                         mgp_memory *memory);
 
 /// @brief Adds a function to the query module.
 /// @param callback - function callback
@@ -1602,12 +1333,25 @@ void AddProcedure(mgp_proc_cb callback, std::string_view name, ProdecureType pro
 /// @param parameters - function parameters
 /// @param module - the query module that the function is added to
 /// @param memory - access to memory
-void AddFunction(mgp_func_cb callback, std::string_view name, std::vector<mgp::Parameter> parameters,
-                 std::vector<Return> returns, mgp_module *module, mgp_memory *memory);
+inline void AddFunction(mgp_func_cb callback, std::string_view name, std::vector<Parameter> parameters,
+                        mgp_module *module, mgp_memory *memory);
 
 /* #endregion */
 
 namespace util {
+// uint to int conversion in C++ is a bit tricky. Take a look here
+// https://stackoverflow.com/questions/14623266/why-cant-i-reinterpret-cast-uint-to-int
+// for more details.
+template <typename TDest, typename TSrc>
+TDest MemcpyCast(TSrc src) {
+  TDest dest;
+  static_assert(sizeof(dest) == sizeof(src), "MemcpyCast expects source and destination to be of the same size");
+  static_assert(std::is_arithmetic<TSrc>::value, "MemcpyCast expects source to be an arithmetic type");
+  static_assert(std::is_arithmetic<TDest>::value, "MemcpyCast expects destination to be an arithmetic type");
+  std::memcpy(&dest, &src, sizeof(src));
+  return dest;
+}
+
 /// @brief Returns whether two MGP API values are equal.
 inline bool ValuesEqual(mgp_value *value1, mgp_value *value2);
 
@@ -1828,9 +1572,29 @@ inline Type ToAPIType(mgp_value_type type) {
 
 /* #region Graph (Id, Graph, Nodes, GraphRelationships, Relationships, Properties & Labels) */
 
+// Id:
+
+inline Id Id::FromUint(uint64_t id) { return Id(util::MemcpyCast<int64_t>(id)); }
+
+inline Id Id::FromInt(int64_t id) { return Id(id); }
+
+inline int64_t Id::AsInt() const { return id_; }
+
+inline uint64_t Id::AsUint() const { return util::MemcpyCast<uint64_t>(id_); }
+
+inline bool Id::operator==(const Id &other) const { return id_ == other.id_; }
+
+inline bool Id::operator!=(const Id &other) const { return !(*this == other); }
+
+inline bool Id::operator<(const Id &other) const { return id_ < other.id_; }
+
+inline Id::Id(int64_t id) : id_(id) {}
+
 // Graph:
 
-int64_t Graph::Order() const {
+inline Graph::Graph(mgp_graph *graph) : graph_(graph) {}
+
+inline int64_t Graph::Order() const {
   int64_t i = 0;
   for (const auto _ : Nodes()) {
     i++;
@@ -1838,7 +1602,7 @@ int64_t Graph::Order() const {
   return i;
 }
 
-int64_t Graph::Size() const {
+inline int64_t Graph::Size() const {
   int64_t i = 0;
   for (const auto _ : Relationships()) {
     i++;
@@ -1867,7 +1631,7 @@ inline Node Graph::GetNodeById(const Id node_id) const {
   return node;
 }
 
-bool Graph::ContainsNode(const Id node_id) const {
+inline bool Graph::ContainsNode(const Id node_id) const {
   auto mgp_node = mgp::graph_get_vertex_by_id(graph_, mgp_vertex_id{.as_int = node_id.AsInt()}, memory);
   if (mgp_node == nullptr) {
     return false;
@@ -1877,9 +1641,9 @@ bool Graph::ContainsNode(const Id node_id) const {
   return true;
 }
 
-bool Graph::ContainsNode(const Node &node) const { return ContainsNode(node.Id()); }
+inline bool Graph::ContainsNode(const Node &node) const { return ContainsNode(node.Id()); }
 
-bool Graph::ContainsRelationship(const Id relationship_id) const {
+inline bool Graph::ContainsRelationship(const Id relationship_id) const {
   for (const auto &graph_relationship : Relationships()) {
     if (graph_relationship.Id() == relationship_id) {
       return true;
@@ -1888,7 +1652,7 @@ bool Graph::ContainsRelationship(const Id relationship_id) const {
   return false;
 }
 
-bool Graph::ContainsRelationship(const Relationship &relationship) const {
+inline bool Graph::ContainsRelationship(const Relationship &relationship) const {
   for (const auto &graph_relationship : Relationships()) {
     if (relationship == graph_relationship) {
       return true;
@@ -1897,7 +1661,9 @@ bool Graph::ContainsRelationship(const Relationship &relationship) const {
   return false;
 }
 
-Node Graph::CreateNode() {
+inline bool Graph::IsMutable() const { return mgp::graph_is_mutable(graph_); }
+
+inline Node Graph::CreateNode() {
   auto *vertex = mgp::graph_create_vertex(graph_, memory);
   auto node = Node(vertex);
 
@@ -1906,11 +1672,11 @@ Node Graph::CreateNode() {
   return node;
 }
 
-void Graph::DeleteNode(const Node &node) { mgp::graph_delete_vertex(graph_, node.ptr_); }
+inline void Graph::DeleteNode(const Node &node) { mgp::graph_delete_vertex(graph_, node.ptr_); }
 
-void Graph::DetachDeleteNode(const Node &node) { mgp::graph_detach_delete_vertex(graph_, node.ptr_); };
+inline void Graph::DetachDeleteNode(const Node &node) { mgp::graph_detach_delete_vertex(graph_, node.ptr_); };
 
-Relationship Graph::CreateRelationship(const Node &from, const Node &to, const std::string_view type) {
+inline Relationship Graph::CreateRelationship(const Node &from, const Node &to, const std::string_view type) {
   auto *edge = mgp::graph_create_edge(graph_, from.ptr_, to.ptr_, mgp_edge_type{.name = type.data()}, memory);
   auto relationship = Relationship(edge);
 
@@ -1919,24 +1685,189 @@ Relationship Graph::CreateRelationship(const Node &from, const Node &to, const s
   return relationship;
 }
 
-void Graph::DeleteRelationship(const Relationship &relationship) { mgp::graph_delete_edge(graph_, relationship.ptr_); }
+inline void Graph::DeleteRelationship(const Relationship &relationship) {
+  mgp::graph_delete_edge(graph_, relationship.ptr_);
+}
 
 // Nodes:
 
+inline Nodes::Nodes(mgp_vertices_iterator *nodes_iterator) : nodes_iterator_(nodes_iterator) {}
+
+inline Nodes::Iterator::Iterator(mgp_vertices_iterator *nodes_iterator) : nodes_iterator_(nodes_iterator) {
+  if (nodes_iterator_ == nullptr) {
+    return;
+  }
+
+  if (mgp::vertices_iterator_get(nodes_iterator_) == nullptr) {
+    mgp::vertices_iterator_destroy(nodes_iterator_);
+    nodes_iterator_ = nullptr;
+  }
+}
+
+inline Nodes::Iterator::Iterator(const Iterator &other) : Iterator(other.nodes_iterator_) {}
+
+inline Nodes::Iterator::~Iterator() {
+  if (nodes_iterator_ != nullptr) {
+    mgp::vertices_iterator_destroy(nodes_iterator_);
+  }
+}
+
+inline Nodes::Iterator &Nodes::Iterator::operator++() {
+  if (nodes_iterator_ != nullptr) {
+    auto next = mgp::vertices_iterator_next(nodes_iterator_);
+
+    if (next == nullptr) {
+      mgp::vertices_iterator_destroy(nodes_iterator_);
+      nodes_iterator_ = nullptr;
+      return *this;
+    }
+    index_++;
+  }
+  return *this;
+}
+
+inline Nodes::Iterator Nodes::Iterator::operator++(int) {
+  auto retval = *this;
+  ++*this;
+  return retval;
+}
+
+inline bool Nodes::Iterator::operator==(Iterator other) const {
+  if (nodes_iterator_ == nullptr && other.nodes_iterator_ == nullptr) {
+    return true;
+  }
+  if (nodes_iterator_ == nullptr || other.nodes_iterator_ == nullptr) {
+    return false;
+  }
+  return mgp::vertex_equal(mgp::vertices_iterator_get(nodes_iterator_),
+                           mgp::vertices_iterator_get(other.nodes_iterator_)) &&
+         index_ == other.index_;
+}
+
+inline bool Nodes::Iterator::operator!=(Iterator other) const { return !(*this == other); }
+
 inline const Node Nodes::Iterator::operator*() const {
   if (nodes_iterator_ == nullptr) {
     return Node((const mgp_vertex *)nullptr);
-    // current_node = Node((const mgp_vertex *)nullptr);
-    // return current_node;
   }
 
-  // auto node = Node(mgp::vertices_iterator_get(nodes_iterator_));
-  // current_node = Node(mgp::vertices_iterator_get(nodes_iterator_));
   return Node(mgp::vertices_iterator_get(nodes_iterator_));
 }
 
+inline Nodes::Iterator Nodes::begin() const { return Iterator(nodes_iterator_); }
+
+inline Nodes::Iterator Nodes::end() const { return Iterator(nullptr); }
+
+inline Nodes::Iterator Nodes::cbegin() const { return Iterator(nodes_iterator_); }
+
+inline Nodes::Iterator Nodes::cend() const { return Iterator(nullptr); }
+
 // GraphRelationships:
 
+inline GraphRelationships::GraphRelationships(mgp_graph *graph) : graph_(graph) {}
+
+inline GraphRelationships::Iterator::Iterator(mgp_vertices_iterator *nodes_iterator) : nodes_iterator_(nodes_iterator) {
+  // Positions the iterator over the first existing relationship
+
+  if (nodes_iterator_ == nullptr) {
+    return;
+  }
+
+  // Go through each graph node’s adjacent nodes
+  for (auto node = mgp::vertices_iterator_get(nodes_iterator_); node;
+       node = mgp::vertices_iterator_next(nodes_iterator_)) {
+    // Check if node exists
+    if (node == nullptr) {
+      mgp::vertices_iterator_destroy(nodes_iterator_);
+      nodes_iterator_ = nullptr;
+      return;
+    }
+
+    // Check if node has out-relationships
+    out_relationships_iterator_ = mgp::vertex_iter_out_edges(node, memory);
+    auto relationship = mgp::edges_iterator_get(out_relationships_iterator_);
+    if (relationship != nullptr) {
+      return;
+    }
+
+    mgp::edges_iterator_destroy(out_relationships_iterator_);
+    out_relationships_iterator_ = nullptr;
+  }
+}
+
+inline GraphRelationships::Iterator::Iterator(const Iterator &other) : Iterator(other.nodes_iterator_) {}
+
+inline GraphRelationships::Iterator::~Iterator() {
+  if (nodes_iterator_ != nullptr) {
+    mgp::vertices_iterator_destroy(nodes_iterator_);
+  }
+  if (out_relationships_iterator_ != nullptr) {
+    mgp::edges_iterator_destroy(out_relationships_iterator_);
+  }
+}
+
+inline GraphRelationships::Iterator &GraphRelationships::Iterator::operator++() {
+  // Moves the iterator onto the next existing relationship
+
+  // 1. Check if the current node has remaining relationships to iterate over
+
+  if (out_relationships_iterator_ != nullptr) {
+    auto next = mgp::edges_iterator_next(out_relationships_iterator_);
+
+    if (next == nullptr) {
+      mgp::edges_iterator_destroy(out_relationships_iterator_);
+      out_relationships_iterator_ = nullptr;
+    }
+  }
+
+  // 2. Move onto the next nodes
+
+  if (nodes_iterator_ != nullptr) {
+    for (auto node = mgp::vertices_iterator_next(nodes_iterator_); node;
+         node = mgp::vertices_iterator_next(nodes_iterator_)) {
+      // Check if node exists - if it doesn’t, we’ve reached the end of the iterator
+      if (node == nullptr) {
+        mgp::vertices_iterator_destroy(nodes_iterator_);
+        nodes_iterator_ = nullptr;
+        return *this;
+      }
+
+      // Check if node has out-relationships
+      out_relationships_iterator_ = mgp::vertex_iter_out_edges(node, memory);
+      auto relationship = mgp::edges_iterator_get(out_relationships_iterator_);
+      if (relationship != nullptr) {
+        return *this;
+      }
+
+      mgp::edges_iterator_destroy(out_relationships_iterator_);
+      out_relationships_iterator_ = nullptr;
+    }
+  }
+  mgp::vertices_iterator_destroy(nodes_iterator_);
+  nodes_iterator_ = nullptr;
+  return *this;
+}
+
+inline GraphRelationships::Iterator GraphRelationships::Iterator::operator++(int) {
+  auto retval = *this;
+  ++*this;
+  return retval;
+}
+
+inline bool GraphRelationships::Iterator::operator==(Iterator other) const {
+  if (out_relationships_iterator_ == nullptr && other.out_relationships_iterator_ == nullptr) {
+    return true;
+  }
+  if (out_relationships_iterator_ == nullptr || other.out_relationships_iterator_ == nullptr) {
+    return false;
+  }
+  return mgp::edge_equal(mgp::edges_iterator_get(out_relationships_iterator_),
+                         mgp::edges_iterator_get(other.out_relationships_iterator_)) &&
+         index_ == other.index_;
+}
+
+inline bool GraphRelationships::Iterator::operator!=(Iterator other) const { return !(*this == other); }
+
 inline const Relationship GraphRelationships::Iterator::operator*() const {
   if (out_relationships_iterator_ != nullptr) {
     return Relationship(mgp::edges_iterator_get(out_relationships_iterator_));
@@ -1945,8 +1876,76 @@ inline const Relationship GraphRelationships::Iterator::operator*() const {
   return Relationship((mgp_edge *)nullptr);
 }
 
+inline GraphRelationships::Iterator GraphRelationships::begin() const {
+  return Iterator(mgp::graph_iter_vertices(graph_, memory));
+}
+
+inline GraphRelationships::Iterator GraphRelationships::end() const { return Iterator(nullptr); }
+
+inline GraphRelationships::Iterator GraphRelationships::cbegin() const {
+  return Iterator(mgp::graph_iter_vertices(graph_, memory));
+}
+
+inline GraphRelationships::Iterator GraphRelationships::cend() const { return Iterator(nullptr); }
+
 // Relationships:
 
+inline Relationships::Relationships(mgp_edges_iterator *relationships_iterator)
+    : relationships_iterator_(relationships_iterator) {}
+
+inline Relationships::Iterator::Iterator(mgp_edges_iterator *relationships_iterator)
+    : relationships_iterator_(relationships_iterator) {
+  if (relationships_iterator_ == nullptr) {
+    return;
+  }
+  if (mgp::edges_iterator_get(relationships_iterator_) == nullptr) {
+    mgp::edges_iterator_destroy(relationships_iterator_);
+    relationships_iterator_ = nullptr;
+  }
+}
+
+inline Relationships::Iterator::Iterator(const Iterator &other) : Iterator(other.relationships_iterator_) {}
+
+inline Relationships::Iterator::~Iterator() {
+  if (relationships_iterator_ != nullptr) {
+    mgp::edges_iterator_destroy(relationships_iterator_);
+  }
+}
+
+inline Relationships::Iterator &Relationships::Iterator::operator++() {
+  if (relationships_iterator_ != nullptr) {
+    auto next = mgp::edges_iterator_next(relationships_iterator_);
+
+    if (next == nullptr) {
+      mgp::edges_iterator_destroy(relationships_iterator_);
+      relationships_iterator_ = nullptr;
+      return *this;
+    }
+    index_++;
+  }
+  return *this;
+}
+
+inline Relationships::Iterator Relationships::Iterator::operator++(int) {
+  auto retval = *this;
+  ++*this;
+  return retval;
+}
+
+inline bool Relationships::Iterator::operator==(Iterator other) const {
+  if (relationships_iterator_ == nullptr && other.relationships_iterator_ == nullptr) {
+    return true;
+  }
+  if (relationships_iterator_ == nullptr || other.relationships_iterator_ == nullptr) {
+    return false;
+  }
+  return mgp::edge_equal(mgp::edges_iterator_get(relationships_iterator_),
+                         mgp::edges_iterator_get(other.relationships_iterator_)) &&
+         index_ == other.index_;
+}
+
+inline bool Relationships::Iterator::operator!=(Iterator other) const { return !(*this == other); }
+
 inline const Relationship Relationships::Iterator::operator*() const {
   if (relationships_iterator_ == nullptr) {
     return Relationship((mgp_edge *)nullptr);
@@ -1956,6 +1955,14 @@ inline const Relationship Relationships::Iterator::operator*() const {
   return relationship;
 }
 
+inline Relationships::Iterator Relationships::begin() const { return Iterator(relationships_iterator_); }
+
+inline Relationships::Iterator Relationships::end() const { return Iterator(nullptr); }
+
+inline Relationships::Iterator Relationships::cbegin() const { return Iterator(relationships_iterator_); }
+
+inline Relationships::Iterator Relationships::cend() const { return Iterator(nullptr); }
+
 // Properties:
 
 inline Properties::Properties(mgp_properties_iterator *properties_iterator) {
@@ -1967,15 +1974,84 @@ inline Properties::Properties(mgp_properties_iterator *properties_iterator) {
   mgp::properties_iterator_destroy(properties_iterator);
 }
 
+inline size_t Properties::Size() const { return property_map_.size(); }
+
+inline bool Properties::Empty() const { return Size() == 0; }
+
 inline Value Properties::operator[](const std::string_view key) const { return property_map_.at(key); }
 
+inline std::map<std::string_view, Value>::const_iterator Properties::begin() const { return property_map_.begin(); }
+
+inline std::map<std::string_view, Value>::const_iterator Properties::end() const { return property_map_.end(); }
+
+inline std::map<std::string_view, Value>::const_iterator Properties::cbegin() const { return property_map_.cbegin(); }
+
+inline std::map<std::string_view, Value>::const_iterator Properties::cend() const { return property_map_.cend(); }
+
 inline bool Properties::operator==(const Properties &other) const { return property_map_ == other.property_map_; }
 
+inline bool Properties::operator!=(const Properties &other) const { return !(*this == other); }
+
 // Labels:
 
+inline Labels::Labels(mgp_vertex *node_ptr) : node_ptr_(mgp::vertex_copy(node_ptr, memory)) {}
+
+inline Labels::Labels(const Labels &other) : Labels(other.node_ptr_) {}
+
+inline Labels::Labels(Labels &&other) noexcept : node_ptr_(other.node_ptr_) { other.node_ptr_ = nullptr; }
+
+inline Labels &Labels::operator=(const Labels &other) noexcept {
+  if (this != &other) {
+    mgp::vertex_destroy(node_ptr_);
+
+    node_ptr_ = mgp::vertex_copy(other.node_ptr_, memory);
+  }
+  return *this;
+}
+
+inline Labels &Labels::operator=(Labels &&other) noexcept {
+  if (this != &other) {
+    mgp::vertex_destroy(node_ptr_);
+
+    node_ptr_ = other.node_ptr_;
+    other.node_ptr_ = nullptr;
+  }
+  return *this;
+}
+
+inline Labels::~Labels() {
+  if (node_ptr_ != nullptr) {
+    mgp::vertex_destroy(node_ptr_);
+  }
+}
+
+inline bool Labels::Iterator::operator==(const Iterator &other) const {
+  return iterable_ == other.iterable_ && index_ == other.index_;
+}
+
+inline bool Labels::Iterator::operator!=(const Iterator &other) const { return !(*this == other); }
+
+inline Labels::Iterator &Labels::Iterator::operator++() {
+  index_++;
+  return *this;
+}
+
 inline const std::string_view Labels::Iterator::operator*() const { return (*iterable_)[index_]; }
 
+inline Labels::Iterator::Iterator(const Labels *iterable, size_t index) : iterable_(iterable), index_(index) {}
+
+inline size_t Labels::Size() const { return mgp::vertex_labels_count(node_ptr_); }
+
 inline std::string_view Labels::operator[](size_t index) const { return mgp::vertex_label_at(node_ptr_, index).name; }
+
+inline Labels::Iterator Labels::begin() { return Iterator(this, 0); }
+
+inline Labels::Iterator Labels::end() { return Iterator(this, Size()); }
+
+inline Labels::Iterator Labels::cbegin() { return Iterator(this, 0); }
+
+inline Labels::Iterator Labels::cend() { return Iterator(this, Size()); }
+
 /* #endregion */
 
 /* #region Types */
@@ -1984,6 +2060,14 @@ inline std::string_view Labels::operator[](size_t index) const { return mgp::ver
 
 // List:
 
+inline List::List(mgp_list *ptr) : ptr_(mgp::list_copy(ptr, memory)) {}
+
+inline List::List(const mgp_list *const_ptr) : ptr_(mgp::list_copy(const_cast<mgp_list *>(const_ptr), memory)) {}
+
+inline List::List() : ptr_(mgp::list_make_empty(0, memory)) {}
+
+inline List::List(size_t capacity) : ptr_(mgp::list_make_empty(capacity, memory)) {}
+
 inline List::List(const std::vector<Value> &values) : ptr_(mgp::list_make_empty(values.size(), memory)) {
   for (const auto &value : values) {
     AppendExtend(value);
@@ -2002,16 +2086,64 @@ inline List::List(const std::initializer_list<Value> values) : ptr_(mgp::list_ma
   }
 }
 
+inline List::List(const List &other) : List(other.ptr_) {}
+
+inline List::List(List &&other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; }
+
+inline List &List::operator=(const List &other) noexcept {
+  if (this != &other) {
+    mgp::list_destroy(ptr_);
+
+    ptr_ = mgp::list_copy(other.ptr_, memory);
+  }
+  return *this;
+}
+
+inline List &List::operator=(List &&other) noexcept {
+  if (this != &other) {
+    mgp::list_destroy(ptr_);
+
+    ptr_ = other.ptr_;
+    other.ptr_ = nullptr;
+  }
+  return *this;
+}
+
 inline List::~List() {
   if (ptr_ != nullptr) {
     mgp::list_destroy(ptr_);
   }
 }
 
+inline size_t List::Size() const { return mgp::list_size(ptr_); }
+
+inline bool List::Empty() const { return Size() == 0; }
+
 inline const Value List::operator[](size_t index) const { return Value(mgp::list_at(ptr_, index)); }
 
+inline bool List::Iterator::operator==(const Iterator &other) const {
+  return iterable_ == other.iterable_ && index_ == other.index_;
+}
+
+inline bool List::Iterator::operator!=(const Iterator &other) const { return !(*this == other); }
+
+inline List::Iterator &List::Iterator::operator++() {
+  index_++;
+  return *this;
+}
+
 inline const Value List::Iterator::operator*() const { return (*iterable_)[index_]; }
 
+inline List::Iterator::Iterator(const List *iterable, size_t index) : iterable_(iterable), index_(index) {}
+
+inline List::Iterator List::begin() const { return Iterator(this, 0); }
+
+inline List::Iterator List::end() const { return Iterator(this, Size()); }
+
+inline List::Iterator List::cbegin() const { return Iterator(this, 0); }
+
+inline List::Iterator List::cend() const { return Iterator(this, Size()); }
+
 inline void List::Append(const Value &value) { mgp::list_append(ptr_, value.ptr_); }
 
 inline void List::Append(Value &&value) {
@@ -2021,20 +2153,28 @@ inline void List::Append(Value &&value) {
 
 inline void List::AppendExtend(const Value &value) { mgp::list_append_extend(ptr_, value.ptr_); }
 
-inline void List::AppendExtend(Value &&value) {
-  mgp::list_append_extend(ptr_, value.ptr_);
-  value.ptr_ = nullptr;
-}
+inline void List::AppendExtend(Value &&value) { mgp::list_append_extend(ptr_, value.ptr_); }
 
 inline bool List::operator==(const List &other) const { return util::ListsEqual(ptr_, other.ptr_); }
 
+inline bool List::operator!=(const List &other) const { return !(*this == other); }
+
 // MapItem:
 
 inline bool MapItem::operator==(MapItem &other) const { return key == other.key && value == other.value; }
+
 inline bool MapItem::operator!=(MapItem &other) const { return !(*this == other); }
 
+inline bool MapItem::operator<(const MapItem &other) const { return key < other.key; }
+
 // Map:
 
+inline Map::Map(mgp_map *ptr) : ptr_(mgp::map_copy(ptr, memory)) {}
+
+inline Map::Map(const mgp_map *const_ptr) : ptr_(mgp::map_copy(const_cast<mgp_map *>(const_ptr), memory)) {}
+
+inline Map::Map() : ptr_(mgp::map_make_empty(memory)) {}
+
 inline Map::Map(const std::map<std::string_view, Value> &items) : ptr_(mgp::map_make_empty(memory)) {
   for (const auto &[key, value] : items) {
     Insert(key, value);
@@ -2054,16 +2194,90 @@ inline Map::Map(const std::initializer_list<std::pair<std::string_view, Value>>
   }
 }
 
+inline Map::Map(const Map &other) : Map(other.ptr_) {}
+
+inline Map::Map(Map &&other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; }
+
+inline Map &Map::operator=(const Map &other) noexcept {
+  if (this != &other) {
+    mgp::map_destroy(ptr_);
+
+    ptr_ = mgp::map_copy(other.ptr_, memory);
+  }
+  return *this;
+}
+
+inline Map &Map::operator=(Map &&other) noexcept {
+  if (this != &other) {
+    mgp::map_destroy(ptr_);
+
+    ptr_ = other.ptr_;
+    other.ptr_ = nullptr;
+  }
+  return *this;
+}
+
 inline Map::~Map() {
   if (ptr_ != nullptr) {
     mgp::map_destroy(ptr_);
   }
 }
 
+inline size_t Map::Size() const { return mgp::map_size(ptr_); }
+
+inline bool Map::Empty() const { return Size() == 0; }
+
 inline const Value Map::operator[](std::string_view key) const { return Value(mgp::map_at(ptr_, key.data())); }
 
 inline const Value Map::At(std::string_view key) const { return Value(mgp::map_at(ptr_, key.data())); }
 
+inline Map::Iterator::Iterator(mgp_map_items_iterator *map_items_iterator) : map_items_iterator_(map_items_iterator) {
+  if (map_items_iterator_ == nullptr) return;
+  if (mgp::map_items_iterator_get(map_items_iterator_) == nullptr) {
+    mgp::map_items_iterator_destroy(map_items_iterator_);
+    map_items_iterator_ = nullptr;
+  }
+}
+
+inline Map::Iterator::Iterator(const Iterator &other) : Iterator(other.map_items_iterator_) {}
+
+inline Map::Iterator::~Iterator() {
+  if (map_items_iterator_ != nullptr) {
+    mgp::map_items_iterator_destroy(map_items_iterator_);
+  }
+}
+
+inline Map::Iterator &Map::Iterator::operator++() {
+  if (map_items_iterator_ != nullptr) {
+    auto next = mgp::map_items_iterator_next(map_items_iterator_);
+
+    if (next == nullptr) {
+      mgp::map_items_iterator_destroy(map_items_iterator_);
+      map_items_iterator_ = nullptr;
+      return *this;
+    }
+  }
+  return *this;
+}
+
+inline Map::Iterator Map::Iterator::operator++(int) {
+  auto retval = *this;
+  ++*this;
+  return retval;
+}
+
+inline bool Map::Iterator::operator==(Iterator other) const {
+  if (map_items_iterator_ == nullptr && other.map_items_iterator_ == nullptr) {
+    return true;
+  }
+  if (map_items_iterator_ == nullptr || other.map_items_iterator_ == nullptr) {
+    return false;
+  }
+  return mgp::map_items_iterator_get(map_items_iterator_) == mgp::map_items_iterator_get(other.map_items_iterator_);
+}
+
+inline bool Map::Iterator::operator!=(Iterator other) const { return !(*this == other); }
+
 inline const MapItem Map::Iterator::operator*() const {
   if (map_items_iterator_ == nullptr) {
     throw ValueException("Empty map item!");
@@ -2077,6 +2291,14 @@ inline const MapItem Map::Iterator::operator*() const {
   return MapItem{.key = map_key, .value = map_value};
 }
 
+inline Map::Iterator Map::begin() const { return Iterator(mgp::map_iter_items(ptr_, memory)); }
+
+inline Map::Iterator Map::end() const { return Iterator(nullptr); }
+
+inline Map::Iterator Map::cbegin() const { return Iterator(mgp::map_iter_items(ptr_, memory)); }
+
+inline Map::Iterator Map::cend() const { return Iterator(nullptr); }
+
 inline void Map::Insert(std::string_view key, const Value &value) { mgp::map_insert(ptr_, key.data(), value.ptr_); }
 
 inline void Map::Insert(std::string_view key, Value &&value) {
@@ -2084,20 +2306,57 @@ inline void Map::Insert(std::string_view key, Value &&value) {
   value.ptr_ = nullptr;
 }
 
+inline std::map<std::string_view, Value>::const_iterator Properties::find(const std::string_view key) const {
+  return property_map_.find(key);
+}
+
 inline bool Map::operator==(const Map &other) const { return util::MapsEqual(ptr_, other.ptr_); }
 
+inline bool Map::operator!=(const Map &other) const { return !(*this == other); }
+
 /* #endregion */
 
 /* #region Graph elements (Node, Relationship & Path) */
 
 // Node:
 
+inline Node::Node(mgp_vertex *ptr) : ptr_(mgp::vertex_copy(ptr, memory)) {}
+
+inline Node::Node(const mgp_vertex *const_ptr) : ptr_(mgp::vertex_copy(const_cast<mgp_vertex *>(const_ptr), memory)) {}
+
+inline Node::Node(const Node &other) : Node(other.ptr_) {}
+
+inline Node::Node(Node &&other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; }
+
+inline Node &Node::operator=(const Node &other) noexcept {
+  if (this != &other) {
+    mgp::vertex_destroy(ptr_);
+
+    ptr_ = mgp::vertex_copy(other.ptr_, memory);
+  }
+  return *this;
+}
+
+inline Node &Node::operator=(Node &&other) noexcept {
+  if (this != &other) {
+    mgp::vertex_destroy(ptr_);
+
+    ptr_ = other.ptr_;
+    other.ptr_ = nullptr;
+  }
+  return *this;
+}
+
 inline Node::~Node() {
   if (ptr_ != nullptr) {
     mgp::vertex_destroy(ptr_);
   }
 }
 
+inline mgp::Id Node::Id() const { return Id::FromInt(mgp::vertex_get_id(ptr_).as_int); }
+
+inline class Labels Node::Labels() const { return mgp::Labels(ptr_); }
+
 inline bool Node::HasLabel(std::string_view label) const {
   for (const auto node_label : Labels()) {
     if (label == node_label) {
@@ -2107,6 +2366,8 @@ inline bool Node::HasLabel(std::string_view label) const {
   return false;
 }
 
+inline class Properties Node::Properties() const { return mgp::Properties(mgp::vertex_iter_properties(ptr_, memory)); }
+
 inline Value Node::operator[](const std::string_view property_name) const { return Properties()[property_name]; }
 
 inline Relationships Node::InRelationships() const {
@@ -2129,36 +2390,111 @@ inline void Node::AddLabel(const std::string_view label) {
   mgp::vertex_add_label(this->ptr_, mgp_label{.name = label.data()});
 }
 
+inline bool Node::operator<(const Node &other) const { return Id() < other.Id(); }
+
 inline bool Node::operator==(const Node &other) const { return util::NodesEqual(ptr_, other.ptr_); }
 
+inline bool Node::operator!=(const Node &other) const { return !(*this == other); }
+
 // Relationship:
 
+inline Relationship::Relationship(mgp_edge *ptr) : ptr_(mgp::edge_copy(ptr, memory)) {}
+
+inline Relationship::Relationship(const mgp_edge *const_ptr)
+    : ptr_(mgp::edge_copy(const_cast<mgp_edge *>(const_ptr), memory)) {}
+
+inline Relationship::Relationship(const Relationship &other) : Relationship(other.ptr_) {}
+
+inline Relationship::Relationship(Relationship &&other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; }
+
+inline Relationship &Relationship::operator=(const Relationship &other) noexcept {
+  if (this != &other) {
+    mgp::edge_destroy(ptr_);
+
+    ptr_ = mgp::edge_copy(other.ptr_, memory);
+  }
+  return *this;
+}
+
+inline Relationship &Relationship::operator=(Relationship &&other) noexcept {
+  if (this != &other) {
+    mgp::edge_destroy(ptr_);
+
+    ptr_ = other.ptr_;
+    other.ptr_ = nullptr;
+  }
+  return *this;
+}
+
 inline Relationship::~Relationship() {
   if (ptr_ != nullptr) {
     mgp::edge_destroy(ptr_);
   }
 }
 
+inline mgp::Id Relationship::Id() const { return Id::FromInt(mgp::edge_get_id(ptr_).as_int); }
+
 inline std::string_view Relationship::Type() const { return mgp::edge_get_type(ptr_).name; }
 
+inline class Properties Relationship::Properties() const {
+  return mgp::Properties(mgp::edge_iter_properties(ptr_, memory));
+}
+
 inline Value Relationship::operator[](const std::string_view property_name) const {
   return Properties()[property_name];
 }
 
+inline Node Relationship::From() const { return Node(mgp::edge_get_from(ptr_)); }
+
+inline Node Relationship::To() const { return Node(mgp::edge_get_to(ptr_)); }
+
+inline bool Relationship::operator<(const Relationship &other) const { return Id() < other.Id(); }
+
 inline bool Relationship::operator==(const Relationship &other) const {
   return util::RelationshipsEqual(ptr_, other.ptr_);
 }
 
+inline bool Relationship::operator!=(const Relationship &other) const { return !(*this == other); }
+
 // Path:
 
+inline Path::Path(mgp_path *ptr) : ptr_(mgp::path_copy(ptr, memory)) {}
+
+inline Path::Path(const mgp_path *const_ptr) : ptr_(mgp::path_copy(const_cast<mgp_path *>(const_ptr), memory)) {}
+
 inline Path::Path(const Node &start_node) : ptr_(mgp::path_make_with_start(start_node.ptr_, memory)) {}
 
+inline Path::Path(const Path &other) : Path(other.ptr_) {}
+
+inline Path::Path(Path &&other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; }
+
+inline Path &Path::operator=(const Path &other) noexcept {
+  if (this != &other) {
+    mgp::path_destroy(ptr_);
+
+    ptr_ = mgp::path_copy(other.ptr_, memory);
+  }
+  return *this;
+}
+
+inline Path &Path::operator=(Path &&other) noexcept {
+  if (this != &other) {
+    mgp::path_destroy(ptr_);
+
+    ptr_ = other.ptr_;
+    other.ptr_ = nullptr;
+  }
+  return *this;
+}
+
 inline Path::~Path() {
   if (ptr_ != nullptr) {
     mgp::path_destroy(ptr_);
   }
 }
 
+inline size_t Path::Length() const { return mgp::path_size(ptr_); }
+
 inline Node Path::GetNodeAt(size_t index) const {
   auto node_ptr = mgp::path_vertex_at(ptr_, index);
   if (node_ptr == nullptr) {
@@ -2178,17 +2514,48 @@ inline Relationship Path::GetRelationshipAt(size_t index) const {
 inline void Path::Expand(const Relationship &relationship) { mgp::path_expand(ptr_, relationship.ptr_); }
 
 inline bool Path::operator==(const Path &other) const { return util::PathsEqual(ptr_, other.ptr_); }
+
+inline bool Path::operator!=(const Path &other) const { return !(*this == other); }
 /* #endregion */
 
 /* #region Temporal types (Date, LocalTime, LocalDateTime, Duration) */
 
 // Date:
 
+inline Date::Date(mgp_date *ptr) : ptr_(mgp::date_copy(ptr, memory)) {}
+
+inline Date::Date(const mgp_date *const_ptr) : ptr_(mgp::date_copy(const_cast<mgp_date *>(const_ptr), memory)) {}
+
+inline Date::Date(std::string_view string) : ptr_(mgp::date_from_string(string.data(), memory)) {}
+
 inline Date::Date(int year, int month, int day) {
   mgp_date_parameters params{.year = year, .month = month, .day = day};
   ptr_ = mgp::date_from_parameters(&params, memory);
 }
 
+inline Date::Date(const Date &other) : Date(other.ptr_) {}
+
+inline Date::Date(Date &&other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; }
+
+inline Date &Date::operator=(const Date &other) noexcept {
+  if (this != &other) {
+    mgp::date_destroy(ptr_);
+
+    ptr_ = mgp::date_copy(other.ptr_, memory);
+  }
+  return *this;
+}
+
+inline Date &Date::operator=(Date &&other) noexcept {
+  if (this != &other) {
+    mgp::date_destroy(ptr_);
+
+    ptr_ = other.ptr_;
+    other.ptr_ = nullptr;
+  }
+  return *this;
+}
+
 inline Date::~Date() {
   if (ptr_ != nullptr) {
     mgp::date_destroy(ptr_);
@@ -2203,6 +2570,14 @@ inline Date Date::Now() {
   return date;
 }
 
+inline int Date::Year() const { return mgp::date_get_year(ptr_); }
+
+inline int Date::Month() const { return mgp::date_get_month(ptr_); }
+
+inline int Date::Day() const { return mgp::date_get_day(ptr_); }
+
+inline int64_t Date::Timestamp() const { return mgp::date_timestamp(ptr_); }
+
 inline bool Date::operator==(const Date &other) const { return util::DatesEqual(ptr_, other.ptr_); }
 
 inline Date Date::operator+(const Duration &dur) const {
@@ -2239,12 +2614,42 @@ inline bool Date::operator<(const Date &other) const {
 
 // LocalTime:
 
+inline LocalTime::LocalTime(mgp_local_time *ptr) : ptr_(mgp::local_time_copy(ptr, memory)) {}
+
+inline LocalTime::LocalTime(const mgp_local_time *const_ptr)
+    : ptr_(mgp::local_time_copy(const_cast<mgp_local_time *>(const_ptr), memory)) {}
+
+inline LocalTime::LocalTime(std::string_view string) : ptr_(mgp::local_time_from_string(string.data(), memory)) {}
+
 inline LocalTime::LocalTime(int hour, int minute, int second, int millisecond, int microsecond) {
   mgp_local_time_parameters params{
       .hour = hour, .minute = minute, .second = second, .millisecond = millisecond, .microsecond = microsecond};
   ptr_ = mgp::local_time_from_parameters(&params, memory);
 }
 
+inline LocalTime::LocalTime(const LocalTime &other) : LocalTime(other.ptr_) {}
+
+inline LocalTime::LocalTime(LocalTime &&other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; };
+
+inline LocalTime &LocalTime::operator=(const LocalTime &other) noexcept {
+  if (this != &other) {
+    mgp::local_time_destroy(ptr_);
+
+    ptr_ = mgp::local_time_copy(other.ptr_, memory);
+  }
+  return *this;
+}
+
+inline LocalTime &LocalTime::operator=(LocalTime &&other) noexcept {
+  if (this != &other) {
+    mgp::local_time_destroy(ptr_);
+
+    ptr_ = other.ptr_;
+    other.ptr_ = nullptr;
+  }
+  return *this;
+}
+
 inline LocalTime::~LocalTime() {
   if (ptr_ != nullptr) {
     mgp::local_time_destroy(ptr_);
@@ -2259,6 +2664,18 @@ inline LocalTime LocalTime::Now() {
   return local_time;
 }
 
+inline int LocalTime::Hour() const { return mgp::local_time_get_hour(ptr_); }
+
+inline int LocalTime::Minute() const { return mgp::local_time_get_minute(ptr_); }
+
+inline int LocalTime::Second() const { return mgp::local_time_get_second(ptr_); }
+
+inline int LocalTime::Millisecond() const { return mgp::local_time_get_millisecond(ptr_); }
+
+inline int LocalTime::Microsecond() const { return mgp::local_time_get_microsecond(ptr_); }
+
+inline int64_t LocalTime::Timestamp() const { return mgp::local_time_timestamp(ptr_); }
+
 inline bool LocalTime::operator==(const LocalTime &other) const { return util::LocalTimesEqual(ptr_, other.ptr_); }
 
 inline LocalTime LocalTime::operator+(const Duration &dur) const {
@@ -2295,6 +2712,14 @@ inline bool LocalTime::operator<(const LocalTime &other) const {
 
 // LocalDateTime:
 
+inline LocalDateTime::LocalDateTime(mgp_local_date_time *ptr) : ptr_(mgp::local_date_time_copy(ptr, memory)) {}
+
+inline LocalDateTime::LocalDateTime(const mgp_local_date_time *const_ptr)
+    : ptr_(mgp::local_date_time_copy(const_cast<mgp_local_date_time *>(const_ptr), memory)) {}
+
+inline LocalDateTime::LocalDateTime(std::string_view string)
+    : ptr_(mgp::local_date_time_from_string(string.data(), memory)) {}
+
 inline LocalDateTime::LocalDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond,
                                     int microsecond) {
   struct mgp_date_parameters date_params {
@@ -2307,6 +2732,29 @@ inline LocalDateTime::LocalDateTime(int year, int month, int day, int hour, int
   ptr_ = mgp::local_date_time_from_parameters(&params, memory);
 }
 
+inline LocalDateTime::LocalDateTime(const LocalDateTime &other) : LocalDateTime(other.ptr_) {}
+
+inline LocalDateTime::LocalDateTime(LocalDateTime &&other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; };
+
+inline LocalDateTime &LocalDateTime::operator=(const LocalDateTime &other) noexcept {
+  if (this != &other) {
+    mgp::local_date_time_destroy(ptr_);
+
+    ptr_ = mgp::local_date_time_copy(other.ptr_, memory);
+  }
+  return *this;
+}
+
+inline LocalDateTime &LocalDateTime::operator=(LocalDateTime &&other) noexcept {
+  if (this != &other) {
+    mgp::local_date_time_destroy(ptr_);
+
+    ptr_ = other.ptr_;
+    other.ptr_ = nullptr;
+  }
+  return *this;
+}
+
 inline LocalDateTime::~LocalDateTime() {
   if (ptr_ != nullptr) {
     mgp::local_date_time_destroy(ptr_);
@@ -2321,6 +2769,24 @@ inline LocalDateTime LocalDateTime::Now() {
   return local_date_time;
 }
 
+inline int LocalDateTime::Year() const { return mgp::local_date_time_get_year(ptr_); }
+
+inline int LocalDateTime::Month() const { return mgp::local_date_time_get_month(ptr_); }
+
+inline int LocalDateTime::Day() const { return mgp::local_date_time_get_day(ptr_); }
+
+inline int LocalDateTime::Hour() const { return mgp::local_date_time_get_hour(ptr_); }
+
+inline int LocalDateTime::Minute() const { return mgp::local_date_time_get_minute(ptr_); }
+
+inline int LocalDateTime::Second() const { return mgp::local_date_time_get_second(ptr_); }
+
+inline int LocalDateTime::Millisecond() const { return mgp::local_date_time_get_millisecond(ptr_); }
+
+inline int LocalDateTime::Microsecond() const { return mgp::local_date_time_get_microsecond(ptr_); }
+
+inline int64_t LocalDateTime::Timestamp() const { return mgp::local_date_time_timestamp(ptr_); }
+
 inline bool LocalDateTime::operator==(const LocalDateTime &other) const {
   return util::LocalDateTimesEqual(ptr_, other.ptr_);
 }
@@ -2359,6 +2825,15 @@ inline bool LocalDateTime::operator<(const LocalDateTime &other) const {
 
 // Duration:
 
+inline Duration::Duration(mgp_duration *ptr) : ptr_(mgp::duration_copy(ptr, memory)) {}
+
+inline Duration::Duration(const mgp_duration *const_ptr)
+    : ptr_(mgp::duration_copy(const_cast<mgp_duration *>(const_ptr), memory)) {}
+
+inline Duration::Duration(std::string_view string) : ptr_(mgp::duration_from_string(string.data(), memory)) {}
+
+inline Duration::Duration(int64_t microseconds) : ptr_(mgp::duration_from_microseconds(microseconds, memory)) {}
+
 inline Duration::Duration(double day, double hour, double minute, double second, double millisecond,
                           double microsecond) {
   mgp_duration_parameters params{.day = day,
@@ -2370,12 +2845,37 @@ inline Duration::Duration(double day, double hour, double minute, double second,
   ptr_ = mgp::duration_from_parameters(&params, memory);
 }
 
+inline Duration::Duration(const Duration &other) : Duration(other.ptr_) {}
+
+inline Duration::Duration(Duration &&other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; };
+
+inline Duration &Duration::operator=(const Duration &other) noexcept {
+  if (this != &other) {
+    mgp::duration_destroy(ptr_);
+
+    ptr_ = mgp::duration_copy(other.ptr_, memory);
+  }
+  return *this;
+}
+
+inline Duration &Duration::operator=(Duration &&other) noexcept {
+  if (this != &other) {
+    mgp::duration_destroy(ptr_);
+
+    ptr_ = other.ptr_;
+    other.ptr_ = nullptr;
+  }
+  return *this;
+}
+
 inline Duration::~Duration() {
   if (ptr_ != nullptr) {
     mgp::duration_destroy(ptr_);
   }
 }
 
+inline int64_t Duration::Microseconds() const { return mgp::duration_get_microseconds(ptr_); }
+
 inline bool Duration::operator==(const Duration &other) const { return util::DurationsEqual(ptr_, other.ptr_); }
 
 inline Duration Duration::operator+(const Duration &other) const {
@@ -2393,6 +2893,7 @@ inline Duration Duration::operator-(const Duration &other) const {
 
   return difference;
 }
+
 inline Duration Duration::operator-() const {
   auto mgp_neg = mgp::duration_neg(ptr_, memory);
   auto neg = Duration(mgp_neg);
@@ -2414,13 +2915,120 @@ inline bool Duration::operator<(const Duration &other) const {
 /* #endregion */
 
 /* #region Value */
+
+inline Value::Value(mgp_value *ptr) : ptr_(mgp::value_copy(ptr, memory)) {}
+
+inline Value::Value() : ptr_(mgp::value_make_null(memory)) {}
+
+inline Value::Value(const bool value) : ptr_(mgp::value_make_bool(value, memory)) {}
+
+inline Value::Value(const int64_t value) : ptr_(mgp::value_make_int(value, memory)) {}
+
+inline Value::Value(const double value) : ptr_(mgp::value_make_double(value, memory)) {}
+
+inline Value::Value(const char *value) : ptr_(mgp::value_make_string(value, memory)) {}
+
+inline Value::Value(const std::string_view value) : ptr_(mgp::value_make_string(value.data(), memory)) {}
+
+inline Value::Value(const List &list) : ptr_(mgp::value_make_list(mgp::list_copy(list.ptr_, memory))) {}
+
+inline Value::Value(List &&list) {
+  ptr_ = mgp::value_make_list(list.ptr_);
+  list.ptr_ = nullptr;
+}
+
+inline Value::Value(const Map &map) : ptr_(mgp::value_make_map(mgp::map_copy(map.ptr_, memory))) {}
+
+inline Value::Value(Map &&map) {
+  ptr_ = mgp::value_make_map(map.ptr_);
+  map.ptr_ = nullptr;
+}
+
+inline Value::Value(const Node &node) : ptr_(mgp::value_make_vertex(mgp::vertex_copy(node.ptr_, memory))) {}
+
+inline Value::Value(Node &&node) {
+  ptr_ = mgp::value_make_vertex(const_cast<mgp_vertex *>(node.ptr_));
+  node.ptr_ = nullptr;
+}
+
+inline Value::Value(const Relationship &relationship)
+    : ptr_(mgp::value_make_edge(mgp::edge_copy(relationship.ptr_, memory))) {}
+
+inline Value::Value(Relationship &&relationship) {
+  ptr_ = mgp::value_make_edge(const_cast<mgp_edge *>(relationship.ptr_));
+  relationship.ptr_ = nullptr;
+}
+
+inline Value::Value(const Path &path) : ptr_(mgp::value_make_path(mgp::path_copy(path.ptr_, memory))) {}
+
+inline Value::Value(Path &&path) {
+  ptr_ = mgp::value_make_path(path.ptr_);
+  path.ptr_ = nullptr;
+}
+
+inline Value::Value(const Date &date) : ptr_(mgp::value_make_date(mgp::date_copy(date.ptr_, memory))) {}
+
+inline Value::Value(Date &&date) {
+  ptr_ = mgp::value_make_date(date.ptr_);
+  date.ptr_ = nullptr;
+}
+
+inline Value::Value(const LocalTime &local_time)
+    : ptr_(mgp::value_make_local_time(mgp::local_time_copy(local_time.ptr_, memory))) {}
+
+inline Value::Value(LocalTime &&local_time) {
+  ptr_ = mgp::value_make_local_time(local_time.ptr_);
+  local_time.ptr_ = nullptr;
+}
+
+inline Value::Value(const LocalDateTime &local_date_time)
+    : ptr_(mgp::value_make_local_date_time(mgp::local_date_time_copy(local_date_time.ptr_, memory))) {}
+
+inline Value::Value(LocalDateTime &&local_date_time) {
+  ptr_ = mgp::value_make_local_date_time(local_date_time.ptr_);
+  local_date_time.ptr_ = nullptr;
+}
+
+inline Value::Value(const Duration &duration)
+    : ptr_(mgp::value_make_duration(mgp::duration_copy(duration.ptr_, memory))) {}
+
+inline Value::Value(Duration &&duration) {
+  ptr_ = mgp::value_make_duration(duration.ptr_);
+  duration.ptr_ = nullptr;
+}
+
+inline Value::Value(const Value &other) : Value(other.ptr_) {}
+
+inline Value::Value(Value &&other) noexcept : ptr_(other.ptr_) { other.ptr_ = nullptr; }
+
+inline Value &Value::operator=(const Value &other) noexcept {
+  if (this != &other) {
+    mgp::value_destroy(ptr_);
+
+    ptr_ = mgp::value_copy(other.ptr_, memory);
+  }
+  return *this;
+}
+
+inline Value &Value::operator=(Value &&other) noexcept {
+  if (this != &other) {
+    mgp::value_destroy(ptr_);
+
+    ptr_ = other.ptr_;
+    other.ptr_ = nullptr;
+  }
+  return *this;
+}
+
 inline Value::~Value() {
   if (ptr_ != nullptr) {
     mgp::value_destroy(ptr_);
   }
 }
 
-inline Type Value::Type() const { return util::ToAPIType(mgp::value_get_type(ptr_)); }
+inline mgp_value *Value::ptr() const { return ptr_; }
+
+inline mgp::Type Value::Type() const { return util::ToAPIType(mgp::value_get_type(ptr_)); }
 
 inline bool Value::ValueBool() const {
   if (Type() != Type::Bool) {
@@ -2444,7 +3052,7 @@ inline double Value::ValueDouble() const {
 }
 
 inline double Value::ValueNumeric() const {
-  if (Type() != Type::Int || Type() != Type::Double) {
+  if (Type() != Type::Int && Type() != Type::Double) {
     throw ValueException("Type of value is wrong: expected Int or Double.");
   }
   if (Type() == Type::Int) {
@@ -2524,99 +3132,133 @@ inline const Duration Value::ValueDuration() const {
 }
 
 inline bool Value::IsNull() const { return mgp::value_is_null(ptr_); }
+
 inline bool Value::IsBool() const { return mgp::value_is_bool(ptr_); }
+
 inline bool Value::IsInt() const { return mgp::value_is_int(ptr_); }
+
 inline bool Value::IsDouble() const { return mgp::value_is_double(ptr_); }
+
 inline bool Value::IsNumeric() const { return IsInt() || IsDouble(); }
+
 inline bool Value::IsString() const { return mgp::value_is_string(ptr_); }
+
 inline bool Value::IsList() const { return mgp::value_is_list(ptr_); }
+
 inline bool Value::IsMap() const { return mgp::value_is_map(ptr_); }
+
 inline bool Value::IsNode() const { return mgp::value_is_vertex(ptr_); }
+
 inline bool Value::IsRelationship() const { return mgp::value_is_edge(ptr_); }
+
 inline bool Value::IsPath() const { return mgp::value_is_path(ptr_); }
+
 inline bool Value::IsDate() const { return mgp::value_is_date(ptr_); }
+
 inline bool Value::IsLocalTime() const { return mgp::value_is_local_time(ptr_); }
+
 inline bool Value::IsLocalDateTime() const { return mgp::value_is_local_date_time(ptr_); }
+
 inline bool Value::IsDuration() const { return mgp::value_is_duration(ptr_); }
 
 inline bool Value::operator==(const Value &other) const { return util::ValuesEqual(ptr_, other.ptr_); }
+
+inline bool Value::operator!=(const Value &other) const { return !(*this == other); }
 /* #endregion */
 
 /* #region Record */
 // Record:
 
+inline Record::Record(mgp_result_record *record) : record_(record) {}
+
 inline void Record::Insert(const char *field_name, bool value) {
   auto mgp_val = mgp::value_make_bool(value, memory);
   { mgp::result_record_insert(record_, field_name, mgp_val); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Record::Insert(const char *field_name, std::int64_t value) {
   auto mgp_val = mgp::value_make_int(value, memory);
   { mgp::result_record_insert(record_, field_name, mgp_val); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Record::Insert(const char *field_name, double value) {
   auto mgp_val = mgp::value_make_double(value, memory);
   { mgp::result_record_insert(record_, field_name, mgp_val); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Record::Insert(const char *field_name, std::string_view value) {
   auto mgp_val = mgp::value_make_string(value.data(), memory);
   { mgp::result_record_insert(record_, field_name, mgp_val); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Record::Insert(const char *field_name, const char *value) {
   auto mgp_val = mgp::value_make_string(value, memory);
   { mgp::result_record_insert(record_, field_name, mgp_val); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Record::Insert(const char *field_name, const List &list) {
   auto mgp_val = mgp::value_make_list(mgp::list_copy(list.ptr_, memory));
   { mgp::result_record_insert(record_, field_name, mgp_val); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Record::Insert(const char *field_name, const Map &map) {
   auto mgp_val = mgp::value_make_map(mgp::map_copy(map.ptr_, memory));
   { mgp::result_record_insert(record_, field_name, mgp_val); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Record::Insert(const char *field_name, const Node &node) {
   auto mgp_val = mgp::value_make_vertex(mgp::vertex_copy(node.ptr_, memory));
   { mgp::result_record_insert(record_, field_name, mgp_val); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Record::Insert(const char *field_name, const Relationship &relationship) {
   auto mgp_val = mgp::value_make_edge(mgp::edge_copy(relationship.ptr_, memory));
   { mgp::result_record_insert(record_, field_name, mgp_val); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Record::Insert(const char *field_name, const Path &path) {
   auto mgp_val = mgp::value_make_path(mgp::path_copy(path.ptr_, memory));
   { mgp::result_record_insert(record_, field_name, mgp_val); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Record::Insert(const char *field_name, const Date &date) {
   auto mgp_val = mgp::value_make_date(mgp::date_copy(date.ptr_, memory));
   { mgp::result_record_insert(record_, field_name, mgp_val); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Record::Insert(const char *field_name, const LocalTime &local_time) {
   auto mgp_val = mgp::value_make_local_time(mgp::local_time_copy(local_time.ptr_, memory));
   { mgp::result_record_insert(record_, field_name, mgp_val); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Record::Insert(const char *field_name, const LocalDateTime &local_date_time) {
   auto mgp_val = mgp::value_make_local_date_time(mgp::local_date_time_copy(local_date_time.ptr_, memory));
   { mgp::result_record_insert(record_, field_name, mgp_val); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Record::Insert(const char *field_name, const Duration &duration) {
   auto mgp_val = mgp::value_make_duration(mgp::duration_copy(duration.ptr_, memory));
   { mgp::result_record_insert(record_, field_name, mgp_val); }
   mgp::value_destroy(mgp_val);
 }
+
 // RecordFactory:
 
+inline RecordFactory::RecordFactory(mgp_result *result) : result_(result) {}
+
 inline const Record RecordFactory::NewRecord() const {
   auto record = mgp::result_new_record(result_);
   if (record == nullptr) {
@@ -2625,81 +3267,146 @@ inline const Record RecordFactory::NewRecord() const {
   return Record(record);
 }
 
+inline void RecordFactory::SetErrorMessage(const std::string_view error_msg) const {
+  mgp::result_set_error_msg(result_, error_msg.data());
+}
+
+inline void RecordFactory::SetErrorMessage(const char *error_msg) const {
+  mgp::result_set_error_msg(result_, error_msg);
+}
+
+// Result:
+
+inline Result::Result(mgp_func_result *result) : result_(result) {}
+
 inline void Result::SetValue(bool value) {
   auto mgp_val = mgp::value_make_bool(value, memory);
   { mgp::func_result_set_value(result_, mgp_val, memory); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Result::SetValue(std::int64_t value) {
   auto mgp_val = mgp::value_make_int(value, memory);
   { mgp::func_result_set_value(result_, mgp_val, memory); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Result::SetValue(double value) {
   auto mgp_val = mgp::value_make_double(value, memory);
   { mgp::func_result_set_value(result_, mgp_val, memory); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Result::SetValue(std::string_view value) {
   auto mgp_val = mgp::value_make_string(value.data(), memory);
   { mgp::func_result_set_value(result_, mgp_val, memory); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Result::SetValue(const char *value) {
   auto mgp_val = mgp::value_make_string(value, memory);
   { mgp::func_result_set_value(result_, mgp_val, memory); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Result::SetValue(const List &list) {
   auto mgp_val = mgp::value_make_list(mgp::list_copy(list.ptr_, memory));
   { mgp::func_result_set_value(result_, mgp_val, memory); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Result::SetValue(const Map &map) {
   auto mgp_val = mgp::value_make_map(mgp::map_copy(map.ptr_, memory));
   { mgp::func_result_set_value(result_, mgp_val, memory); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Result::SetValue(const Node &node) {
   auto mgp_val = mgp::value_make_vertex(mgp::vertex_copy(node.ptr_, memory));
   { mgp::func_result_set_value(result_, mgp_val, memory); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Result::SetValue(const Relationship &relationship) {
   auto mgp_val = mgp::value_make_edge(mgp::edge_copy(relationship.ptr_, memory));
   { mgp::func_result_set_value(result_, mgp_val, memory); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Result::SetValue(const Path &path) {
   auto mgp_val = mgp::value_make_path(mgp::path_copy(path.ptr_, memory));
   { mgp::func_result_set_value(result_, mgp_val, memory); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Result::SetValue(const Date &date) {
   auto mgp_val = mgp::value_make_date(mgp::date_copy(date.ptr_, memory));
   { mgp::func_result_set_value(result_, mgp_val, memory); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Result::SetValue(const LocalTime &local_time) {
   auto mgp_val = mgp::value_make_local_time(mgp::local_time_copy(local_time.ptr_, memory));
   { mgp::func_result_set_value(result_, mgp_val, memory); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Result::SetValue(const LocalDateTime &local_date_time) {
   auto mgp_val = mgp::value_make_local_date_time(mgp::local_date_time_copy(local_date_time.ptr_, memory));
   { mgp::func_result_set_value(result_, mgp_val, memory); }
   mgp::value_destroy(mgp_val);
 }
+
 inline void Result::SetValue(const Duration &duration) {
   auto mgp_val = mgp::value_make_duration(mgp::duration_copy(duration.ptr_, memory));
   { mgp::func_result_set_value(result_, mgp_val, memory); }
   mgp::value_destroy(mgp_val);
 }
 
+inline void Result::SetErrorMessage(const std::string_view error_msg) const {
+  mgp::func_result_set_error_msg(result_, error_msg.data(), memory);
+}
+
+inline void Result::SetErrorMessage(const char *error_msg) const {
+  mgp::func_result_set_error_msg(result_, error_msg, memory);
+}
+
 /* #endregion */
 
 /* #region Module */
 
+// Parameter:
+
+inline Parameter::Parameter(std::string_view name, Type type) : name(name), type_(type) {}
+
+inline Parameter::Parameter(std::string_view name, Type type, bool default_value)
+    : name(name), type_(type), optional(true), default_value(Value(default_value)) {}
+
+inline Parameter::Parameter(std::string_view name, Type type, int64_t default_value)
+    : name(name), type_(type), optional(true), default_value(Value(default_value)) {}
+
+inline Parameter::Parameter(std::string_view name, Type type, double default_value)
+    : name(name), type_(type), optional(true), default_value(Value(default_value)) {}
+
+inline Parameter::Parameter(std::string_view name, Type type, std::string_view default_value)
+    : name(name), type_(type), optional(true), default_value(Value(default_value)) {}
+
+inline Parameter::Parameter(std::string_view name, Type type, const char *default_value)
+    : name(name), type_(type), optional(true), default_value(Value(default_value)) {}
+
+inline Parameter::Parameter(std::string_view name, Type type, Value default_value)
+    : name(name), type_(type), optional(true), default_value(default_value) {}
+
+inline Parameter::Parameter(std::string_view name, std::pair<Type, Type> list_type)
+    : name(name), type_(list_type.first), list_item_type_(list_type.second) {}
+
+inline Parameter::Parameter(std::string_view name, std::pair<Type, Type> list_type, Value default_value)
+    : name(name),
+      type_(list_type.first),
+      list_item_type_(list_type.second),
+      optional(true),
+      default_value(default_value) {}
+
 inline mgp_type *Parameter::GetMGPType() const {
   if (type_ == Type::List) {
     return mgp::type_list(util::ToMGPType(list_item_type_));
@@ -2708,6 +3415,13 @@ inline mgp_type *Parameter::GetMGPType() const {
   return util::ToMGPType(type_);
 }
 
+// Return:
+
+inline Return::Return(std::string_view name, Type type) : name(name), type_(type) {}
+
+inline Return::Return(std::string_view name, std::pair<Type, Type> list_type)
+    : name(name), type_(list_type.first), list_item_type_(list_type.second) {}
+
 inline mgp_type *Return::GetMGPType() const {
   if (type_ == Type::List) {
     return mgp::type_list(util::ToMGPType(list_item_type_));
@@ -2716,15 +3430,14 @@ inline mgp_type *Return::GetMGPType() const {
   return util::ToMGPType(type_);
 }
 
-void AddProcedure(mgp_proc_cb callback, std::string_view name, ProdecureType proc_type,
-                  std::vector<mgp::Parameter> parameters, std::vector<Return> returns, mgp_module *module,
+void AddProcedure(mgp_proc_cb callback, std::string_view name, ProcedureType proc_type,
+                  std::vector<Parameter> parameters, std::vector<Return> returns, mgp_module *module,
                   mgp_memory *memory) {
-  auto proc = (proc_type == ProdecureType::Read) ? mgp::module_add_read_procedure(module, name.data(), callback)
+  auto proc = (proc_type == ProcedureType::Read) ? mgp::module_add_read_procedure(module, name.data(), callback)
                                                  : mgp::module_add_write_procedure(module, name.data(), callback);
 
   for (const auto &parameter : parameters) {
     auto parameter_name = parameter.name.data();
-
     if (!parameter.optional) {
       mgp::proc_add_arg(proc, parameter_name, parameter.GetMGPType());
     } else {
@@ -2739,8 +3452,8 @@ void AddProcedure(mgp_proc_cb callback, std::string_view name, ProdecureType pro
   }
 }
 
-void AddFunction(mgp_func_cb callback, std::string_view name, std::vector<mgp::Parameter> parameters,
-                 mgp_module *module, mgp_memory *memory) {
+void AddFunction(mgp_func_cb callback, std::string_view name, std::vector<Parameter> parameters, mgp_module *module,
+                 mgp_memory *memory) {
   auto func = mgp::module_add_function(module, name.data(), callback);
 
   for (const auto &parameter : parameters) {
@@ -2755,6 +3468,7 @@ void AddFunction(mgp_func_cb callback, std::string_view name, std::vector<mgp::P
 }
 
 /* #endregion */
+
 }  // namespace mgp
 
 namespace std {
diff --git a/query_modules/example.cpp b/query_modules/example.cpp
index 4819cca3c..8e9e80007 100644
--- a/query_modules/example.cpp
+++ b/query_modules/example.cpp
@@ -69,7 +69,7 @@ extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *mem
   try {
     mgp::memory = memory;
 
-    AddProcedure(SampleReadProc, "return_true", mgp::ProdecureType::Read,
+    AddProcedure(SampleReadProc, "return_true", mgp::ProcedureType::Read,
                  {mgp::Parameter("param_1", mgp::Type::Int), mgp::Parameter("param_2", mgp::Type::Double, 2.3)},
                  {mgp::Return("out", mgp::Type::Bool)}, module, memory);
   } catch (const std::exception &e) {
@@ -79,7 +79,7 @@ extern "C" int mgp_init_module(struct mgp_module *module, struct mgp_memory *mem
   try {
     mgp::memory = memory;
 
-    mgp::AddProcedure(AddXNodes, "add_x_nodes", mgp::ProdecureType::Write, {mgp::Parameter("param_1", mgp::Type::Int)},
+    mgp::AddProcedure(AddXNodes, "add_x_nodes", mgp::ProcedureType::Write, {mgp::Parameter("param_1", mgp::Type::Int)},
                       {}, module, memory);
 
   } catch (const std::exception &e) {
diff --git a/tests/unit/cpp_api.cpp b/tests/unit/cpp_api.cpp
index ec1531b3e..f1344776b 100644
--- a/tests/unit/cpp_api.cpp
+++ b/tests/unit/cpp_api.cpp
@@ -113,8 +113,9 @@ TEST_F(CppApiTestFixture, TestList) {
   auto a = mgp::Value("a");
   list_2.Append(a);
   list_2.AppendExtend(a);
+  list_2.AppendExtend(mgp::Value("b"));
 
-  ASSERT_EQ(list_2.Size(), 2);
+  ASSERT_EQ(list_2.Size(), 3);
 
   std::vector<mgp::Value> values{mgp::Value("a"), mgp::Value("b"), mgp::Value("c")};
   auto list_3 = mgp::List(values);
@@ -123,6 +124,18 @@ TEST_F(CppApiTestFixture, TestList) {
 
   auto list_4 = mgp::List({mgp::Value("d"), mgp::Value("e"), mgp::Value("f")});
   ASSERT_EQ(list_4.Size(), 3);
+
+  // Use copy assignment
+  auto list_x = list_1;
+
+  // Use move assignment
+  std::vector<mgp::List> vector_x;
+  vector_x.push_back(mgp::List());
+
+  // Use Value copy constructor
+  auto value_x = mgp::Value(list_1);
+  // Use Value move constructor
+  auto value_y = mgp::Value(mgp::List());
 }
 
 TEST_F(CppApiTestFixture, TestMap) {
@@ -151,6 +164,20 @@ TEST_F(CppApiTestFixture, TestMap) {
   auto map_3 = mgp::Map({p_1, p_2});
 
   ASSERT_EQ(map_3.Size(), 2);
+
+  // Use copy assignment
+  auto map_x = map_1;
+
+  // Use move assignment
+  std::vector<mgp::Map> vector_x;
+  vector_x.push_back(mgp::Map());
+
+  // Use Value copy constructor
+  auto value_x = mgp::Value(map_1);
+  // Use Value move constructor
+  auto value_y = mgp::Value(mgp::Map());
+
+  auto value_z = value_x;
 }
 
 TEST_F(CppApiTestFixture, TestNode) {
@@ -186,6 +213,18 @@ TEST_F(CppApiTestFixture, TestNode) {
   }
 
   ASSERT_EQ(count_in_relationships, 0);
+
+  // Use copy assignment
+  auto node_x = node_1;
+
+  // Use move assignment
+  std::vector<mgp::Node> vector_x;
+  vector_x.push_back(graph.CreateNode());
+
+  // Use Value copy constructor
+  auto value_x = mgp::Value(node_1);
+  // Use Value move constructor
+  auto value_y = mgp::Value(graph.CreateNode());
 }
 
 TEST_F(CppApiTestFixture, TestNodeWithNeighbors) {
@@ -194,8 +233,10 @@ TEST_F(CppApiTestFixture, TestNodeWithNeighbors) {
 
   auto node_1 = graph.CreateNode();
   auto node_2 = graph.CreateNode();
+  auto node_3 = graph.CreateNode();
 
-  auto relationship = graph.CreateRelationship(node_1, node_2, "edge_type");
+  auto relationship_1 = graph.CreateRelationship(node_1, node_2, "edge_type");
+  auto relationship_2 = graph.CreateRelationship(node_1, node_3, "edge_type");
 
   int count_out_relationships = 0;
   int count_in_relationships = 0;
@@ -204,13 +245,13 @@ TEST_F(CppApiTestFixture, TestNodeWithNeighbors) {
       count_out_relationships++;
     }
 
-    for (const auto _ : node.OutRelationships()) {
+    for (const auto _ : node.InRelationships()) {
       count_in_relationships++;
     }
   }
 
-  ASSERT_EQ(count_out_relationships, 1);
-  ASSERT_EQ(count_in_relationships, 1);
+  ASSERT_EQ(count_out_relationships, 2);
+  ASSERT_EQ(count_in_relationships, 2);
 }
 
 TEST_F(CppApiTestFixture, TestRelationship) {
@@ -226,6 +267,18 @@ TEST_F(CppApiTestFixture, TestRelationship) {
   ASSERT_EQ(relationship.Properties().Size(), 0);
   ASSERT_EQ(relationship.From().Id(), node_1.Id());
   ASSERT_EQ(relationship.To().Id(), node_2.Id());
+
+  // Use copy assignment
+  auto relationship_x = relationship;
+
+  // Use move assignment
+  std::vector<mgp::Relationship> vector_x;
+  vector_x.push_back(graph.CreateRelationship(node_2, node_1, "relationship_x"));
+
+  // Use Value copy constructor
+  auto value_x = mgp::Value(relationship);
+  // Use Value move constructor
+  auto value_y = mgp::Value(graph.CreateRelationship(node_2, node_1, "edge_type"));
 }
 
 TEST_F(CppApiTestFixture, TestPath) {
@@ -247,6 +300,18 @@ TEST_F(CppApiTestFixture, TestPath) {
   ASSERT_EQ(path.Length(), 1);
   ASSERT_EQ(path.GetNodeAt(0).Id(), node_0.Id());
   ASSERT_EQ(path.GetRelationshipAt(0).Id(), relationship.Id());
+
+  // Use copy assignment
+  auto path_x = path;
+
+  // Use move assignment
+  std::vector<mgp::Path> vector_x;
+  vector_x.push_back(mgp::Path(node_0));
+
+  // Use Value copy constructor
+  auto value_x = mgp::Value(path);
+  // Use Value move constructor
+  auto value_y = mgp::Value(mgp::Path(node_0));
 }
 
 TEST_F(CppApiTestFixture, TestDate) {
@@ -262,6 +327,18 @@ TEST_F(CppApiTestFixture, TestDate) {
 
   ASSERT_EQ(date_1, date_2);
   ASSERT_NE(date_2, date_3);
+
+  // Use copy assignment
+  auto date_x = date_1;
+
+  // Use move assignment
+  std::vector<mgp::Date> vector_x;
+  vector_x.push_back(mgp::Date("2022-04-09"));
+
+  // Use Value copy constructor
+  auto value_x = mgp::Value(date_1);
+  // Use Value move constructor
+  auto value_y = mgp::Value(mgp::Date("2022-04-09"));
 }
 
 TEST_F(CppApiTestFixture, TestLocalTime) {
@@ -278,6 +355,18 @@ TEST_F(CppApiTestFixture, TestLocalTime) {
 
   ASSERT_EQ(lt_1, lt_2);
   ASSERT_NE(lt_2, lt_3);
+
+  // Use copy assignment
+  auto lt_x = lt_1;
+
+  // Use move assignment
+  std::vector<mgp::LocalTime> vector_x;
+  vector_x.push_back(mgp::LocalTime("09:15:00"));
+
+  // Use Value copy constructor
+  auto value_x = mgp::Value(lt_1);
+  // Use Value move constructor
+  auto value_y = mgp::Value(mgp::LocalTime("09:15:00"));
 }
 
 TEST_F(CppApiTestFixture, TestLocalDateTime) {
@@ -295,14 +384,38 @@ TEST_F(CppApiTestFixture, TestLocalDateTime) {
   ASSERT_EQ(ldt_1.Timestamp() >= 0, true);
 
   ASSERT_EQ(ldt_1, ldt_2);
+
+  // Use copy assignment
+  auto ldt_x = ldt_1;
+
+  // Use move assignment
+  std::vector<mgp::LocalDateTime> vector_x;
+  vector_x.push_back(mgp::LocalDateTime("2021-10-05T14:15:00"));
+
+  // Use Value copy constructor
+  auto value_x = mgp::Value(ldt_1);
+  // Use Value move constructor
+  auto value_y = mgp::Value(mgp::LocalDateTime("2021-10-05T14:15:00"));
 }
 
 TEST_F(CppApiTestFixture, TestDuration) {
-  auto duration_2 = mgp::Duration("PT2M2.33S");
-  auto duration_3 = mgp::Duration(1465355);
-  auto duration_4 = mgp::Duration(5, 14, 15, 0, 0, 0);
+  auto duration_1 = mgp::Duration("PT2M2.33S");
+  auto duration_2 = mgp::Duration(1465355);
+  auto duration_3 = mgp::Duration(5, 14, 15, 0, 0, 0);
 
-  ASSERT_EQ(duration_3.Microseconds(), 1465355);
+  ASSERT_EQ(duration_2.Microseconds(), 1465355);
+  ASSERT_NE(duration_1, duration_2);
   ASSERT_NE(duration_2, duration_3);
-  ASSERT_NE(duration_3, duration_4);
+
+  // Use copy assignment
+  auto duration_x = duration_1;
+
+  // Use move assignment
+  std::vector<mgp::Duration> vector_x;
+  vector_x.push_back(mgp::Duration("PT2M2.33S"));
+
+  // Use Value copy constructor
+  auto value_x = mgp::Value(duration_1);
+  // Use Value move constructor
+  auto value_y = mgp::Value(mgp::Duration("PT2M2.33S"));
 }