# HG changeset patch # User Sylvain Thénault # Date 1265710960 -3600 # Node ID 8abf464d2ffeda6d2afd977068530cf738964bfd # Parent e7ac20bf3629b48f84bc7225aca920a030612eb1 fix and begin to document autofill algorithm diff -r e7ac20bf3629 -r 8abf464d2ffe devtools/fill.py --- a/devtools/fill.py Mon Feb 08 22:41:07 2010 +0100 +++ b/devtools/fill.py Tue Feb 09 11:22:40 2010 +0100 @@ -410,9 +410,9 @@ yield query, args def qargs(self, subjeids, objeids, subjcard, objcard, subjeid, objeid): - if subjcard in '?1': + if subjcard in '?1+': subjeids.remove(subjeid) - if objcard in '?1': + if objcard in '?1+': objeids.remove(objeid) return {'subjeid' : subjeid, 'objeid' : objeid} diff -r e7ac20bf3629 -r 8abf464d2ffe devtools/testlib.py --- a/devtools/testlib.py Mon Feb 08 22:41:07 2010 +0100 +++ b/devtools/testlib.py Tue Feb 09 11:22:40 2010 +0100 @@ -692,31 +692,52 @@ from cubicweb.devtools.fill import insert_entity_queries, make_relations_queries +# XXX cleanup unprotected_entities & all mess + def how_many_dict(schema, cursor, how_many, skip): - """compute how many entities by type we need to be able to satisfy relations - cardinality + """given a schema, compute how many entities by type we need to be able to + satisfy relations cardinality. + + The `how_many` argument tells how many entities of which type we want at + least. + + Return a dictionary with entity types as key, and the number of entities for + this type as value. """ - # compute how many entities by type we need to be able to satisfy relation constraint relmap = {} for rschema in schema.relations(): if rschema.final: continue for subj, obj in rschema.rdefs: card = rschema.rdef(subj, obj).cardinality - if card[0] in '1?' and len(rschema.subjects(obj)) == 1: + # if the relation is mandatory, we'll need at least as many subj and + # obj to satisfy it + if card[0] in '1+' and card[1] in '1?': + # subj has to be linked to at least one obj, + # but obj can be linked to only one subj + # -> we need at least as many subj as obj to satisfy + # cardinalities for this relation relmap.setdefault((rschema, subj), []).append(str(obj)) - if card[1] in '1?' and len(rschema.objects(subj)) == 1: + if card[1] in '1+' and card[0] in '1?': + # reverse subj and obj in the above explanation relmap.setdefault((rschema, obj), []).append(str(subj)) unprotected = unprotected_entities(schema) - for etype in skip: + for etype in skip: # XXX (syt) duh? explain or kill unprotected.add(etype) howmanydict = {} + # step 1, compute a base number of each entity types: number of already + # existing entities of this type + `how_many` for etype in unprotected_entities(schema, strict=True): howmanydict[str(etype)] = cursor.execute('Any COUNT(X) WHERE X is %s' % etype)[0][0] if etype in unprotected: howmanydict[str(etype)] += how_many + # step 2, augment nb entity per types to satisfy cardinality constraints, + # by recomputing for each relation that constrained an entity type: + # + # new num for etype = max(current num, sum(num for possible target etypes)) + # + # XXX we should first check there is no cycle then propagate changes for (rschema, etype), targets in relmap.iteritems(): - # XXX should 1. check no cycle 2. propagate changes relfactor = sum(howmanydict[e] for e in targets) howmanydict[str(etype)] = max(relfactor, howmanydict[etype]) return howmanydict