gqlite 1.5.1 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/Cargo.toml +10 -4
- data/ext/db-index/Cargo.toml +29 -0
- data/ext/db-index/src/hnsw/error.rs +66 -0
- data/ext/db-index/src/hnsw/graph_store.rs +272 -0
- data/ext/db-index/src/hnsw/id.rs +36 -0
- data/ext/db-index/src/hnsw/implementation.rs +1517 -0
- data/ext/db-index/src/hnsw/kernels.rs +1228 -0
- data/ext/db-index/src/hnsw/metric.rs +244 -0
- data/ext/db-index/src/hnsw/scalar.rs +72 -0
- data/ext/db-index/src/hnsw/simple_store.rs +140 -0
- data/ext/db-index/src/hnsw/store.rs +472 -0
- data/ext/db-index/src/hnsw/vector.rs +105 -0
- data/ext/db-index/src/hnsw/vectors.rs +568 -0
- data/ext/db-index/src/hnsw.rs +42 -0
- data/ext/db-index/src/lib.rs +3 -0
- data/ext/gqlitedb/Cargo.toml +19 -9
- data/ext/gqlitedb/benches/common/pokec.rs +62 -2
- data/ext/gqlitedb/benches/pokec_divan.rs +66 -2
- data/ext/gqlitedb/benches/pokec_iai.rs +60 -3
- data/ext/gqlitedb/release.toml +2 -2
- data/ext/gqlitedb/src/aggregators/arithmetic.rs +3 -1
- data/ext/gqlitedb/src/aggregators/containers.rs +1 -1
- data/ext/gqlitedb/src/aggregators/stats.rs +21 -12
- data/ext/gqlitedb/src/capi.rs +1 -1
- data/ext/gqlitedb/src/compiler/expression_analyser.rs +28 -20
- data/ext/gqlitedb/src/compiler/variables_manager.rs +97 -29
- data/ext/gqlitedb/src/compiler.rs +505 -225
- data/ext/gqlitedb/src/connection.rs +149 -11
- data/ext/gqlitedb/src/consts.rs +1 -2
- data/ext/gqlitedb/src/error.rs +123 -61
- data/ext/gqlitedb/src/functions/common.rs +39 -2
- data/ext/gqlitedb/src/functions/math.rs +8 -3
- data/ext/gqlitedb/src/functions/path.rs +48 -11
- data/ext/gqlitedb/src/functions/value.rs +1 -1
- data/ext/gqlitedb/src/functions.rs +23 -7
- data/ext/gqlitedb/src/graph.rs +1 -9
- data/ext/gqlitedb/src/interpreter/evaluators.rs +968 -130
- data/ext/gqlitedb/src/interpreter/instructions.rs +39 -2
- data/ext/gqlitedb/src/lib.rs +5 -4
- data/ext/gqlitedb/src/planner.rs +329 -0
- data/ext/gqlitedb/src/prelude.rs +3 -3
- data/ext/gqlitedb/src/store/pgrx.rs +1 -1
- data/ext/gqlitedb/src/store/postgres.rs +735 -7
- data/ext/gqlitedb/src/store/redb/hnsw_store.rs +702 -0
- data/ext/gqlitedb/src/store/redb/index.rs +274 -0
- data/ext/gqlitedb/src/store/redb.rs +1268 -113
- data/ext/gqlitedb/src/store/sqlbase/sqlmetadata.rs +28 -0
- data/ext/gqlitedb/src/store/sqlbase/sqlstore.rs +103 -0
- data/ext/gqlitedb/src/store/sqlbase.rs +146 -16
- data/ext/gqlitedb/src/store/sqlite.rs +569 -5
- data/ext/gqlitedb/src/store/vector_extract.rs +56 -0
- data/ext/gqlitedb/src/store.rs +123 -3
- data/ext/gqlitedb/src/tests/compiler.rs +207 -10
- data/ext/gqlitedb/src/tests/connection/postgres.rs +38 -3
- data/ext/gqlitedb/src/tests/connection/redb.rs +23 -0
- data/ext/gqlitedb/src/tests/connection/sqlite.rs +31 -0
- data/ext/gqlitedb/src/tests/connection.rs +61 -1
- data/ext/gqlitedb/src/tests/evaluators.rs +162 -7
- data/ext/gqlitedb/src/tests/parser.rs +54 -23
- data/ext/gqlitedb/src/tests/planner.rs +511 -0
- data/ext/gqlitedb/src/tests/store/postgres.rs +7 -0
- data/ext/gqlitedb/src/tests/store/redb.rs +8 -0
- data/ext/gqlitedb/src/tests/store/sqlite.rs +8 -0
- data/ext/gqlitedb/src/tests/store/vector_index/postgres.rs +182 -0
- data/ext/gqlitedb/src/tests/store/vector_index/redb.rs +386 -0
- data/ext/gqlitedb/src/tests/store/vector_index/sqlite.rs +166 -0
- data/ext/gqlitedb/src/tests/store/vector_index.rs +2313 -0
- data/ext/gqlitedb/src/tests/store.rs +78 -14
- data/ext/gqlitedb/src/tests/templates/ast.rs +92 -16
- data/ext/gqlitedb/src/tests/templates/programs.rs +14 -7
- data/ext/gqlitedb/src/tests.rs +15 -9
- data/ext/gqlitedb/src/utils.rs +6 -1
- data/ext/gqlitedb/src/value/compare.rs +61 -3
- data/ext/gqlitedb/src/value.rs +136 -7
- data/ext/gqlitedb/templates/sql/postgres/metadata_delete.sql +1 -0
- data/ext/gqlitedb/templates/sql/postgres/node_select.sql +1 -1
- data/ext/gqlitedb/templates/sql/sqlite/metadata_delete.sql +1 -0
- data/ext/gqliterb/src/lib.rs +53 -8
- data/ext/gqlparser/Cargo.toml +25 -0
- data/ext/gqlparser/README.MD +9 -0
- data/ext/gqlparser/benches/pokec_divan.rs +34 -0
- data/ext/gqlparser/src/common.rs +69 -0
- data/ext/gqlparser/src/gqls/ast.rs +69 -0
- data/ext/gqlparser/src/gqls/constraint.rs +79 -0
- data/ext/gqlparser/src/gqls/error.rs +22 -0
- data/ext/gqlparser/src/gqls/parser.rs +813 -0
- data/ext/gqlparser/src/gqls/prelude.rs +8 -0
- data/ext/gqlparser/src/gqls/properties.rs +115 -0
- data/ext/gqlparser/src/gqls/resolve.rs +207 -0
- data/ext/gqlparser/src/gqls.rs +265 -0
- data/ext/gqlparser/src/lib.rs +7 -0
- data/ext/gqlparser/src/oc/ast.rs +680 -0
- data/ext/gqlparser/src/oc/error.rs +172 -0
- data/ext/gqlparser/src/oc/lexer.rs +429 -0
- data/ext/gqlparser/src/oc/parser/tests.rs +2284 -0
- data/ext/gqlparser/src/oc/parser.rs +2005 -0
- data/ext/gqlparser/src/oc.rs +33 -0
- data/ext/gqlparser/src/prelude.rs +3 -0
- data/ext/graphcore/Cargo.toml +1 -0
- data/ext/graphcore/src/error.rs +26 -0
- data/ext/graphcore/src/graph.rs +177 -51
- data/ext/graphcore/src/lib.rs +4 -2
- data/ext/graphcore/src/open_cypher.rs +12 -0
- data/ext/graphcore/src/table.rs +50 -2
- data/ext/graphcore/src/timestamp.rs +127 -104
- data/ext/graphcore/src/value/tensor.rs +739 -0
- data/ext/graphcore/src/value/value_map.rs +1 -1
- data/ext/graphcore/src/value.rs +343 -19
- metadata +90 -22
- data/ext/gqlitedb/src/parser/ast.rs +0 -604
- data/ext/gqlitedb/src/parser/parser_impl.rs +0 -1213
- data/ext/gqlitedb/src/parser.rs +0 -4
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
use std::path::Path;
|
|
2
2
|
|
|
3
|
-
use crate::{prelude
|
|
3
|
+
use crate::{QueryResult, planner, prelude::*};
|
|
4
|
+
use substring::Substring;
|
|
4
5
|
use value::ValueTryIntoRef;
|
|
5
6
|
|
|
6
7
|
/// Backend
|
|
@@ -104,16 +105,126 @@ where
|
|
|
104
105
|
{
|
|
105
106
|
fn execute_oc_query(&self, query: &str, parameters: value::ValueMap) -> Result<QueryResult>
|
|
106
107
|
{
|
|
107
|
-
|
|
108
|
+
use gqlparser::oc::ErrorKind;
|
|
109
|
+
let queries = gqlparser::oc::parse_oc_query(query).map_err(|e| match e.error_kind()
|
|
110
|
+
{
|
|
111
|
+
ErrorKind::IntegerOverflow => error::CompileTimeError::IntegerOverflow {
|
|
112
|
+
text: query.substring(e.span().start, e.span().end).to_string(),
|
|
113
|
+
},
|
|
114
|
+
ErrorKind::FloatingPointOverflow => error::CompileTimeError::FloatingPointOverflow {
|
|
115
|
+
text: query.substring(e.span().start, e.span().end).to_string(),
|
|
116
|
+
},
|
|
117
|
+
ErrorKind::RequiresDirectedEdge => error::CompileTimeError::RequiresDirectedRelationship {
|
|
118
|
+
text: query.substring(e.span().start, e.span().end).to_string(),
|
|
119
|
+
span: e.span().clone(),
|
|
120
|
+
},
|
|
121
|
+
ErrorKind::NoSingleRelationshipType => error::CompileTimeError::NoSingleRelationshipType {
|
|
122
|
+
text: query.substring(e.span().start, e.span().end).to_string(),
|
|
123
|
+
span: e.span().clone(),
|
|
124
|
+
},
|
|
125
|
+
_ => error::CompileTimeError::ParseError {
|
|
126
|
+
error_kind: e.error_kind().clone(),
|
|
127
|
+
text: query.substring(e.span().start, e.span().end).to_string(),
|
|
128
|
+
span: e.span().clone(),
|
|
129
|
+
},
|
|
130
|
+
})?;
|
|
131
|
+
if consts::SHOW_AST
|
|
132
|
+
{
|
|
133
|
+
log::debug!("ast = {:#?}", queries);
|
|
134
|
+
}
|
|
108
135
|
let mut results = Vec::<QueryResult>::default();
|
|
109
136
|
for query in queries
|
|
110
137
|
{
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
138
|
+
match query
|
|
139
|
+
{
|
|
140
|
+
gqlparser::oc::ast::Query::Statements(stmts) =>
|
|
141
|
+
{
|
|
142
|
+
let logical_plans: Result<Vec<_>> = stmts.into_iter().map(planner::plan).collect();
|
|
143
|
+
let program = compiler::compile(&self.function_manager, logical_plans?)?;
|
|
144
|
+
results.push(interpreter::evaluators::eval_program(
|
|
145
|
+
&self.store,
|
|
146
|
+
&program,
|
|
147
|
+
¶meters,
|
|
148
|
+
)?)
|
|
149
|
+
}
|
|
150
|
+
gqlparser::oc::ast::Query::Union { branches, all } =>
|
|
151
|
+
{
|
|
152
|
+
// Evaluate each branch independently
|
|
153
|
+
let branch_results: Result<Vec<_>> = branches
|
|
154
|
+
.into_iter()
|
|
155
|
+
.map(|stmts| {
|
|
156
|
+
let logical_plans: Result<Vec<_>> = stmts.into_iter().map(planner::plan).collect();
|
|
157
|
+
let program = compiler::compile(&self.function_manager, logical_plans?)?;
|
|
158
|
+
interpreter::evaluators::eval_program(&self.store, &program, ¶meters)
|
|
159
|
+
})
|
|
160
|
+
.collect();
|
|
161
|
+
|
|
162
|
+
// Extract tables from results and validate headers
|
|
163
|
+
let branch_results = branch_results?;
|
|
164
|
+
let mut tables: Vec<graphcore::Table> = Vec::new();
|
|
165
|
+
let mut has_empty = false;
|
|
166
|
+
|
|
167
|
+
for result in branch_results
|
|
168
|
+
{
|
|
169
|
+
match result
|
|
170
|
+
{
|
|
171
|
+
QueryResult::Table(t) => tables.push(t),
|
|
172
|
+
QueryResult::Empty => has_empty = true,
|
|
173
|
+
_ => return Err(CompileTimeError::DifferentColumnsInUnion.into()),
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// If all branches are empty, return Empty
|
|
178
|
+
if tables.is_empty()
|
|
179
|
+
{
|
|
180
|
+
results.push(QueryResult::Empty);
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Validate that all tables have identical headers
|
|
185
|
+
let headers = tables[0].headers().clone();
|
|
186
|
+
for t in &tables[1..]
|
|
187
|
+
{
|
|
188
|
+
if t.headers() != &headers
|
|
189
|
+
{
|
|
190
|
+
return Err(CompileTimeError::DifferentColumnsInUnion.into());
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// If any branch was empty, that's a header mismatch
|
|
195
|
+
if has_empty
|
|
196
|
+
{
|
|
197
|
+
return Err(CompileTimeError::DifferentColumnsInUnion.into());
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Concatenate all row data
|
|
201
|
+
let mut data: Vec<graphcore::Value> = tables
|
|
202
|
+
.into_iter()
|
|
203
|
+
.flat_map(|t| t.into_row_iter().flatten())
|
|
204
|
+
.collect();
|
|
205
|
+
|
|
206
|
+
// UNION (distinct): deduplicate rows
|
|
207
|
+
if !all
|
|
208
|
+
{
|
|
209
|
+
let col_count = headers.len();
|
|
210
|
+
let mut result_rows: Vec<Vec<graphcore::Value>> = Vec::new();
|
|
211
|
+
|
|
212
|
+
for row_chunk in data.chunks(col_count)
|
|
213
|
+
{
|
|
214
|
+
let row = row_chunk.to_vec();
|
|
215
|
+
// Check if row is already in result
|
|
216
|
+
if !result_rows.iter().any(|r| r == &row)
|
|
217
|
+
{
|
|
218
|
+
result_rows.push(row);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
data = result_rows.into_iter().flatten().collect();
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
results.push(QueryResult::Table(graphcore::Table::new(headers, data)?));
|
|
226
|
+
}
|
|
227
|
+
}
|
|
117
228
|
}
|
|
118
229
|
match results.len()
|
|
119
230
|
{
|
|
@@ -160,6 +271,14 @@ pub struct Connection
|
|
|
160
271
|
connection: Box<dyn ConnectionTrait>,
|
|
161
272
|
}
|
|
162
273
|
|
|
274
|
+
impl std::fmt::Debug for Connection
|
|
275
|
+
{
|
|
276
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
|
|
277
|
+
{
|
|
278
|
+
f.write_str("Connection")
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
163
282
|
ccutils::assert_impl_all!(Connection: Sync, Send);
|
|
164
283
|
|
|
165
284
|
impl Connection
|
|
@@ -180,9 +299,9 @@ impl Connection
|
|
|
180
299
|
/// ```rust
|
|
181
300
|
/// # use gqlitedb::Connection;
|
|
182
301
|
/// # fn example() -> gqlitedb::Result<()> {
|
|
183
|
-
/// let connection = Connection::create(gqlitedb::value_map!("backend" => "
|
|
302
|
+
/// let connection = Connection::create(gqlitedb::value_map!("backend" => "sqlite"))?;
|
|
184
303
|
/// # Ok(()) }
|
|
185
|
-
/// ```
|
|
304
|
+
/// ```
|
|
186
305
|
pub fn create(options: value::ValueMap) -> Result<Connection>
|
|
187
306
|
{
|
|
188
307
|
let backend = options.get("backend").map_or_else(
|
|
@@ -303,7 +422,7 @@ impl Connection
|
|
|
303
422
|
/// Example of use:
|
|
304
423
|
/// ```no_run
|
|
305
424
|
/// # use gqlitedb::{Connection, Backend};
|
|
306
|
-
/// let connection = Connection::builder().path("path/to/file").backend(Backend::
|
|
425
|
+
/// let connection = Connection::builder().path("path/to/file").backend(Backend::Redb).create().unwrap();
|
|
307
426
|
/// ```
|
|
308
427
|
pub fn builder() -> ConnectionBuilder
|
|
309
428
|
{
|
|
@@ -345,3 +464,22 @@ impl Connection
|
|
|
345
464
|
self.connection.execute_oc_query(query.as_ref(), parameters)
|
|
346
465
|
}
|
|
347
466
|
}
|
|
467
|
+
|
|
468
|
+
impl graphcore::OpenCypherQueryExecutor for Connection
|
|
469
|
+
{
|
|
470
|
+
fn execute_oc_query(
|
|
471
|
+
&self,
|
|
472
|
+
query: &str,
|
|
473
|
+
parameters: graphcore::ValueMap,
|
|
474
|
+
) -> Result<Option<graphcore::Table>, graphcore::Error>
|
|
475
|
+
{
|
|
476
|
+
let qr = self
|
|
477
|
+
.execute_oc_query(query, parameters)
|
|
478
|
+
.map_err(|e| graphcore::Error::QueryExecutionError(e.to_string()))?;
|
|
479
|
+
match qr
|
|
480
|
+
{
|
|
481
|
+
QueryResult::Table(tbl) => Ok(Some(tbl)),
|
|
482
|
+
_ => Ok(None),
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
data/ext/gqlitedb/src/consts.rs
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
pub(crate) const SHOW_PARSE_TREE: bool = false;
|
|
2
1
|
pub(crate) const SHOW_AST: bool = false;
|
|
3
2
|
pub(crate) const SHOW_PROGRAM: bool = false;
|
|
4
3
|
pub(crate) const SHOW_EVALUATOR_STATE: bool = false;
|
|
5
4
|
|
|
6
5
|
pub(crate) const GQLITE_VERSION: crate::utils::Version = crate::utils::Version {
|
|
7
6
|
major: 1,
|
|
8
|
-
minor:
|
|
7
|
+
minor: 8,
|
|
9
8
|
patch: 0,
|
|
10
9
|
};
|
data/ext/gqlitedb/src/error.rs
CHANGED
|
@@ -20,8 +20,22 @@ pub enum CompileTimeError
|
|
|
20
20
|
text: String
|
|
21
21
|
},
|
|
22
22
|
/// Parse error
|
|
23
|
-
#[error("ParseError: '{
|
|
24
|
-
ParseError
|
|
23
|
+
#[error("ParseError: {error_kind:?}: '{text}' at {span:?}.")]
|
|
24
|
+
ParseError
|
|
25
|
+
{
|
|
26
|
+
error_kind: gqlparser::oc::ErrorKind,
|
|
27
|
+
text: String,
|
|
28
|
+
span: std::ops::Range<usize>,
|
|
29
|
+
},
|
|
30
|
+
/// Unexpected syntax encountered at compile time (used to match TCK expectations)
|
|
31
|
+
#[error("UnexpectedSyntax: Expected token {expected} got {got} at ({line}, {col}).")]
|
|
32
|
+
UnexpectedSyntax
|
|
33
|
+
{
|
|
34
|
+
expected: String,
|
|
35
|
+
got: String,
|
|
36
|
+
line: usize,
|
|
37
|
+
col: usize,
|
|
38
|
+
},
|
|
25
39
|
/// Variable is not defined
|
|
26
40
|
#[error("UndefinedVariable: Unknown variable '{name}'.")]
|
|
27
41
|
UndefinedVariable
|
|
@@ -43,13 +57,20 @@ pub enum CompileTimeError
|
|
|
43
57
|
name: String
|
|
44
58
|
},
|
|
45
59
|
/// ()-[]-() is not accepted in this context
|
|
46
|
-
#[error("RequiresDirectedRelationship: edges need to be directed
|
|
60
|
+
#[error("RequiresDirectedRelationship: edges need to be directed at: '{text}' at {span:?}.")]
|
|
47
61
|
RequiresDirectedRelationship
|
|
48
62
|
{
|
|
49
|
-
|
|
63
|
+
text: String,
|
|
64
|
+
span: std::ops::Range<usize>,
|
|
65
|
+
},
|
|
66
|
+
#[error(
|
|
67
|
+
"NoSingleRelationshipType: a single edge type need to be specified at: '{text}' at {span:?}."
|
|
68
|
+
)]
|
|
69
|
+
NoSingleRelationshipType
|
|
70
|
+
{
|
|
71
|
+
text: String,
|
|
72
|
+
span: std::ops::Range<usize>,
|
|
50
73
|
},
|
|
51
|
-
#[error("NoSingleRelationshipType: an edge type need to be specified.")]
|
|
52
|
-
NoSingleRelationshipType,
|
|
53
74
|
#[error("NotComparable: values are not comparable.")]
|
|
54
75
|
NotComparable,
|
|
55
76
|
#[error("UnknownFunction: {name}.")]
|
|
@@ -67,7 +88,9 @@ pub enum CompileTimeError
|
|
|
67
88
|
#[error("InvalidDelete: invalid delete argument, expected node or edge.")]
|
|
68
89
|
InvalidDelete,
|
|
69
90
|
/// Too few or too many arguments
|
|
70
|
-
#[error(
|
|
91
|
+
#[error(
|
|
92
|
+
"InvalidNumberOfArguments: Invalid number of arguments for function '{function_name}' got {got} expected {expected}."
|
|
93
|
+
)]
|
|
71
94
|
InvalidNumberOfArguments
|
|
72
95
|
{
|
|
73
96
|
function_name: &'static str,
|
|
@@ -78,6 +101,35 @@ pub enum CompileTimeError
|
|
|
78
101
|
NonConstantExpression,
|
|
79
102
|
#[error("InvalidArgumentType: invalid argument type.")]
|
|
80
103
|
InvalidArgumentType,
|
|
104
|
+
#[error("NegativeIntegerArgument: statement expect a positive integer.")]
|
|
105
|
+
NegativeIntegerArgument,
|
|
106
|
+
#[error("CreatingVarLength: attempt at creating a variable length edge.")]
|
|
107
|
+
CreatingVarLength,
|
|
108
|
+
#[error("InvalidVectorInput: Expected vector or tensor for SEARCH.")]
|
|
109
|
+
InvalidVectorInput,
|
|
110
|
+
#[error(
|
|
111
|
+
"InvalidVectorElement: Array element must be numeric (Integer or Float), got {type_name}."
|
|
112
|
+
)]
|
|
113
|
+
InvalidVectorElement
|
|
114
|
+
{
|
|
115
|
+
type_name: String
|
|
116
|
+
},
|
|
117
|
+
#[error("NestedArrayNotSupported: Nested arrays are not supported in vector inputs.")]
|
|
118
|
+
NestedArrayNotSupported,
|
|
119
|
+
#[error("EmptyVector: Vector cannot be empty.")]
|
|
120
|
+
EmptyVector,
|
|
121
|
+
#[error("ExpectedNode: Expected a value to be a node in {context}.")]
|
|
122
|
+
ExpectedNode
|
|
123
|
+
{
|
|
124
|
+
context: &'static str
|
|
125
|
+
},
|
|
126
|
+
#[error("ExpectedEdge: Expected a value to be an edge in {context}.")]
|
|
127
|
+
ExpectedEdge
|
|
128
|
+
{
|
|
129
|
+
context: &'static str
|
|
130
|
+
},
|
|
131
|
+
#[error("DifferentColumnsInUnion: All sub-queries in a UNION must have the same column names.")]
|
|
132
|
+
DifferentColumnsInUnion,
|
|
81
133
|
}
|
|
82
134
|
|
|
83
135
|
/// Runtime errors.
|
|
@@ -93,7 +145,9 @@ pub enum RunTimeError
|
|
|
93
145
|
name: String
|
|
94
146
|
},
|
|
95
147
|
/// Too few or too many arguments
|
|
96
|
-
#[error(
|
|
148
|
+
#[error(
|
|
149
|
+
"InvalidNumberOfArguments: Invalid number of arguments for function '{function_name}' got {got} expected {expected}."
|
|
150
|
+
)]
|
|
97
151
|
InvalidNumberOfArguments
|
|
98
152
|
{
|
|
99
153
|
function_name: &'static str,
|
|
@@ -150,6 +204,11 @@ pub enum RunTimeError
|
|
|
150
204
|
{
|
|
151
205
|
graph_name: String
|
|
152
206
|
},
|
|
207
|
+
#[error("DuplicatedVectorIndex: vector index '{index_name}' already exists.")]
|
|
208
|
+
DuplicatedVectorIndex
|
|
209
|
+
{
|
|
210
|
+
index_name: String
|
|
211
|
+
},
|
|
153
212
|
#[error("UnknownGraph: {graph_name} does not exists.")]
|
|
154
213
|
UnknownGraph
|
|
155
214
|
{
|
|
@@ -167,6 +226,13 @@ pub enum RunTimeError
|
|
|
167
226
|
{
|
|
168
227
|
value: f64, min: f64, max: f64
|
|
169
228
|
},
|
|
229
|
+
#[error("ExpectedEdge: Expected a value to be an edge in {context}.")]
|
|
230
|
+
ExpectedEdge
|
|
231
|
+
{
|
|
232
|
+
context: &'static str
|
|
233
|
+
},
|
|
234
|
+
#[error("MergeReadOwnWrites: Cannot merge node using null property value, which is not allowed.")]
|
|
235
|
+
MergeReadOwnWrites,
|
|
170
236
|
}
|
|
171
237
|
|
|
172
238
|
/// Internal errors, should be treated as bugs.
|
|
@@ -180,16 +246,6 @@ pub enum InternalError
|
|
|
180
246
|
MissingAggregationArgument,
|
|
181
247
|
#[error("Aggregations are missing.")]
|
|
182
248
|
MissingAggregations,
|
|
183
|
-
#[error("Expected a value to be a node in {context}.")]
|
|
184
|
-
ExpectedNode
|
|
185
|
-
{
|
|
186
|
-
context: &'static str
|
|
187
|
-
},
|
|
188
|
-
#[error("Expected a value to be an edge in {context}.")]
|
|
189
|
-
ExpectedEdge
|
|
190
|
-
{
|
|
191
|
-
context: &'static str
|
|
192
|
-
},
|
|
193
249
|
#[error("Missing a pair from pest parsing in {context}.")]
|
|
194
250
|
MissingPair
|
|
195
251
|
{
|
|
@@ -205,11 +261,6 @@ pub enum InternalError
|
|
|
205
261
|
{
|
|
206
262
|
context: &'static str
|
|
207
263
|
},
|
|
208
|
-
#[error("Path pattern was used in create expression in {context}.")]
|
|
209
|
-
PathPatternInCreateExpression
|
|
210
|
-
{
|
|
211
|
-
context: &'static str
|
|
212
|
-
},
|
|
213
264
|
#[error("Invalid create labels expression {context}.")]
|
|
214
265
|
InvalidCreateLabels
|
|
215
266
|
{
|
|
@@ -257,7 +308,9 @@ pub enum InternalError
|
|
|
257
308
|
{
|
|
258
309
|
got: usize, expected: usize
|
|
259
310
|
},
|
|
260
|
-
#[error(
|
|
311
|
+
#[error(
|
|
312
|
+
"Some variables were declared, but not set. Set variables are {set_variables:?}, all variables are {all_variables:?}"
|
|
313
|
+
)]
|
|
261
314
|
NotAllVariablesAreSet
|
|
262
315
|
{
|
|
263
316
|
set_variables: Vec<String>,
|
|
@@ -275,6 +328,9 @@ pub enum InternalError
|
|
|
275
328
|
#[error("Invalid aggregation state")]
|
|
276
329
|
InvalidAggregationState,
|
|
277
330
|
|
|
331
|
+
#[error("Migration error: {0}")]
|
|
332
|
+
MigrationError(String),
|
|
333
|
+
|
|
278
334
|
#[error("Invalid query result cast")]
|
|
279
335
|
InvalidQueryResultCast,
|
|
280
336
|
|
|
@@ -285,7 +341,7 @@ pub enum InternalError
|
|
|
285
341
|
// Errors from askama
|
|
286
342
|
#[cfg(feature = "sqlite")]
|
|
287
343
|
#[error("Askama: {0}")]
|
|
288
|
-
AskamaError(
|
|
344
|
+
AskamaError(askama::Error),
|
|
289
345
|
|
|
290
346
|
// Serialization errors
|
|
291
347
|
#[error("An error occured while serialization to Cbor: {0}")]
|
|
@@ -310,6 +366,8 @@ pub enum InternalError
|
|
|
310
366
|
UnknownNode,
|
|
311
367
|
#[error("Unknown edge")]
|
|
312
368
|
UnknownEdge,
|
|
369
|
+
#[error("UnsupportedRecursivePatternInMerge")]
|
|
370
|
+
UnsupportedRecursivePatternInMerge,
|
|
313
371
|
#[error("Unimplemented error at {0}")]
|
|
314
372
|
Unimplemented(&'static str),
|
|
315
373
|
#[error("Infallible.")]
|
|
@@ -367,7 +425,9 @@ pub enum StoreError
|
|
|
367
425
|
{
|
|
368
426
|
backend: &'static str
|
|
369
427
|
},
|
|
370
|
-
#[error(
|
|
428
|
+
#[error(
|
|
429
|
+
"OpeningError: could not open database, got the following error messages from the backends: {errors}."
|
|
430
|
+
)]
|
|
371
431
|
OpeningError
|
|
372
432
|
{
|
|
373
433
|
errors: String
|
|
@@ -377,6 +437,11 @@ pub enum StoreError
|
|
|
377
437
|
{
|
|
378
438
|
graph_name: String
|
|
379
439
|
},
|
|
440
|
+
#[error("DuplicatedVectorIndex: vector index '{index_name}' already exists.")]
|
|
441
|
+
DuplicatedVectorIndex
|
|
442
|
+
{
|
|
443
|
+
index_name: String
|
|
444
|
+
},
|
|
380
445
|
#[error("UnknownGraph: {graph_name} is not known.")]
|
|
381
446
|
UnknownGraph
|
|
382
447
|
{
|
|
@@ -390,6 +455,10 @@ pub enum StoreError
|
|
|
390
455
|
actual: utils::Version,
|
|
391
456
|
expected: utils::Version,
|
|
392
457
|
},
|
|
458
|
+
#[error(
|
|
459
|
+
"MissingVersionMetadata: database has no version metadata; refusing to open an unrecognized or corrupted database file."
|
|
460
|
+
)]
|
|
461
|
+
MissingVersionMetadata,
|
|
393
462
|
#[error("Invalid database format: {0}.")]
|
|
394
463
|
InvalidFormat(String),
|
|
395
464
|
}
|
|
@@ -522,37 +591,27 @@ impl<T> From<std::sync::PoisonError<T>> for Error
|
|
|
522
591
|
}
|
|
523
592
|
}
|
|
524
593
|
|
|
525
|
-
|
|
526
|
-
{
|
|
527
|
-
fn from(value: pest::error::Error<crate::parser::parser_impl::Rule>) -> Self
|
|
528
|
-
{
|
|
529
|
-
CompileTimeError::from(Box::new(value)).into()
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
macro_rules! error_as_internal {
|
|
534
|
-
($err_type:ty) => {
|
|
594
|
+
macro_rules! error_as_ {
|
|
595
|
+
($err_type:ty, $enum_name: ident) => {
|
|
535
596
|
impl From<$err_type> for crate::prelude::ErrorType
|
|
536
597
|
{
|
|
537
598
|
fn from(value: $err_type) -> Self
|
|
538
599
|
{
|
|
539
|
-
let err: crate::error
|
|
600
|
+
let err: crate::error::$enum_name = value.into();
|
|
540
601
|
err.into()
|
|
541
602
|
}
|
|
542
603
|
}
|
|
543
604
|
};
|
|
544
605
|
}
|
|
606
|
+
macro_rules! error_as_internal {
|
|
607
|
+
($err_type:ty) => {
|
|
608
|
+
error_as_! {$err_type, InternalError}
|
|
609
|
+
};
|
|
610
|
+
}
|
|
545
611
|
|
|
546
612
|
macro_rules! error_as_store {
|
|
547
613
|
($err_type:ty) => {
|
|
548
|
-
|
|
549
|
-
{
|
|
550
|
-
fn from(value: $err_type) -> Self
|
|
551
|
-
{
|
|
552
|
-
let err: crate::error::StoreError = value.into();
|
|
553
|
-
err.into()
|
|
554
|
-
}
|
|
555
|
-
}
|
|
614
|
+
error_as_! {$err_type, StoreError}
|
|
556
615
|
};
|
|
557
616
|
}
|
|
558
617
|
|
|
@@ -563,6 +622,7 @@ error_as_internal! {ciborium::de::Error<std::io::Error>}
|
|
|
563
622
|
error_as_internal! {serde_json::Error}
|
|
564
623
|
error_as_internal! {std::num::ParseFloatError}
|
|
565
624
|
error_as_internal! {std::str::Utf8Error}
|
|
625
|
+
error_as_internal! {std::io::Error}
|
|
566
626
|
|
|
567
627
|
#[cfg(feature = "redb")]
|
|
568
628
|
mod _trait_impl_redb
|
|
@@ -618,6 +678,13 @@ mod _trait_impl_postgres
|
|
|
618
678
|
#[cfg(any(feature = "postgres", feature = "sqlite"))]
|
|
619
679
|
mod _trait_impl_askama
|
|
620
680
|
{
|
|
681
|
+
impl From<askama::Error> for crate::error::InternalError
|
|
682
|
+
{
|
|
683
|
+
fn from(err: askama::Error) -> Self
|
|
684
|
+
{
|
|
685
|
+
crate::error::InternalError::GenericStdError(Box::new(err))
|
|
686
|
+
}
|
|
687
|
+
}
|
|
621
688
|
error_as_internal! {askama::Error}
|
|
622
689
|
}
|
|
623
690
|
|
|
@@ -628,22 +695,6 @@ pub(crate) fn vec_to_error(errs: &[ErrorType]) -> String
|
|
|
628
695
|
errs.join(", ")
|
|
629
696
|
}
|
|
630
697
|
|
|
631
|
-
pub(crate) fn parse_int_error_to_compile_error(
|
|
632
|
-
text: &str,
|
|
633
|
-
e: std::num::ParseIntError,
|
|
634
|
-
) -> crate::prelude::ErrorType
|
|
635
|
-
{
|
|
636
|
-
use std::num::IntErrorKind;
|
|
637
|
-
match e.kind()
|
|
638
|
-
{
|
|
639
|
-
IntErrorKind::PosOverflow | IntErrorKind::NegOverflow => CompileTimeError::IntegerOverflow {
|
|
640
|
-
text: text.to_owned(),
|
|
641
|
-
}
|
|
642
|
-
.into(),
|
|
643
|
-
_ => InternalError::ParseIntError(e).into(),
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
|
|
647
698
|
/// Convenient macro for mapping errors, for instance, from internal error to runtime error:
|
|
648
699
|
///
|
|
649
700
|
/// ```notest
|
|
@@ -675,6 +726,17 @@ impl From<std::convert::Infallible> for Error
|
|
|
675
726
|
}
|
|
676
727
|
}
|
|
677
728
|
|
|
729
|
+
#[cfg(feature = "redb")]
|
|
730
|
+
impl From<db_index::hnsw::Error> for Error
|
|
731
|
+
{
|
|
732
|
+
fn from(value: db_index::hnsw::Error) -> Self
|
|
733
|
+
{
|
|
734
|
+
let error_msg = format!("HNSW error: {:?}", value);
|
|
735
|
+
log::error!("{}", error_msg);
|
|
736
|
+
InternalError::Unimplemented("HNSW operation error").into()
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
|
|
678
740
|
// ____ _ _____
|
|
679
741
|
// / ___| ___ _ __ ___ _ __(_) ___| ____|_ __ _ __ ___ _ __ ___
|
|
680
742
|
// | | _ / _ \ '_ \ / _ \ '__| |/ __| _| | '__| '__/ _ \| '__/ __|
|
|
@@ -13,7 +13,6 @@ impl Size
|
|
|
13
13
|
value::Value::String(str) => Ok(str.len() as i64),
|
|
14
14
|
value::Value::Array(arr) => Ok(arr.len() as i64),
|
|
15
15
|
value::Value::Map(obj) => Ok(obj.len() as i64),
|
|
16
|
-
value::Value::Path(..) => Ok(1.into()),
|
|
17
16
|
_ => Err(RunTimeError::InvalidArgument {
|
|
18
17
|
function_name: "size",
|
|
19
18
|
index: 0,
|
|
@@ -24,4 +23,42 @@ impl Size
|
|
|
24
23
|
}
|
|
25
24
|
}
|
|
26
25
|
|
|
27
|
-
super::
|
|
26
|
+
impl super::FunctionTrait for Size
|
|
27
|
+
{
|
|
28
|
+
fn call(&self, mut arguments: Vec<value::Value>) -> crate::Result<value::Value>
|
|
29
|
+
{
|
|
30
|
+
let arg = arguments
|
|
31
|
+
.first()
|
|
32
|
+
.ok_or(RunTimeError::InvalidNumberOfArguments {
|
|
33
|
+
function_name: "size",
|
|
34
|
+
got: arguments.len(),
|
|
35
|
+
expected: 1,
|
|
36
|
+
})?;
|
|
37
|
+
if arg.is_null()
|
|
38
|
+
{
|
|
39
|
+
return Ok(value::Value::Null);
|
|
40
|
+
}
|
|
41
|
+
let val = arguments.remove(0);
|
|
42
|
+
Self::call_impl(val).map(|r| r.into()).map_err(Into::into)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
fn validate_arguments(
|
|
46
|
+
&self,
|
|
47
|
+
args: Vec<crate::compiler::expression_analyser::ExpressionType>,
|
|
48
|
+
) -> crate::Result<crate::compiler::expression_analyser::ExpressionType>
|
|
49
|
+
{
|
|
50
|
+
use crate::compiler::expression_analyser::ExpressionType;
|
|
51
|
+
if args.iter().any(|t| matches!(t, ExpressionType::Path))
|
|
52
|
+
{
|
|
53
|
+
return Err(crate::error::CompileTimeError::InvalidArgumentType.into());
|
|
54
|
+
}
|
|
55
|
+
Ok(ExpressionType::Integer)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
fn is_deterministic(&self) -> bool
|
|
59
|
+
{
|
|
60
|
+
true
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
super::declare_function!(size, Size, custom_trait);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
use rand::
|
|
1
|
+
use rand::RngExt;
|
|
2
2
|
|
|
3
3
|
use crate::prelude::*;
|
|
4
4
|
|
|
@@ -48,7 +48,7 @@ impl Rand
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
super::declare_function!(rand, Rand, call_impl() -> Vec<f64
|
|
51
|
+
super::declare_function!(rand, Rand, call_impl() -> Vec<f64>, non_deterministic);
|
|
52
52
|
|
|
53
53
|
macro_rules! define_f64_function {
|
|
54
54
|
($name: ident, $class_name: ident, $rust_func: ident $(, $arg0: expr)*) => {
|
|
@@ -102,10 +102,15 @@ super::declare_function!(atan2, Atan2, call_impl(f64, f64) -> f64);
|
|
|
102
102
|
#[cfg(test)]
|
|
103
103
|
mod test
|
|
104
104
|
{
|
|
105
|
-
use crate::functions::math::Extra as _;
|
|
105
|
+
use crate::functions::math::{Extra as _, Rand};
|
|
106
106
|
#[test]
|
|
107
107
|
fn test_cot()
|
|
108
108
|
{
|
|
109
109
|
assert_eq!(0.5_f64.cot(), 1.830487721712452);
|
|
110
110
|
}
|
|
111
|
+
#[test]
|
|
112
|
+
fn test_rand()
|
|
113
|
+
{
|
|
114
|
+
assert!(!Rand::create().1.is_deterministic());
|
|
115
|
+
}
|
|
111
116
|
}
|