gqlite 1.8.0 → 1.8.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 69d9620b19310b76b69a9bb2373cde64cfd94133e73b4197c51d59b0b5463c3d
4
- data.tar.gz: 80af6abeddd183326704ae95cb5b00f2e41317e5a104d2a0c4d77c95cc4cdd5b
3
+ metadata.gz: 4af74e4cc44046fee49a1e9573a876066a80ddc6eaaf2def11f5af0002b89ff2
4
+ data.tar.gz: c105b94002e5c43a74e8f7b418ba45d8d17c47bab1a68dc32c914e18c3a3e1cb
5
5
  SHA512:
6
- metadata.gz: 1f14ae08b820f1e5e48960220912e01f74a41b83610571eec99e46647de2ebd48eed5925e280bf45f728973a7826b1da63cff2e526382bf5d0399b347043a247
7
- data.tar.gz: 9de4b0738781537c2657c90bad7e1831064f8e783387973503971de741c2b861f651efc64733ecc406b0741dba2ba19cfb5f32fab83692b24f2be6a62b6057a2
6
+ metadata.gz: 885b3a13b70473a45cdad51df3fe04f1aebd98828a6211445bf1907c44f88ff543e78ffbf86b5afa971f76482e0b190ed76a7212cbf8b520a20b6e5505a58081
7
+ data.tar.gz: d784d78413e35a708b204a557ef0e1d54236adae193679205b522d788529277c2f183824c87e57946733dd68e36013aea2e0cca6f42fe774d92ce6eccb8d4aed
@@ -2,10 +2,10 @@
2
2
  name = "db-index"
3
3
  description = "Reusable indexing algorithms for key-value storage engines"
4
4
  readme = "README.md"
5
- license = "MIT"
5
+ license.workspace = true
6
6
  homepage.workspace = true
7
7
  repository.workspace = true
8
- version = "0.11.0"
8
+ version.workspace = true
9
9
  edition = "2021"
10
10
 
11
11
  [dependencies]
@@ -22,6 +22,34 @@ pub(crate) trait AggregatorTrait: Debug + Sync + Send
22
22
 
23
23
  pub(crate) type Aggregator = Arc<Box<dyn AggregatorTrait>>;
24
24
 
25
+ #[derive(Debug)]
26
+ pub(crate) struct DistinctAggregatorState
27
+ {
28
+ pub(crate) inner: Box<dyn AggregatorState>,
29
+ pub(crate) seen: Vec<value::Value>,
30
+ }
31
+
32
+ impl AggregatorState for DistinctAggregatorState
33
+ {
34
+ fn next(&mut self, expression: value::Value) -> Result<()>
35
+ {
36
+ if self.seen.iter().any(|v| v == &expression)
37
+ {
38
+ Ok(())
39
+ }
40
+ else
41
+ {
42
+ self.seen.push(expression.clone());
43
+ self.inner.next(expression)
44
+ }
45
+ }
46
+
47
+ fn finalise(self: Box<Self>) -> Result<value::Value>
48
+ {
49
+ self.inner.finalise()
50
+ }
51
+ }
52
+
25
53
  macro_rules! declare_aggregator {
26
54
  ($function_name: ident, $type_name: ident, $state_type_name: tt, ( $( $arg_type: ty $(,)? )* ) -> $ret_type: ty) => {
27
55
  #[derive(Debug)]
@@ -256,6 +256,15 @@ impl<'b> Analyser<'b>
256
256
  )),
257
257
  ast::Expression::FunctionCall(call) =>
258
258
  {
259
+ if call.distinct && !self.functions_manager.is_aggregate(&call.name)?
260
+ {
261
+ return Err(
262
+ error::CompileTimeError::DistinctOnNonAggregateFunction {
263
+ name: call.name.clone(),
264
+ }
265
+ .into(),
266
+ );
267
+ }
259
268
  let arguments = (call.arguments.iter(), validators::any).analyse(self)?;
260
269
  Ok(ExpressionInfo::new(
261
270
  self.functions_manager.validate_arguments(
@@ -438,6 +447,30 @@ impl<'b> Analyser<'b>
438
447
  false,
439
448
  false,
440
449
  )),
450
+ ast::Expression::Contains(contains) => Ok(ExpressionInfo::new_type(
451
+ ExpressionType::Boolean,
452
+ (
453
+ [&contains.left, &contains.right].into_iter(),
454
+ validators::string_or_null,
455
+ )
456
+ .analyse(self)?,
457
+ )),
458
+ ast::Expression::StartsWith(starts_with) => Ok(ExpressionInfo::new_type(
459
+ ExpressionType::Boolean,
460
+ (
461
+ [&starts_with.left, &starts_with.right].into_iter(),
462
+ validators::string_or_null,
463
+ )
464
+ .analyse(self)?,
465
+ )),
466
+ ast::Expression::EndsWith(ends_with) => Ok(ExpressionInfo::new_type(
467
+ ExpressionType::Boolean,
468
+ (
469
+ [&ends_with.left, &ends_with.right].into_iter(),
470
+ validators::string_or_null,
471
+ )
472
+ .analyse(self)?,
473
+ )),
441
474
  }
442
475
  }
