diff --git a/ToDo.yaml b/ToDo.yaml index 5e327b5e3..ca25cd5f7 100644 --- a/ToDo.yaml +++ b/ToDo.yaml @@ -291,12 +291,6 @@ items: - Split Datatype pure-RegExp (with TLC, configurable in Repo) from Java Converter (with DI with @AutoService, fix): tags: [clean] - - Make Rosetta --load multiple inputs instead of --in: &rosettaLoad - - - Unify DocGen into Rosetta: - tags: [ui, docgen, rosetta] - depends: [*rosettaLoad] - - Unify UI with Rosetta: tags: [ui, rosetta] diff --git a/docs/concepts/other.md b/docs/concepts/other.md index ee484741a..c842356b1 100644 --- a/docs/concepts/other.md +++ b/docs/concepts/other.md @@ -140,6 +140,7 @@ Vaguely related other such tools include: * [`com.google.common.graph`](https://github.com/google/guava/wiki/GraphsExplained) Java API * [JGraphT](https://jgrapht.org) Java Library +* [NetworkX](https://networkx.org/) Python package [Semantic Triple](https://en.wikipedia.org/wiki/Semantic_triple) Java libraries ([comparison](https://github.com/trellis-ldp/trellis/issues/358)): @@ -189,6 +190,7 @@ Some [db-engines.com](https://db-engines.com/en/ranking/rdf+store): ### GraphML DB +* [ArangoDB](https://arangodb.com) #GraphML #opensource #commercial * [LlamaIndex](https://www.llamaindex.ai) #GraphML #opensource? #ToDo * [varunshenoy/GraphGPT](https://github.com/varunshenoy/GraphGPT) #GraphML #opensource #demo * [HKUDS/GraphGPT](https://github.com/HKUDS/GraphGPT) #GraphML #opensource #paper diff --git a/docs/use/get/index.md b/docs/use/get/index.md index 18a082315..3fb0510ff 100644 --- a/docs/use/get/index.md +++ b/docs/use/get/index.md @@ -39,3 +39,5 @@ Get something from a loaded 🐢 Turtle resource, e.g. from the [enola.dev/enola $ ./enola get --load models/enola.dev/enola.ttl https://enola.dev/emoji | head --lines=3 ... ``` + +Note that `get` [supports various formats](../help/index.md#get). diff --git a/java/dev/enola/cli/BUILD b/java/dev/enola/cli/BUILD index d18242f4a..e2ea9e3c8 100644 --- a/java/dev/enola/cli/BUILD +++ b/java/dev/enola/cli/BUILD @@ -48,6 +48,7 @@ java_binary( "//java/dev/enola/infer/datalog", "//java/dev/enola/model", "//java/dev/enola/rdf/io", + "//java/dev/enola/rdf/proto", "//java/dev/enola/thing:thing_java", "//java/dev/enola/thing:thing_java_proto", "//java/dev/enola/thing/gen", @@ -57,6 +58,8 @@ java_binary( "@maven//:com_google_protobuf_protobuf_java", "@maven//:info_picocli_picocli", "@maven//:org_apache_logging_log4j_log4j_to_jul", + "@maven//:org_eclipse_rdf4j_rdf4j_model", + "@maven//:org_eclipse_rdf4j_rdf4j_rio_api", "@maven//:org_jspecify_jspecify", "@maven//:org_slf4j_slf4j_api", "@maven//:org_slf4j_slf4j_jdk14", diff --git a/java/dev/enola/cli/CommandWithIRI.java b/java/dev/enola/cli/CommandWithIRI.java index b39b3feb4..af6b5f0d7 100644 --- a/java/dev/enola/cli/CommandWithIRI.java +++ b/java/dev/enola/cli/CommandWithIRI.java @@ -28,6 +28,18 @@ import dev.enola.core.proto.EnolaServiceGrpc.EnolaServiceBlockingStub; import dev.enola.core.proto.GetFileDescriptorSetRequest; import dev.enola.core.view.EnolaMessages; +import dev.enola.rdf.io.RdfWriterConverter; +import dev.enola.rdf.proto.ProtoThingRdfConverter; +import dev.enola.thing.gen.graphviz.GraphvizGenerator; +import dev.enola.thing.message.ProtoThings; +import dev.enola.thing.metadata.ThingMetadataProvider; +import dev.enola.thing.proto.Thing; +import dev.enola.thing.proto.Things; +import dev.enola.web.EnolaThingProvider; + +import org.eclipse.rdf4j.model.impl.SimpleValueFactory; +import org.eclipse.rdf4j.model.util.ModelBuilder; +import org.eclipse.rdf4j.rio.helpers.StatementCollector; import picocli.CommandLine; @@ -38,7 +50,7 @@ public abstract class CommandWithIRI extends CommandWithModelAndOutput { @CommandLine.Option( names = {"--format", "-f"}, required = true, - defaultValue = "YAML", + defaultValue = "Turtle", description = "Output Format: ${COMPLETION-CANDIDATES}; default=${DEFAULT-VALUE}") Format format; @@ -49,9 +61,12 @@ public abstract class CommandWithIRI extends CommandWithModelAndOutput { private WritableResource resource; private TypeRegistryWrapper typeRegistryWrapper; protected EnolaMessages enolaMessages; + private ThingMetadataProvider thingMetadataProvider; @Override protected final void run(EnolaServiceBlockingStub service) throws Exception { + thingMetadataProvider = getMetadataProvider(new EnolaThingProvider(service)); + var gfdsr = GetFileDescriptorSetRequest.newBuilder().build(); var fds = service.getFileDescriptorSet(gfdsr).getProtos(); typeRegistryWrapper = TypeRegistryWrapper.from(fds); @@ -73,6 +88,27 @@ protected final void run(EnolaServiceBlockingStub service) throws Exception { protected abstract void run(EnolaServiceBlockingStub service, String eri) throws Exception; protected void write(Message thing) throws IOException { + if (Format.Turtle.equals(format) || Format.JSONLD.equals(format)) { + var model = new ModelBuilder().build(); + var statementCollector = new StatementCollector(model); + if (thing instanceof Thing protoThing) { + var vf = SimpleValueFactory.getInstance(); + new ProtoThingRdfConverter(vf).convertInto(protoThing, statementCollector); + } else if (thing instanceof Things protoThings) { + for (var protoThing : protoThings.getThingsList()) + new ProtoThingRdfConverter().convertInto(protoThing, statementCollector); + } + new RdfWriterConverter().convertIntoOrThrow(model, resource); + return; + } + + if (Format.Graphviz.equals(format) && thing instanceof Things protoThings) { + var javaThings = ProtoThings.proto2java(protoThings.getThingsList()); + new GraphvizGenerator(thingMetadataProvider).convertIntoOrThrow(javaThings, resource); + return; + } + + // Otherwise new ProtoIO(typeRegistryWrapper.get()).write(thing, resource); } } diff --git a/java/dev/enola/cli/EnolaCLITest.java b/java/dev/enola/cli/EnolaCLITest.java index d0ba85636..9d5869e30 100644 --- a/java/dev/enola/cli/EnolaCLITest.java +++ b/java/dev/enola/cli/EnolaCLITest.java @@ -215,7 +215,7 @@ public void getList() { var exec = cli("-vvv", "get", "--load", MODEL, "enola:/"); var run = assertThat(exec); run.err().isEmpty(); - run.hasExitCode(0).out().contains("https://enola.dev/emoji"); + run.hasExitCode(0).out().contains("enola:emoji"); } @Test diff --git a/java/dev/enola/cli/Format.java b/java/dev/enola/cli/Format.java index 9931e61f9..f7b523d25 100644 --- a/java/dev/enola/cli/Format.java +++ b/java/dev/enola/cli/Format.java @@ -20,28 +20,34 @@ import com.google.common.net.MediaType; import dev.enola.common.protobuf.ProtobufMediaTypes; +import dev.enola.rdf.io.RdfMediaTypes; +import dev.enola.thing.gen.graphviz.GraphvizMediaType; public enum Format { + Turtle, + + JSONLD, + + Graphviz, + TextProto, - YAML, + ProtoYAML, - JSON, + ProtoJSON, BinaryPB; MediaType toMediaType() { - switch (this) { - case TextProto: - return ProtobufMediaTypes.PROTOBUF_TEXTPROTO_UTF_8; - case YAML: - return ProtobufMediaTypes.PROTOBUF_YAML_UTF_8; - case JSON: - return ProtobufMediaTypes.PROTOBUF_JSON_UTF_8; - case BinaryPB: - return ProtobufMediaTypes.PROTOBUF_BINARY; - default: - throw new IllegalStateException(); - } + return switch (this) { + case Turtle -> RdfMediaTypes.TURTLE; + case JSONLD -> RdfMediaTypes.JSON_LD; + case Graphviz -> GraphvizMediaType.GV; + + case TextProto -> ProtobufMediaTypes.PROTOBUF_TEXTPROTO_UTF_8; + case ProtoYAML -> ProtobufMediaTypes.PROTOBUF_YAML_UTF_8; + case ProtoJSON -> ProtobufMediaTypes.PROTOBUF_JSON_UTF_8; + case BinaryPB -> ProtobufMediaTypes.PROTOBUF_BINARY; + }; } } diff --git a/java/dev/enola/cli/GetCommand.java b/java/dev/enola/cli/GetCommand.java index 2492afb38..219febaa4 100644 --- a/java/dev/enola/cli/GetCommand.java +++ b/java/dev/enola/cli/GetCommand.java @@ -25,8 +25,6 @@ @Command(name = "get", description = "Get Thing") public class GetCommand extends CommandWithIRI { - // TODO Add "export" support; e.g. to get as *.ttl - @Override protected void run(EnolaServiceBlockingStub service, String iri) throws Exception { var request = GetThingRequest.newBuilder().setIri(iri).build(); diff --git a/java/dev/enola/common/protobuf/ProtobufMediaTypes.java b/java/dev/enola/common/protobuf/ProtobufMediaTypes.java index a3232eb87..91d371002 100644 --- a/java/dev/enola/common/protobuf/ProtobufMediaTypes.java +++ b/java/dev/enola/common/protobuf/ProtobufMediaTypes.java @@ -68,11 +68,11 @@ public static Optional getProtoMessageFQN(MediaType mediaType) { public static final MediaType PROTOBUF_TEXTPROTO_UTF_8 = MediaType.create("text", "protobuf").withCharset(StandardCharsets.UTF_8); - // TODO Rethink, and doc, what this actually means? Isn't a "ProtoBuf JSON" really just JSON?! + /** "ProtoBuf as JSON" - which is different from e.g. a JSON-LD representation of RDF. */ public static final MediaType PROTOBUF_JSON_UTF_8 = MediaType.create("text", "protobuf+json").withCharset(StandardCharsets.UTF_8); - // TODO Rethink, and doc, what this actually means? Isn't a "ProtoBuf YAML" really just YAML?! + /** "ProtoBuf as YAML" - which is different from e.g. a YAML-LD representation of RDF. */ public static final MediaType PROTOBUF_YAML_UTF_8 = MediaType.create("text", "protobuf+yaml").withCharset(StandardCharsets.UTF_8);