def Queries(i: Inst) -> s.SearchStrategy[Query]: if len(i) == 0: return s.just(Query()) # only valid query on an empty inst matches = s.frozensets(iAtoms(i), min_size=0, max_size=3) return matches.flatmap(lambda ms: s.builds(Query, s.just(ms), ( lambda var: s.frozensets(choice(var), min_size=0, max_size=len(var)))( set.union(*([x.tup.variables for x in ms] or [set()])))))
def test_query() -> None: # Matching triangle for simple edges gives the same relation back res = egd_edge.q.run(iTriangle) res.rename_attrs(**{'x0': 'src', 'x1': 'tar'}) assert res.rename('Triangle') == iTriangle['Triangle'] # There are no bidirectional edges in Triangle assert len(egd_bidirectional.q.run(iTriangle).tups) == 0 # Detect self loop assert Query.fromatom(selfedge).run(iTriangle11) == Rel.fromlist([[1]], '', ['x0']) # Detect nothing in triangle w/o loop assert len( Query.fromatom(selfedge).rename( TriangleLoop='Triangle').run(iTriangle).tups) == 0
def test_chase() -> None: '''Unit test for computing a terminating chase''' tri = copy.deepcopy(iTriangle['Triangle']) tri.substitutes({V0: Const("a"), V1: Const("b"), Var(3): Const("c")}) # If there's an edge a->b, then there's an edge b->a deps = Dependencies.fromlist( [TGD.fromlist(Query.fromatom(edge), Triangle=[1, 0])]) res = deps.chase(Inst([tri])) assert res.fail is None and not res.timeout assert len(res) == 2
def nonmatching_query(draw: Draw) -> T[Inst, Query, Atom]: inst: Inst = Inst([draw(Rels1305)]) # create a random inst rel = draw(iRels(inst)) # pick a random relation n = len(rel.attrs) # Create a random CONSTANT tuple for this relation tup: ImmTup = draw( s.builds(ImmTup, s.lists(Consts, min_size=n, max_size=n).map(tuple))) # check we didn't accidentally pick a const tuple actually present assume(tup not in rel.tups) qatom: Query = Query.fromatom(Atom(rel.name, tup)) # Add it to a random query query: Query = draw(Queries(inst)) return inst, qatom.merge(query), draw(iAtoms(inst))
def test_validate_match() -> None: """Check whether ...""" res = Rel.fromlist([['d', 3]], attrs=['x4', 'x5']) assert Query.fromatom(q1).run(i1) == res res = Rel.fromlist([['x'], ['y']], attrs=['x4']) assert Query.fromatom(q2).run(i1) == res
def EGDs(draw: Draw, i: Inst) -> EGD: '''Generate an EGD by forcing a query to quantify over 0 and 1''' a01: FS[Atom] = frozenset( [draw(Atom_with_val(draw(iRels(i)), Var(n))) for n in range(2)]) q = draw(Queries(i)) return EGD(Query(frozenset.union(q.matches, a01), frozenset([V0, V1])))
################ # Example Data # ################ i1_ = Inst.fromdict(A=(['col1', 'col2', 'col3'], [[1, 'x', 2], ['c', 'd', 3]]), B=(['col2', 'col4'], [['x', 'x'], ['x', 'y']])) i1 = Inst.fromcsv(['B', 'A']) iTriangle = Inst.fromcsv('Triangle') iTriangle11 = Inst.fromcsv('TriangleLoop') iTriangle_N = Inst.union(iTriangle11, Inst([Rel('N', ['col1'])])) q1 = Atom.fromlist('A', ['c', 4, 5]) q2 = Atom.fromlist('B', ['x', 4]) q3 = Query.fromatoms([q1, q2]) ab = i1['A'].join(i1['B']) edge = Atom.fromlist('Triangle', [0, 1]) selfedge = Atom.fromlist('TriangleLoop', [0, 0]) egd_bidirectional = EGD( Query.fromatoms([edge, Atom.fromlist('Triangle', [1, 0])])) egd_edge = EGD(Query.fromatom(edge)) tgd = TGD.fromlist(Query.fromatom(selfedge), N=[0]) ############## # Generators # ##############