cozodb / cozo

A transactional, relational-graph-vector database that uses Datalog for query. The hippocampus for AI!
https://cozodb.org
Mozilla Public License 2.0
3.24k stars 92 forks source link

Record types #245

Open andrewbaxter opened 4 months ago

andrewbaxter commented 4 months ago

Using tuples everywhere relies on positioning to correlate symbols which is risky (mix up the order of two symbols and you can end up with strange results).

Relations kind of support a record syntax, but this isn't supported anywhere else.

I'd like:

I assume the framework for this is already there, since results already have headers etc.

And maybe

creatorrr commented 2 weeks ago

Curious. What do you mean by:

Record matching for non-relations, like := my_rule{a: a, b: b}

isn't this already supported? Also, could you use json objects in place of records? It won't be pretty but I guess it'll have similar semantics.

andrewbaxter commented 2 weeks ago

My brain cache has been purged, but I think it was something like this:

{
stuff[x,y] <- [[1, 2]]
?[y] := stuff{y: 2, x: y}
}

This gives a syntax error. It would be equivalent to stuff[y, 2] but more explicit.

  × The query parser has encountered unexpected input / end of input at 38..38
   ╭─[2:1]
 2 │ stuff[x,y] <- [[1, 2]]
 3 │ ?[y] := stuff{y: 2, x: y}
   ·              ▲
 4 │ }
   ╰────
andrewbaxter commented 2 weeks ago

You're right, JSON might work. This works for instance:

{
stuff[x] <- [[json({"x": 1, "y": 2})]]
?[y] := stuff[x], y = get(x, "x"), get(x, "y") == 2
}

And you can effectively name output parameters

{
stuff[x] <- [[json({"x": 1, "y": 2})]]
?[res] := stuff[x], y = get(x, "x"), get(x, "y") == 2, res = json({"y": get(x, "x")})
}

which I think checks all my boxes above.

If I were to push for having this natively instead of via json, I think the reasons are:

creatorrr commented 2 weeks ago

There's definitely an overhead of json conversions and it can be error-prone for no real benefit other than syntax niceties. I do second this on second thought, it may make sense that records -> json mapping is easy and simply calling json({...}) on them works.