Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {

// Insert data with transaction
let mut tx = session.transaction()?;
tx.execute("CREATE (p:Person {name: 'Alice'})")?;
tx.execute("INSERT (:Person {name: 'Alice'})")?;
tx.commit()?;

// Query data
Expand Down Expand Up @@ -327,7 +327,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {

// Insert data
coordinator.process_query(
"CREATE (p:Person {name: 'Alice'})",
"INSERT (:Person {name: 'Alice'})",
&session_id
)?;

Expand Down
12 changes: 6 additions & 6 deletions bindings/java/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ public class Example {
// Create session
String session = db.createSession("admin");

// Execute queries
db.execute(session, "CREATE (p:Person {name: 'Alice', age: 30})");
// Execute queries (insert single node)
db.execute(session, "INSERT (:Person {name: 'Alice', age: 30})");

// Query data
QueryResult result = db.query(session,
Expand Down Expand Up @@ -120,9 +120,9 @@ db.execute(session, "USE SCHEMA myschema");
db.execute(session, "CREATE GRAPH social");
db.execute(session, "USE GRAPH social");

// DML statements
db.execute(session, "CREATE (p:Person {name: 'Alice', age: 30})");
db.execute(session, "CREATE (p:Person {name: 'Bob', age: 25})");
// DML statements (multiple nodes in one INSERT statement)
db.execute(session, "INSERT (:Person {name: 'Alice', age: 30}), " +
"(:Person {name: 'Bob', age: 25})");
```

### Querying Data
Expand Down Expand Up @@ -203,7 +203,7 @@ try {
try (GraphLite db = GraphLite.open("./mydb")) {
String session = db.createSession("admin");

db.execute(session, "CREATE (p:Person {name: 'Alice'})");
db.execute(session, "INSERT (:Person {name: 'Alice'})");
QueryResult result = db.query(session, "MATCH (p:Person) RETURN p");

for (Map<String, Object> row : result.getRows()) {
Expand Down
12 changes: 6 additions & 6 deletions bindings/python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ db.execute(session, "SESSION SET SCHEMA example")
db.execute(session, "CREATE GRAPH IF NOT EXISTS social")
db.execute(session, "SESSION SET GRAPH social")

# Execute queries
db.execute(session, "CREATE (p:Person {name: 'Alice', age: 30})")
# Execute queries (insert single node)
db.execute(session, "INSERT (:Person {name: 'Alice', age: 30})")

# Query data
result = db.query(session, "MATCH (p:Person) RETURN p.name, p.age")
Expand Down Expand Up @@ -85,9 +85,9 @@ db.execute(session, "USE SCHEMA myschema")
db.execute(session, "CREATE GRAPH social")
db.execute(session, "USE GRAPH social")

# DML statements
db.execute(session, "CREATE (p:Person {name: 'Alice', age: 30})")
db.execute(session, "CREATE (p:Person {name: 'Bob', age: 25})")
# DML statements (multiple nodes in one INSERT statement)
db.execute(session, "INSERT (:Person {name: 'Alice', age: 30}), "
"(:Person {name: 'Bob', age: 25})")
```

### Querying Data
Expand Down Expand Up @@ -165,7 +165,7 @@ except GraphLiteError as e:
with GraphLite("./mydb") as db:
session = db.create_session("admin")

db.execute(session, "CREATE (p:Person {name: 'Alice'})")
db.execute(session, "INSERT (:Person {name: 'Alice'})")
result = db.query(session, "MATCH (p:Person) RETURN p")

for row in result.rows:
Expand Down
28 changes: 14 additions & 14 deletions docs/Getting Started With GQL.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,24 +85,24 @@ CALL show_session();
-- Copy-paste this entire block into GraphLite REPL
-- ============================================

-- Insert Person nodes
INSERT (:Person {name: 'Alice Johnson', age: 30, email: 'alice@example.com', city: 'New York', joined: '2020-01-15', status: 'active'});
INSERT (:Person {name: 'Bob Smith', age: 25, email: 'bob@example.com', city: 'San Francisco', joined: '2021-03-20', status: 'active'});
INSERT (:Person {name: 'Carol Williams', age: 28, email: 'carol@example.com', city: 'New York', joined: '2020-06-10', status: 'active'});
INSERT (:Person {name: 'David Brown', age: 35, email: 'david@example.com', city: 'Chicago', joined: '2019-11-05', status: 'inactive'});
INSERT (:Person {name: 'Eve Davis', age: 27, email: 'eve@example.com', city: 'San Francisco', joined: '2021-08-12', status: 'active'});
INSERT (:Person {name: 'Frank Miller', age: 32, email: 'frank@example.com', city: 'Boston', joined: '2020-04-18', status: 'active'});
-- Insert Person nodes (multiple nodes in one INSERT statement)
INSERT (:Person {name: 'Alice Johnson', age: 30, email: 'alice@example.com', city: 'New York', joined: '2020-01-15', status: 'active'}),
(:Person {name: 'Bob Smith', age: 25, email: 'bob@example.com', city: 'San Francisco', joined: '2021-03-20', status: 'active'}),
(:Person {name: 'Carol Williams', age: 28, email: 'carol@example.com', city: 'New York', joined: '2020-06-10', status: 'active'}),
(:Person {name: 'David Brown', age: 35, email: 'david@example.com', city: 'Chicago', joined: '2019-11-05', status: 'inactive'}),
(:Person {name: 'Eve Davis', age: 27, email: 'eve@example.com', city: 'San Francisco', joined: '2021-08-12', status: 'active'}),
(:Person {name: 'Frank Miller', age: 32, email: 'frank@example.com', city: 'Boston', joined: '2020-04-18', status: 'active'});

-- Insert Company nodes
INSERT (:Company {name: 'TechCorp', industry: 'Technology', founded: '2010-01-01', employees: 500, revenue: 50000000});
INSERT (:Company {name: 'DataInc', industry: 'Analytics', founded: '2015-06-15', employees: 200, revenue: 20000000});
INSERT (:Company {name: 'CloudSystems', industry: 'Cloud Services', founded: '2012-03-10', employees: 800, revenue: 100000000});
INSERT (:Company {name: 'TechCorp', industry: 'Technology', founded: '2010-01-01', employees: 500, revenue: 50000000}),
(:Company {name: 'DataInc', industry: 'Analytics', founded: '2015-06-15', employees: 200, revenue: 20000000}),
(:Company {name: 'CloudSystems', industry: 'Cloud Services', founded: '2012-03-10', employees: 800, revenue: 100000000});

-- Insert Project nodes
INSERT (:Project {name: 'AI Platform', budget: 5000000, start_date: '2023-01-01', status: 'active', priority: 'high'});
INSERT (:Project {name: 'Mobile App', budget: 2000000, start_date: '2023-03-15', status: 'active', priority: 'medium'});
INSERT (:Project {name: 'Data Pipeline', budget: 3000000, start_date: '2022-09-01', status: 'completed', priority: 'high'});
INSERT (:Project {name: 'Security Audit', budget: 500000, start_date: '2023-06-01', status: 'planned', priority: 'low'});
INSERT (:Project {name: 'AI Platform', budget: 5000000, start_date: '2023-01-01', status: 'active', priority: 'high'}),
(:Project {name: 'Mobile App', budget: 2000000, start_date: '2023-03-15', status: 'active', priority: 'medium'}),
(:Project {name: 'Data Pipeline', budget: 3000000, start_date: '2022-09-01', status: 'completed', priority: 'high'}),
(:Project {name: 'Security Audit', budget: 500000, start_date: '2023-06-01', status: 'planned', priority: 'low'});

-- Create KNOWS relationships
MATCH (alice:Person {name: 'Alice Johnson'}), (bob:Person {name: 'Bob Smith'}) INSERT (alice)-[:KNOWS {since: '2020-05-10', strength: 'strong'}]->(bob);
Expand Down
15 changes: 10 additions & 5 deletions docs/Quick Start.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,10 @@ SESSION SET GRAPH /social/network;
### Step 2: Insert Some Data

```gql
-- Create people
INSERT (:Person {name: 'Alice', age: 30, city: 'New York'});
INSERT (:Person {name: 'Bob', age: 25, city: 'San Francisco'});
INSERT (:Person {name: 'Carol', age: 28, city: 'Chicago'});
-- Create people (multiple nodes in one INSERT statement)
INSERT (:Person {name: 'Alice', age: 30, city: 'New York'}),
(:Person {name: 'Bob', age: 25, city: 'San Francisco'}),
(:Person {name: 'Carol', age: 28, city: 'Chicago'});

-- Create friendships
MATCH (alice:Person {name: 'Alice'}), (bob:Person {name: 'Bob'})
Expand Down Expand Up @@ -375,9 +375,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
### Data Insertion

```gql
-- Insert node
-- Insert single node
INSERT (:Label {property: 'value'});

-- Insert multiple nodes (comma-separated)
INSERT (:Person {name: 'Alice'}),
(:Person {name: 'Bob'}),
(:Person {name: 'Carol'});

-- Insert relationship
MATCH (a:Label1 {id: 1}), (b:Label2 {id: 2})
INSERT (a)-[:RELATIONSHIP {prop: 'val'}]->(b);
Expand Down
12 changes: 5 additions & 7 deletions graphlite-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ let result = session.query("MATCH (n:Person) RETURN n")?;
Or for statements that don't return results:

```rust
session.execute("CREATE (p:Person {name: 'Alice'})")?;
session.execute("INSERT (:Person {name: 'Alice'})")?;
```

### Transactions
Expand All @@ -95,14 +95,13 @@ Transactions follow the rusqlite pattern with automatic rollback:
```rust
// Transaction with explicit commit
let mut tx = session.transaction()?;
tx.execute("CREATE (p:Person {name: 'Alice'})")?;
tx.execute("CREATE (p:Person {name: 'Bob'})")?;
tx.execute("INSERT (:Person {name: 'Alice'}), (:Person {name: 'Bob'})")?;
tx.commit()?; // Persist changes

// Transaction with automatic rollback
{
let mut tx = session.transaction()?;
tx.execute("CREATE (p:Person {name: 'Charlie'})")?;
tx.execute("INSERT (:Person {name: 'Charlie'})")?;
// tx is dropped here - changes are automatically rolled back
}
```
Expand Down Expand Up @@ -156,9 +155,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
session.execute("CREATE GRAPH social")?;
session.execute("USE GRAPH social")?;

// Create nodes
session.execute("CREATE (p:Person {name: 'Alice', age: 30})")?;
session.execute("CREATE (p:Person {name: 'Bob', age: 25})")?;
// Create nodes (multiple in one INSERT statement)
session.execute("INSERT (:Person {name: 'Alice', age: 30}), (:Person {name: 'Bob', age: 25})")?;

// Create relationships
session.execute(
Expand Down
8 changes: 2 additions & 6 deletions graphlite/src/ast/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,7 @@ pub struct MatchClause {
}

/// Path type constraints for graph traversal
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[derive(Default)]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
pub enum PathType {
/// WALK - allows repeated vertices and edges (most permissive)
#[default]
Expand All @@ -286,7 +285,6 @@ pub enum PathType {
AcyclicPath,
}


impl PathType {
/// Check if this path type allows repeated vertices
pub fn allows_repeated_vertices(&self) -> bool {
Expand Down Expand Up @@ -1780,14 +1778,12 @@ pub enum GraphIndexTypeSpecifier {
}

/// Index options for CREATE INDEX
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Default)]
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct IndexOptions {
pub parameters: std::collections::HashMap<String, Value>,
pub location: Location,
}


/// Value type for index parameters
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum Value {
Expand Down
5 changes: 1 addition & 4 deletions graphlite/src/cache/invalidation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,7 @@ impl InvalidationManager {

{
let mut reverse_deps = self.reverse_deps.write().unwrap();
reverse_deps
.entry(dep_key)
.or_default()
.insert(entry_key);
reverse_deps.entry(dep_key).or_default().insert(entry_key);
}
}

Expand Down
3 changes: 1 addition & 2 deletions graphlite/src/exec/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,8 +334,7 @@ impl ExecutionContext {
Value::Vector(vec.iter().map(|&f| f as f32).collect())
}
crate::ast::ast::Literal::List(list) => {
let converted: Vec<Value> =
list.iter().map(Self::literal_to_value).collect();
let converted: Vec<Value> = list.iter().map(Self::literal_to_value).collect();
Value::List(converted)
}
}
Expand Down
20 changes: 10 additions & 10 deletions graphlite/src/exec/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,8 @@ impl QueryExecutor {
catalog_path
.segments
.last()
.ok_or_else(|| ExecutionError::RuntimeError("Invalid catalog path".to_string())).cloned()
.ok_or_else(|| ExecutionError::RuntimeError("Invalid catalog path".to_string()))
.cloned()
}
Some(GraphExpression::CurrentGraph) => {
// CurrentGraph requires session context - cannot resolve without it
Expand Down Expand Up @@ -1543,7 +1544,8 @@ impl QueryExecutor {
let filtered_rows = result_rows
.into_iter()
.filter(|row| {
self.evaluate_where_expression_on_row(where_clause, row, context).unwrap_or_default()
self.evaluate_where_expression_on_row(where_clause, row, context)
.unwrap_or_default()
})
.collect();
return Ok(filtered_rows);
Expand Down Expand Up @@ -3373,8 +3375,6 @@ impl QueryExecutor {

let execution_time = start_time.elapsed().as_millis() as u64;



match execute_result {
Ok(rows) => {
// Extract variable names from the physical plan to preserve column order
Expand Down Expand Up @@ -3689,9 +3689,9 @@ impl QueryExecutor {
|| !result
.iter()
.any(|existing| self.rows_equal(left_row, existing)))
{
result.push(left_row.clone());
}
{
result.push(left_row.clone());
}
}
Ok(result)
}
Expand All @@ -3711,9 +3711,9 @@ impl QueryExecutor {
|| !result
.iter()
.any(|existing| self.rows_equal(left_row, existing)))
{
result.push(left_row.clone());
}
{
result.push(left_row.clone());
}
}
Ok(result)
}
Expand Down
12 changes: 5 additions & 7 deletions graphlite/src/exec/unwind_preprocessor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,13 +245,11 @@ impl UnwindPreprocessor {
let text_after_paren = &match_clause[open_paren + 1..];

// Find the variable name - it's the first word after (
let var_end = text_after_paren
.find([':', ')', ' '])
.ok_or_else(|| {
ExecutionError::RuntimeError(
"Invalid MATCH clause: cannot find variable name".to_string(),
)
})?;
let var_end = text_after_paren.find([':', ')', ' ']).ok_or_else(|| {
ExecutionError::RuntimeError(
"Invalid MATCH clause: cannot find variable name".to_string(),
)
})?;

let var_name = text_after_paren[..var_end].trim();

Expand Down
3 changes: 1 addition & 2 deletions graphlite/src/exec/with_clause_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1196,8 +1196,7 @@ impl WithClauseProcessor {
Literal::TimeWindow(tw) => Value::String(tw.clone()),
Literal::Vector(vec) => Value::String(format!("{:?}", vec)),
Literal::List(list) => {
let converted: Vec<Value> =
list.iter().map(Self::literal_to_value).collect();
let converted: Vec<Value> = list.iter().map(Self::literal_to_value).collect();
Value::List(converted)
}
}
Expand Down
3 changes: 1 addition & 2 deletions graphlite/src/exec/write_stmt/data_stmt/insert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,7 @@ impl InsertExecutor {
Value::Vector(vec.iter().map(|&f| f as f32).collect())
}
crate::ast::ast::Literal::List(list) => {
let converted: Vec<Value> =
list.iter().map(Self::literal_to_value).collect();
let converted: Vec<Value> = list.iter().map(Self::literal_to_value).collect();
Value::List(converted)
}
}
Expand Down
9 changes: 6 additions & 3 deletions graphlite/src/exec/write_stmt/data_stmt/match_delete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ impl MatchDeleteExecutor {
Literal::TimeWindow(tw) => Value::String(tw.clone()),
Literal::Vector(vec) => Value::Vector(vec.iter().map(|&f| f as f32).collect()),
Literal::List(list) => {
let converted: Vec<Value> =
list.iter().map(Self::literal_to_value).collect();
let converted: Vec<Value> = list.iter().map(Self::literal_to_value).collect();
Value::List(converted)
}
}
Expand Down Expand Up @@ -286,7 +285,11 @@ impl MatchDeleteExecutor {
// First check nodes
if let Some(node) = node_combination.get(&var.name) {
Some(Value::String(node.id.clone()))
} else { edge_combination.get(&var.name).map(|edge| Value::String(edge.id.clone())) }
} else {
edge_combination
.get(&var.name)
.map(|edge| Value::String(edge.id.clone()))
}
}
Expression::PropertyAccess(prop_access) => {
// First check if the object is a node
Expand Down
8 changes: 2 additions & 6 deletions graphlite/src/exec/write_stmt/data_stmt/match_insert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ impl MatchInsertExecutor {
Literal::TimeWindow(tw) => Value::String(tw.clone()),
Literal::Vector(vec) => Value::Vector(vec.iter().map(|&f| f as f32).collect()),
Literal::List(list) => {
let converted: Vec<Value> =
list.iter().map(Self::literal_to_value).collect();
let converted: Vec<Value> = list.iter().map(Self::literal_to_value).collect();
Value::List(converted)
}
}
Expand Down Expand Up @@ -481,10 +480,7 @@ impl DataStatementExecutor for MatchInsertExecutor {
var_name,
node.id
);
variable_candidates
.entry(var_name)
.or_default()
.push(node);
variable_candidates.entry(var_name).or_default().push(node);
}
}
} else {
Expand Down
Loading