Skip to content

Commit c4f71ff

Browse files
Create config entries as full F+ objects
If we are not going to create config entries as blanks node, they need IRIs; if they are going to have IRIs they need UUIDs generating and might as well be F+ objects. Create a class Document ⊂ Individual and make ConfigEntry a subclass. * Use the ConfigEntry's own UUID for the etag. * Remove the Instant handling for now. Ideally it would come back later applied to all Individuals but we don't need it for now. * Config entries are now F+ objects so they have Registration entries. We must not generate these for Registration entries or we have an infinite loop. These could be supplied virtually as they are immutable. * Delete orphaned structured config entries. * Adjust some of the namespacing and use relative URLs within the Turtle rather than a plethora of namespaces.
1 parent 7582bba commit c4f71ff

7 files changed

Lines changed: 189 additions & 120 deletions

File tree

acs-metadb/src/main/java/uk/co/amrc/factoryplus/metadb/api/V2Config.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,13 @@ public Response get ()
4343
return req.configEntry(app, obj).getValue();
4444
});
4545
return entry
46-
.map(e -> Response.ok(e.value())
47-
.tag(e.etag())
48-
.lastModified(Date.from(e.mtime()))
49-
.build())
46+
.map(e -> {
47+
var res = Response.ok(e.value())
48+
.tag(e.etag());
49+
e.mtime().ifPresent(t ->
50+
res.lastModified(Date.from(t)));
51+
return res.build();
52+
})
5053
.orElseThrow(() -> new WebApplicationException(404));
5154
}
5255

