Closed daveraja closed 11 months ago
I have a first cut with of a replace(fn)
and a modify(fn)
end point. With replace(fn)
fn
returns a collection (list/set) of replace facts, while the query selected elements are deleted. In contrast modify(fn)
is more general and fn
must return a pair of collections where the first is the facts to delete and the second are the facts to add.
This change is in the clorm dev version on test.pypi.org and conda dev.
Some documentation:
https://clorm.readthedocs.io/en/latest/clorm/factbase.html#queries-that-modify-the-factbase
While these endpoints can be useful, the required parameter function signatures might make it too complicated and prone to error.
@MaxOstrowski I remember you were talking about wanting to modify facts, do you think this feature would be useful and not to complicated to use?
I actually quite like the new functions. I'm a bit unsure how the modify function is supposed to work. Does it still get the query selection criteria as input like replace
? If yes, this sounds pretty useful.
@MaxOstrowski Yes, the modify
function still gets the selected facts as input. So it's just a more general version of replace
where you can explicitly decide which facts to delete. But you're right that it is potentially confusing since you could also delete arbitrary facts that where not selected by the query.
I'm also tempted to have one more version of replace
(either overloading replace
or give it a new name) which would be a special case where you pass the replace
function the named parameters of the fields to modify. So with the replace query:
fb.query(P).where(P.a == 1).replace(lambda p: p.clone(a=2))
you could also write it as:
fb.query(P).where(P.a == 1).replace(a=2)
I think it's pretty clear what it means if there is only one predicate selected, but it does create a bit of ambiguity if there are multiple predicates. For example if you had:
class P(Predicate):
a: int
b: int
class Q(Predicate):
a: int
b: int
c: int
fb.query(P,Q).join(P.a == Q.a).replace(b=4)
fb.query(P,Q).join(P.a == Q.a).replace(c=5)
In these two queries it is not completely clear what a natural intuition would be for which facts should be deleted and which added.
I think the first version is completely sufficient and there is no need to make things "easier" but ambiguous.
It can be useful to want to modify the facts in a factbase the way you might modify entries in a traditional database. However, clorm facts are immutable (see [1]). But we can come close to a modify mechanism by providing a query feature that can be used with the existing
clone()
method to make it easy to replace some existing fact in a fact base.For example if you have a predicate
P
with a fielda
and you want to modify alla
values of1
with value of2
, currently you would have to do something like the following:This is a bit cumbersome and prone to mistakes. For example adding a fact to a factbase from inside a query of that factbase could lead to unpredictable interactions between the addition function and the query. Also it would make more sense to first delete the old items and then add the new items rather than the other way around in case these two sets have some intersection.
The new query replace feature would instead allow this to be done in a single declarative line:
This query
replace()
feature should also handle queries with joins where we want to modify a set of related facts. We could also provide a functionextend()
that doesn't delete the original facts and simply allows new facts to be added.[1] making clorm facts mutable isn't really an option since we want to be able to use it in a factbase and/or set (which means that it needs an immutable hash value).