443
476
  }
@@ -596,7 +596,8 @@ impl VariablesManager
596
596
  LogicalPlan::Filter { source, .. }
597
597
  | LogicalPlan::Sort { source, .. }
598
598
  | LogicalPlan::Skip { source, .. }
599
- | LogicalPlan::Limit { source, .. } => self.analyse(source.as_ref())?,
599
+ | LogicalPlan::Limit { source, .. }
600
+ | LogicalPlan::Distinct { source } => self.analyse(source.as_ref())?,
600
601
  LogicalPlan::Projection { .. } =>
601
602
  {}
602
603
  LogicalPlan::Call { .. } =>
@@ -132,6 +132,7 @@ impl Compiler
132
132
  init_instructions,
133
133
  aggregator,
134
134
  argument_instructions,
135
+ distinct: function_call.distinct,
135
136
  },
136
137
  ));
137
138
  Instruction::GetVariable { col_id: var_col_id }
@@ -317,6 +318,21 @@ impl Compiler
317
318
  instructions.push(Instruction::IsNullUnaryOperator);
318
319
  Instruction::NotUnaryOperator
319
320
  }
321
+ ast::Expression::Contains(contains) =>
322
+ {
323
+ compile_binary_op!(self, contains, instructions, aggregations);
324
+ Instruction::StringContainsOperator
325
+ }
326
+ ast::Expression::StartsWith(starts_with) =>
327
+ {
328
+ compile_binary_op!(self, starts_with, instructions, aggregations);
329
+ Instruction::StringStartsWithOperator
330
+ }
331
+ ast::Expression::EndsWith(ends_with) =>
332
+ {
333
+ compile_binary_op!(self, ends_with, instructions, aggregations);
334
+ Instruction::StringEndsWithOperator
335
+ }
320
336
  };
321
337
  instructions.push(expr);
322
338
  Ok(())
@@ -980,6 +996,7 @@ impl Compiler
980
996
  },
981
997
  )?;