acs-metadb/src/main/java/uk/co/amrc/factoryplus/metadb/db/AppUpdater.java

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -48,28 +48,66 @@ public AppUpdater (RequestHandler req)
4848
<app/appliesTo> ?domain.
4949
?obj a ?domain;
5050
<core/uuid> ?uuid.
51+
52+
# We do not generate Reg entries here, they must be done in
53+
# a second pass.
54+
filter(?app != <app/Registration>)
55+
}
56+
""");
57+
private static Query Q_findObjects = Vocab.query("""
58+
select ?obj
59+
where {
60+
?obj <core/uuid> ?uuid.
61+
62+
# We don't generate Reg entries for Reg entries.
63+
filter not exists {
64+
?obj a <app/Registration>.
65+
}
66+
}
67+
""");
68+
/* This query assumes we do not have sub-apps, so that a given
69+
* ConfigEntry is a member of only one App. If SPARQL had DELETE
70+
* RETURNING this could be an UpdateRequest: we must know what was
71+
* removed to send notify updates.
72+
*/
73+
private static Query Q_orphanConfigs = Vocab.query("""
74+
select ?conf ?app ?obj
75+
where {
76+
?conf a ?app; <app/for> ?obj.
77+
?app <app/appliesTo> ?domain.
78+
79+
filter not exists { ?obj a ?domain. }
5180
}
5281
""");
5382

5483
public void update ()
5584
{
5685
var updates = db().selectQuery(Q_findUpdates)
5786
.materialise();
58-
59-
updates.forEachRemaining(update -> {
60-
var app = update.getResource("app");
61-
var obj = update.getResource("obj");
87+
updates.forEachRemaining(row -> {
88+
var app = row.getResource("app");
89+
var obj = row.getResource("obj");
6290
updateEntry(app, obj);
6391
});
6492

65-
/* We may have created the current instant in order to update a
66-
* config entry. In this case it may not have been captured by
67-
* the first pass through the changes. But we don't want to
68-
* store an Instant if we don't need one. */
69-
if (!updated.isEmpty()) {
70-
var now = request().getInstant();
71-
updateEntry(Vocab.App.Registration, now);
72-
}
93+
/* We update Reg entries in a second pass, as updating the other
94+
* entries will have created registered objects. */
95+
var objects = db().selectQuery(Q_findObjects)
96+
.materialise();
97+
objects.forEachRemaining(row -> {
98+
var obj = row.getResource("obj");
99+
updateEntry(Vocab.App.Registration, obj);
100+
});
101+
102+
var orphans = db().selectQuery(Q_orphanConfigs)
103+
.materialise();
104+
orphans.forEachRemaining(row -> {
105+
var conf = row.getResource("conf");
106+
db().removeResource(conf);
107+
var app = row.getResource("app");
108+
var obj = row.getResource("obj");
109+
updated.add(new Config(app, obj));
110+
});
73111
}
74112

75113
public void publish ()

acs-metadb/src/main/java/uk/co/amrc/factoryplus/metadb/db/ConfigEntry.java

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,22 +43,20 @@ public static ConfigEntry create (RequestHandler req, UUID app, UUID obj)
4343
return new ConfigEntry(req, appO.node(), objO.node());
4444
}
4545

46-
public record Value (JsonValue value, String etag, Instant mtime) {}
46+
public record Value (JsonValue value, String etag, Optional<Instant> mtime) {}
4747

4848
private boolean isStructured ()
4949
{
5050
return db().derived().contains(app, RDF.type, Vocab.App.Structured);
5151
}
5252

5353
private static final Query Q_getValue = Vocab.query("""
54-
select ?value ?etag ?mtime
54+
select ?value ?etag
5555
where {
5656
?config a ?app;
5757
<app/for> ?obj;
58-
<app/value> ?value.
59-
?config <core/start> ?instant.
60-
?instant <core/uuid> ?etag;
61-
<core/timestamp> ?mtime.
58+
<core/uuid> ?etag;
59+
<doc/content> ?value.
6260
}
6361
""");
6462

@@ -69,10 +67,10 @@ public Optional<Value> getValue ()
6967
var val = Util.decodeLiteral(binding.get("value"), RDF.JSON,
7068
s -> Json.createReader(new StringReader(s)).readValue());
7169
var etag = Util.decodeLiteral(binding.get("etag"), XSD.xstring, s -> s);
72-
var mtime = Util.decodeLiteral(binding.get("mtime"), XSD.dateTime,
73-
Instant::parse);
70+
//var mtime = Util.decodeLiteral(binding.get("mtime"), XSD.dateTime,
71+
// Instant::parse);
7472

75-
return new Value(val, etag, mtime);
73+
return new Value(val, etag, Optional.empty());
7674
});
7775
}
7876

@@ -126,13 +124,12 @@ public boolean putRawValue (JsonValue value)
126124
value.toString(), RDF.dtRDFJSON);
127125

128126
var graph = db().derived();
129-
var entry = graph.createResource();
130-
var inst = request().getInstant();
127+
var entry = db().createObject(app).node();
128+
//var inst = request().getInstant();
131129

132-
graph.add(entry, RDF.type, app);
133130
graph.add(entry, Vocab.App.forP, obj);
134-
graph.add(entry, Vocab.App.value, json);
135-
graph.add(entry, Vocab.start, inst);
131+
graph.add(entry, Vocab.Doc.content, json);
132+
//graph.add(entry, Vocab.Time.start, inst);
136133

137134
return true;
138135
}

acs-metadb/src/main/java/uk/co/amrc/factoryplus/metadb/db/ObjectStructure.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public static Relation of (String relation)
5353
}
5454

5555
private static final Set<Resource> IMMUTABLE = Set.of(
56-
Vocab.Application, Vocab.Special,
56+
Vocab.App.Application, Vocab.Special,
5757
Vocab.App.Registration, Vocab.App.ConfigSchema,
5858
Vocab.Wildcard, Vocab.Unowned);
5959

acs-metadb/src/main/java/uk/co/amrc/factoryplus/metadb/db/RdfStore.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,16 @@ public Optional<Resource> findResource (Property pred, RDFNode obj)
132132
direct.listResourcesWithProperty(pred, obj));
133133
}
134134

135-
/* TXN */
135+
public void removeResource (Resource node)
136+
{
137+
derived.removeAll(node, null, null);
138+
derived.removeAll(null, null, node);
139+
140+
/* We don't do this yet but we may in the future. */
141+
if (node.canAs(Property.class))
142+
derived.removeAll(null, node.as(Property.class), null);
143+
}
144+
136145
public Optional<FPObject> findObject (UUID uuid)
137146
{
138147
return findResource(Vocab.uuid, Vocab.uuidLiteral(uuid))
@@ -162,7 +171,6 @@ public int findRank (Resource obj)
162171
return Util.decodeLiteral(binding.get("rank"), XSD.xint, Integer::parseInt);
163172
}
164173

165-
/* TXN */
166174
public FPObject createObject (Resource klass)
167175
{
168176
UUID uuid;
@@ -176,7 +184,6 @@ public FPObject createObject (Resource klass)
176184
return createObject(klass, uuid);
177185
}
178186

179-
/* TXN */
180187
public FPObject createObject (Resource klass, UUID uuid)
181188
{
182189
var obj = Vocab.uuidResource(uuid);
@@ -193,12 +200,11 @@ public FPObject createObject (Resource klass, UUID uuid)
193200
return new FPObject(obj, uuid);
194201
}
195202

196-
/* TXN */
197203
public Resource createInstant ()
198204
{
199-
var inst = createObject(Vocab.Instant).node();
205+
var inst = createObject(Vocab.Time.Instant).node();
200206
var stamp = derived.createTypedLiteral(Instant.now(), XSDDatatype.XSDdateTime);
201-
derived.add(inst, Vocab.timestamp, stamp);
207+
derived.add(inst, Vocab.Time.timestamp, stamp);
202208
return inst;
203209
}
204210

acs-metadb/src/main/java/uk/co/amrc/factoryplus/metadb/db/Vocab.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,26 @@ public static Property prop (String p) {
3737
public static final Property rank = prop("core/rank");
3838
public static final Property primary = prop("core/primary");
3939
public static final Property deleted = prop("core/deleted");
40-
public static final Property start = prop("core/start");
4140

4241
public static final Resource Special = res("core/Special");
4342
public static final Resource Wildcard = res("core/Wildcard");
4443
public static final Resource Unowned = res("core/Unowned");
4544

46-
public static final Resource Instant = res("core/Instant");
47-
public static final Property timestamp = prop("core/timestamp");
45+
public static class Time {
46+
public static final Resource Instant = res("time/Instant");
4847

49-
public static final Resource Application = res("core/Application");
48+
public static final Property start = prop("time/start");
49+
public static final Property timestamp = prop("time/timestamp");
50+
}
51+
52+
public static class Doc {
53+
public static final Resource Document = res("doc/Document");
54+
55+
public static final Property content = prop("doc/content");
56+
}
5057

5158
public static class App {
59+
public static final Resource Application = res("app/Application");
5260
public static final Resource Structured = res("app/Structured");
5361
public static final Resource Registration = res("app/Registration");
5462
public static final Resource ConfigSchema = res("app/ConfigSchema");

0 commit comments

Comments
 (0)