diff --git a/docs/comparing_the_alternatives.md b/docs/comparing_the_alternatives.md index 51705707b4762472ed193bd82fddc772d6ec281e..ee7d565762680d82c3738d9b068957a4a56c8738 100644 --- a/docs/comparing_the_alternatives.md +++ b/docs/comparing_the_alternatives.md @@ -24,127 +24,21 @@ benchmark program and run it for yourself! ## Feature Breakdown -Despite the superior performance of Ferma it also supports all the features provided by the alternatives out there, not -to mention several novel features. The following gives a quick breakdown of the features of the various frameworks. We -also include a bit later in the document some Ferma examples showing the various features in action. All of the examples -below use the domain model [found here](Ferma:Domain_Example). - -| | **Ferma** | **Frames** | **Totorom** | **Peapod** | -|------------------------------------------------------------------------------------------------------------------|---------------|---------------|---------------|---------------| -| **[JPA-like Annotations](creating_annotated_domain_models)** | Supported | Supported | Not Supported | Supported | -| **[Type information encoded into graph](#type-information-encoded-into-graph)** | Supported | Supported | Supported | Supported | -| **[Framing of elements instantiated according to type hierarchy](#framing-instantiated-by-type-hierarchy)** | Supported | Supported | Supported | Supported | -| **[Element queried by type hierarchy](#element-queried-by-type-hierarchy)** | Supported | Not Supported | Not Supported | Partial \* | -| **[Turning off type resolution on a per call basis](#turning-off-type-resolution-per-call)** | Supported | Not Supported | Not Supported | Not Supported | -| **[Changing the encoded graph type already stored in the database](#changing-type-encoded-in-the-graph)** | Supported | Not Supported | Not Supported | Not Supported | -| **[Customizing the way type information is stored in the graph](#customizing-how-types-are-encoded)** | Supported | Not Supported | Not Supported | Not Supported | -| **Tinkerpop 2 support** | Supported | Supported | Supported | Not Supported | -| **Tinkerpop 3 support** | Not Supported | Not Supported | Not Supported | Supported | +Ferma also supports all the features provided by the alternatives out there, not to mention several novel features. The +following gives a quick breakdown of the features of the various frameworks. We also link to some Ferma examples showing +the various features in action. + +| Feature | **Ferma** | **Frames** | **Totorom** | **Peapod** | +|-----------------------------------------------------------------------------------------------------------------------------|---------------|---------------|---------------|---------------| +| **[JPA-like Annotations](features.md#jpa-like-annotations)** | Supported | Supported | Not Supported | Supported | +| **[Type information encoded into graph](features.md#type-information-encoded-into-graph)** | Supported | Supported | Supported | Supported | +| **[Framing of elements instantiated according to type hierarchy](features.md#framing-instantiated-by-type-hierarchy)** | Supported | Supported | Supported | Supported | +| **[Element queried by type hierarchy](features.md#element-queried-by-type-hierarchy)** | Supported | Not Supported | Not Supported | Partial \* | +| **[Turning off type resolution on a per call basis](features.md#turning-off-type-resolution-per-call)** | Supported | Not Supported | Not Supported | Not Supported | +| **[Changing the encoded graph type already stored in the database](features.md#changing-type-encoded-in-the-graph)** | Supported | Not Supported | Not Supported | Not Supported | +| **[Customizing the way type information is stored in the graph](features.md#customizing-how-types-are-encoded)** | Supported | Not Supported | Not Supported | Not Supported | +| **Tinkerpop 2 support** | Supported | Supported | Supported | Not Supported | +| **Tinkerpop 3 support** | Supported | Not Supported | Not Supported | Supported | \* While Peapod does support querying for all instances of a type, and its subtypes, it does not support a mechanism to query for a specific type while excluding subtypes. - -### Type information encoded into graph - -```java -Set<Class<?>> types = new HashSet<Class<?>>(Arrays.asList(new Class<?>[]{Person.class})); -Graph g = new TinkerGraph(); -FramedGraph fg = new DelegatingFramedGraph(g, types); - -fg.addFramedVertex(Person.class); -Person person = fg.v().next(Program.class); - -String personClassName = Person.class.getName(); -String encodedClassName = person.getProperty(PolymorphicTypeResolver.TYPE_RESOLUTION_KEY) -assert(personClassName.equals(encodedClassName)); -``` - -### Framing instantiated by type hierarchy - -```java -Set<Class<?>> types = new HashSet<Class<?>>(Arrays.asList(new Class<?>[]{Person.class, - Programmer.class})); -TinkerGraph g = new TinkerGraph(); -FramedGraph fg = new DelegatingFramedGraph(g, types); - -fg.addFramedVertex(Programmer.class); - -//make sure the newly added node is actually a programmer -Person programmer = fg.v().next(Person.class); -assert(programmer instanceof Programmer); -``` - -### Element queried by type hierarchy - -```java -Set<Class<?>> types = new HashSet<Class<?>>(Arrays.asList(new Class<?>[]{Person.class, - Programmer.class})); -TinkerGraph g = new TinkerGraph(); -FramedGraph fg = new DelegatingFramedGraph(g, types); - -fg.addFramedVertex(Programmer.class); -fg.addFramedVertex(Person.class); - -//counts how many people (or subclasses thereof) in the graph. -assert(fg.v().has(Person.class).count() == 2); -//counts how many programmers are in the graph -assert(fg.v().has(Programmer.class).count() == 1); -``` - -### Turning off type resolution per call - -```java -Set<Class<?>> types = new HashSet<Class<?>>(Arrays.asList(new Class<?>[]{Person.class, - Programmer.class})); -TinkerGraph g = new TinkerGraph(); -FramedGraph fg = new DelegatingFramedGraph(g, types); - -fg.addFramedVertex(Programmer.class); - -//With type resolution is active it should be a programmer -assert(fg.v().next(Person.class) instanceof Programmer); -//With type resolution bypassed it is no longer a programmer -assert(!(fg.v().nextExplicit(Person.class) instanceof Programmer)); -``` - -### Changing type encoded in the graph - -```java -Set<Class<?>> types = new HashSet<Class<?>>(Arrays.asList(new Class<?>[]{Person.class, - Programmer.class})); -TinkerGraph g = new TinkerGraph(); -FramedGraph fg = new DelegatingFramedGraph(g, types); - -fg.addFramedVertex(Programmer.class); - -//make sure the newly added node is actually a programmer -Person programmer = fg.v().next(Person.class); -assert(programmer instanceof Programmer); - -//change the type resolution to person -programmer.setTypeResolution(Person.class); - -//make sure the newly added node is actually a programmer -Person person = fg.v().next(Person.class); -assert(person instanceof Person); -assert(!(person instanceof Programmer)); -``` - -### Customizing how types are encoded - -```java -Set<Class<?>> types = new HashSet<Class<?>>(Arrays.asList(new Class<?>[]{Person.class})); -final ReflectionCache cache = new ReflectionCache(types); -FrameFactory factory = new AnnotationFrameFactory(cache); -TypeResolver resolver = new PolymorphicTypeResolver(cache, "customTypeKey"); -Graph g = new TinkerGraph(); -FramedGraph fg = new DelegatingFramedGraph(g, factory, resolver); - -fg.addFramedVertex(Person.class); -Person person = fg.v().next(Program.class); - -String personClassName = Person.class.getName(); -String encodedClassName = person.getProperty("customTypeKey") -assert(personClassName.equals(encodedClassName)); -``` - diff --git a/docs/features.md b/docs/features.md new file mode 100644 index 0000000000000000000000000000000000000000..68628d75fe4ceeee7c7774e0a4e4dad3e00eb73b --- /dev/null +++ b/docs/features.md @@ -0,0 +1,157 @@ +The following gives a quick breakdown of some of the features of the Ferma framework along with examples. + +* [JPA-like Annotations](#jpa-like-annotations) +* [Type information encoded into graph](#type-information-encoded-into-graph) +* [Framing of elements instantiated according to type hierarchy](#framing-instantiated-by-type-hierarchy) +* [Element queried by type hierarchy](#element-queried-by-type-hierarchy) +* [Turning off type resolution on a per call basis](#turning-off-type-resolution-per-call) +* [Changing the encoded graph type already stored in the database](#changing-type-encoded-in-the-graph) +* [Customizing the way type information is stored in the graph](#customizing-how-types-are-encoded) +* Tinkerpop 2 support +* Tinkerpop 3 support + +## JPA-like Annotations + +```Java +public abstract class Person extends AbstractVertexFrame { + @Property("name") + public abstract String getName(); + + @Property("name") + public abstract void setName(String name); + + @Adjacency(label = "knows") + public abstract List<Person> getKnowsPeople(); +} + +public abstract class Programmer extends Person { +} + +public void testAnnotatedTyping() { + Set<Class<?>> types = new HashSet<Class<?>>(Arrays.asList(new Class<?>[]{ + Person.class, + Programmer.class, + Knows.class})); + Graph graph = TinkerGraph.open(); + + //implies annotated mode + FramedGraph fg = new DelegatingFramedGraph(graph, true, types); + + Person jeff = fg.addFramedVertex(Programmer.class); + jeff.setName("Jeff"); + + Person julia = fg.addFramedVertex(Person.class); + julia.setName("Julia"); + julia.addKnows(jeff); + + Person juliaAgain = fg.traverse((g) -> g.V().has("name", "Julia")).next(Person.class); + Person jeffAgain = juliaAgain.getKnowsPeople().get(0); + + assert jeffAgain instanceof Programmer; + assert jeffAgain.getName().equals("Jeff"); +} +``` + +## Type information encoded into graph + +```java +Set<Class<?>> types = new HashSet<Class<?>>(Arrays.asList(new Class<?>[]{Person.class})); +Graph g = new TinkerGraph(); +FramedGraph fg = new DelegatingFramedGraph(g, types); + +fg.addFramedVertex(Person.class); +Person person = fg.traverse(g -> g.V()).next(Program.class); + +String personClassName = Person.class.getName(); +String encodedClassName = person.getProperty(PolymorphicTypeResolver.TYPE_RESOLUTION_KEY) +assert personClassName.equals(encodedClassName); +``` + +## Framing instantiated by type hierarchy + +```java +Set<Class<?>> types = new HashSet<Class<?>>(Arrays.asList(new Class<?>[]{Person.class, + Programmer.class})); +TinkerGraph g = new TinkerGraph(); +FramedGraph fg = new DelegatingFramedGraph(g, types); + +fg.addFramedVertex(Programmer.class); + +//make sure the newly added node is actually a programmer +Person programmer = fg.traverse(g -> g.V()).next(Person.class); +assert programmer instanceof Programmer; +``` + +## Element queried by type hierarchy + +```java +Set<Class<?>> types = new HashSet<Class<?>>(Arrays.asList(new Class<?>[]{Person.class, + Programmer.class})); +TinkerGraph g = new TinkerGraph(); +FramedGraph fg = new DelegatingFramedGraph(g, types); + +fg.addFramedVertex(Programmer.class); +fg.addFramedVertex(Person.class); + +//counts how many people (or subclasses thereof) in the graph. +assert fg.traverse(g -> g.getTypeResolver().hasType(g.V(), Person.class)).toList(Person.class).size() == 2; +//counts how many programmers are in the graph +assert fg.traverse(g -> g.getTypeResolver().hasType(g.V(), Programmer.class)).toList(Person.class).size() == 1; +``` + +## Turning off type resolution per call + +```java +Set<Class<?>> types = new HashSet<Class<?>>(Arrays.asList(new Class<?>[]{Person.class, + Programmer.class})); +TinkerGraph g = new TinkerGraph(); +FramedGraph fg = new DelegatingFramedGraph(g, types); + +fg.addFramedVertex(Programmer.class); + +//With type resolution is active it should be a programmer +assert fg.traverse(g -> g.V()).next(Person.class) instanceof Programmer; +//With type resolution bypassed it is no longer a programmer +assert !(fg.traverse(g -> g.V()).nextExplicit(Person.class) instanceof Programmer); +``` + +## Changing type encoded in the graph + +```java +Set<Class<?>> types = new HashSet<Class<?>>(Arrays.asList(new Class<?>[]{Person.class, + Programmer.class})); +TinkerGraph g = new TinkerGraph(); +FramedGraph fg = new DelegatingFramedGraph(g, types); + +fg.addFramedVertex(Programmer.class); + +//make sure the newly added node is actually a programmer +Person programmer = fg.traverse(g -> g.V()).next(Person.class); +assert programmer instanceof Programmer; + +//change the type resolution to person +programmer.setTypeResolution(Person.class); + +//make sure the newly added node is actually a programmer +Person person = fg.traverse(g -> g.V()).next(Person.class); +assert !(person instanceof Programmer); +``` + +## Customizing how types are encoded + +```java +Set<Class<?>> types = new HashSet<Class<?>>(Arrays.asList(new Class<?>[]{Person.class})); +final ReflectionCache cache = new ReflectionCache(types); +FrameFactory factory = new AnnotationFrameFactory(cache); +TypeResolver resolver = new PolymorphicTypeResolver(cache, "customTypeKey"); +Graph g = new TinkerGraph(); +FramedGraph fg = new DelegatingFramedGraph(g, factory, resolver); + +fg.addFramedVertex(Person.class); +Person person = fg.traverse(g -> g.V()).next(Programmer.class); + +String personClassName = Person.class.getName(); +String encodedClassName = person.getProperty("customTypeKey") +assert personClassName.equals(encodedClassName); +``` + diff --git a/mkdocs.yml b/mkdocs.yml index 861e69fb5a26190a7a5f1f82193e98b2dfc2f966..eacbf0c46b5cc416dbf1c29ed89edc845aed8ee6 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -11,6 +11,7 @@ site_url: 'http://syncleus.com/Ferma' pages: - Home: index.md - Getting Started: getting_started.md + - Features: features.md - Object Mapping: object_mapping.md - Core Annotations: - Overview: annotations/overview.md