982
998
  Ok(instructions::Modifiers {
999
+ distinct: modifiers.distinct,
983
1000
  limit,
984
1001
  skip,
985
1002
  order_by,
@@ -1100,6 +1117,12 @@ impl Compiler
1100
1117
  projection.modifiers.limit = Some(expression);
1101
1118
  Ok(projection)
1102
1119
  }
1120
+ LogicalPlan::Distinct { source } =>
1121
+ {
1122
+ let mut projection = Self::unpack_projection_plan(*source)?;
1123
+ projection.modifiers.distinct = true;
1124
+ Ok(projection)
1125
+ }
1103
1126
  _ => Err(
1104
1127
  InternalError::Unreachable {
1105
1128
  context: "compile/unpack_projection_plan",
@@ -1239,7 +1262,8 @@ pub(crate) fn compile(
1239
1262
  | LogicalPlan::Sort { .. }
1240
1263
  | LogicalPlan::Skip { .. }
1241
1264
  | LogicalPlan::Limit { .. }
1242
- | LogicalPlan::Filter { .. } => compiler.compile_projection_plan(logical_plan),
1265
+ | LogicalPlan::Filter { .. }
1266
+ | LogicalPlan::Distinct { .. } => compiler.compile_projection_plan(logical_plan),
1243
1267
  LogicalPlan::Call { name, arguments } =>
1244
1268
  {
1245
1269
  let mut instructions = Instructions::new();
@@ -32,8 +32,8 @@ impl ConnectionBuilder
32
32
  /// Merge options. This might overwrite value from the builder
33
33
  pub fn options(mut self, options: impl Into<value::ValueMap>) -> Self
34
34
  {
35
- let mut options = options.into();
36
- self.map.extend(options.drain());
35
+ let options = options.into();
36
+ self.map.extend(options);
37
37
  self
38
38
  }
39
39
  /// Set the option value for the given key.
@@ -5,5 +5,5 @@ pub(crate) const SHOW_EVALUATOR_STATE: bool = false;
5
5
  pub(crate) const GQLITE_VERSION: crate::utils::Version = crate::utils::Version {
6
6
  major: 1,
7
7
  minor: 8,
8
- patch: 0,
8
+ patch: 1,
9
9
  };
@@ -78,6 +78,13 @@ pub enum CompileTimeError
78
78
  {
79
79
  name: String
80
80
  },
81
+ #[error(
82
+ "DistinctOnNonAggregateFunction: DISTINCT can only be used with aggregate functions, got '{name}'."
83
+ )]
84
+ DistinctOnNonAggregateFunction
85
+ {
86
+ name: String
87
+ },
81
88
  #[error("InvalidAggregation: aggregation is not accepted in this expression.")]
82
89
  InvalidAggregation,
83
90
  #[error("ColumnNameConflict: Column '{name}' is duplicated.")]
@@ -1,4 +1,4 @@
1
- use std::collections::HashMap;
1
+ use std::collections::{HashMap, HashSet};
2
2
 
3
3
  use rustc_hash::FxHashSet;
4
4
 
@@ -333,6 +333,27 @@ fn execute_binary_operator<T: Into<crate::value::Value>>(
333
333
  Ok(())
334
334
  }
335
335
 
336
+ fn execute_string_operator(
337
+ stack: &mut Stack,
338
+ operand: impl FnOnce(String, String) -> bool,
339
+ ) -> Result<()>
340
+ {
341
+ let a: Value = stack.try_pop()?;
342
+ let b: Value = stack.try_pop()?;
343
+
344
+ let a: graphcore::Value = a.try_into()?;
345
+ let b: graphcore::Value = b.try_into()?;
346
+
347
+ let a = a.try_into();
348
+ let b = b.try_into();
349
+ match (a, b)
350
+ {
351
+ (Ok(a), Ok(b)) => stack.push(operand(a, b)),
352
+ _ => stack.push(graphcore::Value::Null),
353
+ }
354
+ Ok(())
355
+ }
356
+
336
357
  fn eval_instructions(
337
358
  stack: &mut Stack,
338
359
  row: &impl value_table::RowInterface,
@@ -807,6 +828,18 @@ fn eval_instructions(
807
828
  {
808
829
  execute_binary_operator(stack, |a, b| a.pow(b))?;
809
830
  }
831
+ &instructions::Instruction::StringContainsOperator =>
832
+ {
833
+ execute_string_operator(stack, |a, b| a.contains(&b))?;
834
+ }
835
+ &instructions::Instruction::StringStartsWithOperator =>
836
+ {
837
+ execute_string_operator(stack, |a, b| a.starts_with(&b))?;
838
+ }
839
+ &instructions::Instruction::StringEndsWithOperator =>
840
+ {
841
+ execute_string_operator(stack, |a, b| a.ends_with(&b))?;
842
+ }
810
843
  }
811
844
  }
812
845
  Ok(())
@@ -921,13 +954,20 @@ fn create_aggregations_states(
921
954
  &agg.init_instructions,
922
955
  parameters,
923
956
  )?;
924
- let state = agg.aggregator.create(
957
+ let mut state = agg.aggregator.create(
925
958
  stack
926
959
  .into_vec()
927
960
  .into_iter()
928
961
  .map(|v| v.try_into())
929
962
  .collect::<Result<_>>()?,
930
963
  )?;
964
+ if agg.distinct
965
+ {
966
+ state = Box::new(aggregators::DistinctAggregatorState {
967
+ inner: state,
968
+ seen: Vec::new(),
969
+ });
970
+ }
931
971
 
932
972
  Ok((name.to_owned(), state))
933
973
  })
@@ -1059,7 +1099,6 @@ fn compute_return_with_table(
1059
1099
  {
1060
1100
  output_table = filter_rows(output_table.into_row_iter(), filter, parameters)?.try_into()?;
1061
1101
  }
1062
- // Apply modifiers
1063
1102
  // Sort the table according to order_by
1064
1103
  if !modifiers.order_by.is_empty()
1065
1104
  {
@@ -1125,7 +1164,7 @@ fn compute_return_with_table(
1125
1164
  }
1126
1165
  }
1127
1166
 
1128
- output_table
1167
+ let output_table_iter = output_table
1129
1168
  .into_row_iter()
1130
1169
  .map(|mut row| {
1131
1170
  Ok(Row::new(
@@ -1136,8 +1175,25 @@ fn compute_return_with_table(
1136
1175
  0,
1137
1176
  ))
1138
1177
  })
1139
- .map(value_table::RowResult)
1140
- .collect()
1178
+ .map(value_table::RowResult);
1179
+
1180
+ // Apply modifiers
1181
+ if modifiers.distinct
1182
+ {
1183
+ let mut seen = HashSet::new();
1184
+
1185
+ output_table_iter
1186
+ .filter(|row| match &row.0
1187
+ {
1188
+ Ok(row) => seen.insert(RowKey(row.clone())),
1189
+ Err(_) => true,
1190
+ })
1191
+ .collect()
1192
+ }
1193
+ else
1194
+ {
1195
+ output_table_iter.collect()
1196
+ }
1141
1197
  }
1142
1198
 
1143
1199
  fn filter_rows(
@@ -79,6 +79,9 @@ pub(crate) enum Instruction
79
79
  DivisionBinaryOperator,
80
80
  ModuloBinaryOperator,
81
81
  ExponentBinaryOperator,
82
+ StringContainsOperator,
83
+ StringStartsWithOperator,
84
+ StringEndsWithOperator,
82
85
  }
83
86
 
84
87
  pub(crate) type Instructions = Vec<Instruction>;
@@ -127,6 +130,7 @@ pub(crate) struct RWAggregation
127
130
  pub(crate) init_instructions: Instructions,
128
131
  pub(crate) argument_instructions: Instructions,
129
132
  pub(crate) aggregator: aggregators::Aggregator,
133
+ pub(crate) distinct: bool,
130
134
  }
131
135
 
132
136
  /// R(eturn)W(ith)Expression are expressions computed in Return or With blocks.
@@ -189,6 +193,7 @@ pub(crate) struct OrderBy
189
193
  #[derive(Debug)]
190
194
  pub(crate) struct Modifiers
191
195
  {
196
+ pub distinct: bool,
192
197
  pub limit: Option<Instructions>,
193
198
  pub skip: Option<Instructions>,
194
199
  pub order_by: Vec<OrderBy>,
@@ -89,6 +89,12 @@ pub enum LogicalPlan
89
89
  /// Limit expression.
90
90
  expression: ast::Expression,
91
91
  },
92
+ /// Make sure values only appear onces.
93
+ Distinct
94
+ {
95
+ /// Input operator.
96
+ source: Box<LogicalPlan>,
97
+ },
92
98
  /// Invoke a callable.
93
99
  Call
94
100
  {
@@ -211,6 +217,13 @@ fn wrap_modifiers(plan: LogicalPlan, modifiers: ast::Modifiers) -> LogicalPlan
211
217
  };
212
218
  }
213
219
 
220
+ if modifiers.distinct
221
+ {
222
+ plan = LogicalPlan::Distinct {
223
+ source: Box::new(plan),
224
+ }
225
+ }
226
+
214
227
  plan
215
228
  }
216
229
 
@@ -570,7 +570,7 @@ impl Store
570
570
  /// database forward exactly one step; the function recurses until `from` matches current.
571
571
  fn upgrade_database(&self, from: utils::Version, tx: &mut TransactionBox) -> Result<()>
572
572
  {
573
- if from == consts::GQLITE_VERSION
573
+ if from.major == consts::GQLITE_VERSION.major && from.minor == consts::GQLITE_VERSION.minor
574
574
  {
575
575
  return Ok(());
576
576
  }
@@ -248,6 +248,7 @@ fn test_compile_logicalplan_projection_modifiers()
248
248
  asc: false,
249
249
  instructions: vec![Instruction::GetVariable { col_id: 0 }],
250
250
  }],
251
+ distinct: false,
251
252
  },
252
253
  variables_sizes: VariablesSizes {
253
254
  persistent_variables: 1,
@@ -41,3 +41,25 @@ fn test_vector_search_dimension_mismatch()
41
41
  let connection = builder.create().unwrap();
42
42
  super::test_vector_search_dimension_mismatch(connection);
43
43
  }
44
+
45
+ #[test]
46
+ fn test_not_wraps_comparison_at_runtime()
47
+ {
48
+ let db = crate::tests::postgres::create_tmp_db(14);
49
+ let builder = crate::Connection::builder()
50
+ .set_option("url", db.connection_uri())
51
+ .backend(crate::Backend::Postgres);
52
+ let connection = builder.create().unwrap();
53
+ super::test_not_wraps_comparison_at_runtime(connection);
54
+ }
55
+
56
+ #[test]
57
+ fn test_count_distinct_end_to_end()
58
+ {
59
+ let db = crate::tests::postgres::create_tmp_db(15);
60
+ let builder = crate::Connection::builder()
61
+ .set_option("url", db.connection_uri())
62
+ .backend(crate::Backend::Postgres);
63
+ let connection = builder.create().unwrap();
64
+ super::test_count_distinct_end_to_end(connection);
65
+ }
@@ -21,3 +21,19 @@ fn test_create_edge_return()
21
21
  let connection = builder.create().unwrap();
22
22
  super::test_create_edge_return(connection);
23
23
  }
24
+
25
+ #[test]
26
+ fn test_not_wraps_comparison_at_runtime()
27
+ {
28
+ let builder = crate::Connection::builder().backend(crate::Backend::Redb);
29
+ let connection = builder.create().unwrap();
30
+ super::test_not_wraps_comparison_at_runtime(connection);
31
+ }
32
+
33
+ #[test]
34
+ fn test_count_distinct_end_to_end()
35
+ {
36
+ let builder = crate::Connection::builder().backend(crate::Backend::Redb);
37
+ let connection = builder.create().unwrap();
38
+ super::test_count_distinct_end_to_end(connection);
39
+ }
@@ -29,3 +29,19 @@ fn test_vector_search_dimension_mismatch()
29
29
  let connection = builder.create().unwrap();
30
30
  super::test_vector_search_dimension_mismatch(connection);
31
31
  }
32
+
33
+ #[test]
34
+ fn test_not_wraps_comparison_at_runtime()
35
+ {
36
+ let builder = crate::Connection::builder().backend(crate::Backend::SQLite);
37
+ let connection = builder.create().unwrap();
38
+ super::test_not_wraps_comparison_at_runtime(connection);
39
+ }
40
+
41
+ #[test]
42
+ fn test_count_distinct_end_to_end()
43
+ {
44
+ let builder = crate::Connection::builder().backend(crate::Backend::SQLite);
45
+ let connection = builder.create().unwrap();
46
+ super::test_count_distinct_end_to_end(connection);
47
+ }
@@ -77,3 +77,67 @@ fn test_vector_search_dimension_mismatch(connection: crate::Connection)
77
77
  );
78
78
  assert!(result.is_err(), "dimension mismatch should raise an error");
79
79
  }
80
+
81
+ fn test_not_wraps_comparison_at_runtime(connection: crate::Connection)
82
+ {
83
+ connection
84
+ .execute_oc_query("CREATE (:Person {name: \"Alice\"})", Default::default())
85
+ .unwrap();
86
+ connection
87
+ .execute_oc_query("CREATE (:Person {name: \"Bob\"})", Default::default())
88
+ .unwrap();
89
+
90
+ let result = connection
91
+ .execute_oc_query(
92
+ r#"MATCH (p:Person) WHERE NOT p.name = "Alice" RETURN count(p) AS n"#,
93
+ Default::default(),
94
+ )
95
+ .unwrap();
96
+ let table = result.try_into_table().unwrap();
97
+ assert_eq!(table.rows(), 1);
98
+ let count: i64 = table.value(0, 0).unwrap().try_into().unwrap();
99
+ assert_eq!(count, 1, "only Bob should match (NOT Alice)");
100
+ }
101
+
102
+ fn test_count_distinct_end_to_end(connection: crate::Connection)
103
+ {
104
+ connection
105
+ .execute_oc_query("CREATE (:Person {id: 1})", Default::default())
106
+ .unwrap();
107
+ connection
108
+ .execute_oc_query("CREATE (:Person {id: 2})", Default::default())
109
+ .unwrap();
110
+ connection
111
+ .execute_oc_query("CREATE (:Person {id: 3})", Default::default())
112
+ .unwrap();
113
+
114
+ connection
115
+ .execute_oc_query(
116
+ "MATCH (p:Person {id: 1}), (f:Person) CREATE (p)-[:KNOWS]->(f)",
117
+ Default::default(),
118
+ )
119
+ .unwrap();
120
+ connection
121
+ .execute_oc_query(
122
+ "MATCH (p:Person {id: 1}), (f:Person {id: 2}) CREATE (p)-[:KNOWS]->(f)",
123
+ Default::default(),
124
+ )
125
+ .unwrap();
126
+ connection
127
+ .execute_oc_query(
128
+ "MATCH (p:Person {id: 1}), (f:Person {id: 3}) CREATE (p)-[:KNOWS]->(f)",
129
+ Default::default(),
130
+ )
131
+ .unwrap();
132
+
133
+ let result = connection
134
+ .execute_oc_query(
135
+ "MATCH (p:Person {id: 1})-[:KNOWS]->(friend:Person) RETURN count(DISTINCT friend) AS n",
136
+ Default::default(),
137
+ )
138
+ .unwrap();
139
+ let table = result.try_into_table().unwrap();
140
+ assert_eq!(table.rows(), 1);
141
+ let count: i64 = table.value(0, 0).unwrap().try_into().unwrap();
142
+ assert_eq!(count, 3, "should count distinct friends");
143
+ }
@@ -99,6 +99,7 @@ fn test_plan_return_creates_projection_modifier_chain()
99
99
  .into(),
100
100
  }],
101
101
  modifiers: Modifiers {
102
+ distinct: false,
102
103
  skip: Some(Value { value: 2.into() }.into()),
103
104
  limit: Some(Value { value: 4.into() }.into()),
104
105
  order_by: Some(OrderBy {
@@ -9,6 +9,7 @@ fn return_statement(var_id: VariableIdentifier) -> Statement
9
9
  expression: Variable { identifier: var_id }.into(),
10
10
  }],
11
11
  modifiers: Modifiers {
12
+ distinct: false,
12
13
  skip: None,
13
14
  limit: None,
14
15
  order_by: None,
@@ -70,6 +71,7 @@ pub(crate) fn create_named_node() -> Statements
70
71
  .into(),
71
72
  }],
72
73
  modifiers: Modifiers {
74
+ distinct: false,
73
75
  skip: None,
74
76
  limit: None,
75
77
  order_by: None,
@@ -134,6 +136,7 @@ pub(crate) fn create_named_node_double_return() -> Statements
134
136
  },
135
137
  ],
136
138
  modifiers: Modifiers {
139
+ distinct: false,
137
140
  skip: None,
138
141
  limit: None,
139
142
  order_by: None,
@@ -162,6 +165,7 @@ pub(crate) fn double_with_return() -> Statements
162
165
  },
163
166
  ],
164
167
  modifiers: Modifiers {
168
+ distinct: false,
165
169
  skip: None,
166
170
  limit: None,
167
171
  order_by: None,
@@ -188,6 +192,7 @@ pub(crate) fn double_with_return() -> Statements
188
192
  },
189
193
  ],
190
194
  modifiers: Modifiers {
195
+ distinct: false,
191
196
  skip: None,
192
197
  limit: None,
193
198
  order_by: None,
@@ -291,10 +296,12 @@ pub(crate) fn match_count() -> Statements
291
296
  expression: FunctionCall {
292
297
  name: "count".into(),
293
298
  arguments: vec![Value { value: 0.into() }.into()],
299
+ distinct: false,
294
300
  }
295
301
  .into(),
296
302
  }],
297
303
  modifiers: Modifiers {
304
+ distinct: false,
298
305
  skip: None,
299
306
  limit: None,
300
307
  order_by: None,
@@ -349,11 +356,13 @@ pub(crate) fn aggregation() -> Statements
349
356
  }
350
357
  .into(),
351
358
  ],
359
+ distinct: false,
352
360
  }
353
361
  .into(),
354
362
  },
355
363
  ],
356
364
  modifiers: Modifiers {
365
+ distinct: false,
357
366
  skip: None,
358
367
  limit: None,
359
368
  order_by: None,
@@ -421,6 +430,7 @@ pub(crate) fn match_with_vector_search(index_name: &str) -> Statements
421
430
  .into(),
422
431
  }],
423
432
  modifiers: Modifiers {
433
+ distinct: false,
424
434
  skip: None,
425
435
  limit: None,
426
436
  order_by: None,