Hi Everyone,
I am happy to announce the release of Twig 1.0 featuring Parallel
Asynchronous Commands, a fluent command interface and tons of
performance enhancing features to really make your applications fly
and reduce development time. Twig is an alternative to the standard
persistence interfaces JDO and JPA, specifically designed to make the
most of the underlying datastore's unique features.
Twig is the only datastore interface that allows you to execute
queries and store data in parallel without blocking. If you run 10
queries in a request your app could now run up to 10 times faster!
// execute a query but don't wait for the results
Future<QueryResultIterator<Band>> futureBands =
datastore.find().type(Band.class).returnResultsLater();
// do some other processing or store data while the first command runs
Key key =
datastore
.store
().instances(myLittlePonies).withParent(bigDaddyPony).returnKeyNow();
// now block until the first command is finished
Iterator<Band> bands = futureBands.get();
Twig is the only interface to support direct unowned relationships so
your code is not dependent on low-level datastore classes. It is the
only interface to support OR queries by merging together multiple
queries, sorting them and filtering out duplicates at the lowest level
for performance.
No need to register persistent classes - most objects can be stored
with _no_ configuration. Twig is built for speed so it has no start-
up overhead and provides many unique performance optimisation features.
Stop wasting time wrestling with JDO! Details, documents and
downloads at http://code.google.com/p/twig-persist/
Or read on for a summary of what else Twig can do...
== Persist any Java object graph with no dependencies on the datastore
==
With Twig you store plain Java objects with direct references to each
other - just like real Java.
class MusicFestival
{
Date when;
List<Band> bands; // Unique to Twig
}
class Band
{
@Key String name; // key is optional and can be almost any type
int performanceFee;
}
// create a complex object graph - example taken from the unit tests
MusicFestival festival = ...
// create an implementation - usually done in a factory or Guice
Provider
ObjectDatastore datastore = new AnnotationObjectDatastore();
// store the entire object graph of referenced instances
Key key = datastore.store(festival);
// find all instances of a type
Iterator<Band> bands = datastore.find(Band.class);
Band nostalgia = datastore.load(Band.class, "Nostalgia 77"); // load
by key
// delete all bands - time to go home
datastore.deleteAll(Band.class);
== Fluent Interface API ==
Using Twig's fluent interface makes code easier to read and more
difficult to make mistakes. http://martinfowler.com/bliki/FluentInterface.html
// store all bands with their record label as parent - notice it
knows we will return "keys"
Map<Band, Key> keys =
datastore.store().instances(bands).withParent(label).returnKeysNow();
// find all bands exploited by EMI - we want results now
Iterator<Band> exploited = datastore.find()
.type(Band.class)
.addFilter("albums.sold", GREATER_THAN, 1000)
.withAncestor(emi)
.startFom(15)
.returnResultsNow();
You can only ever use options that are valid depending on the other
options you have set.
Read on to see how "returnResultsLater()" can make your applications
faster.
== Polymorphism and Inheritance ==
RockBand extends Band
{
HairStyle hair;
}
festival.bands.add(ledZeppelin);
datastore.update(festival);
You can store any subtype of Band
== Embedded Collections ==
Say we want to display a list of a bands albums when we display the
bands profile page. By embedding the collection of albums in the same
entity as the band details we can save a lot of load operations.
class Band
{
@Key String name;
int performanceFee;
@Embed Set<Album> albums; // albums are embedded in the same
entity
}
This also means we can query for bands on an albums properties which
take multiple queries in JDO and JPA. To find all bands with platinum
albums is easy and fast:
Iterator<Band> popularBands =
datastore.find()
.type(Band.class)
.addFilter("albums.sold", GREATER_THAN, 1000000)
.returnResultsNow();
== Relationships managed directly ==
No more messing about with Keys and extracting parent keys and
creating child keys.
class Album
{
@Key String name;
@Child List<Track> tracks; // all stored as children - also use on
single member
}
class Track
{
@Parent Album album;
@Key String name;
Duration length; // most classes can be stored without
configuration
}
The parent field is automatically set to the parent instance by using
the Tracks key. Twig is the only datastore interface that supports
these simple direct references
== Parallel Asynchronous Commands ==
Datastore queries can only return contiguous results from an index
which forces many useful operators such as OR, IN and NOT_EQUAL to be
broken down into multiple queries. Currently these must be executed
serially one after the other which slows down you application. Not
anymore! Twig 1.0 introduces parallel asynchronous commands which
execute at the same time and only block when you need the results.
// find all tracks from the album but ask for the results in the future
Future<Iterator<Track>> futureTracks =
datastore.find()
.type(Track.class)
.addFilter("duration" GREATER_THAN, 5.0)
.returnResultsLater();
// do some other queries and what not...
// now wait for the query to finish and get the results
Iterator<Track> tracks = futureTracks.get();
Storing data can take a long time and often we just want to return to
the user immediately without waiting to see if it was successful.
// store multiple instances but don't wait
Future<Key> futureKey =
datastore.store().instance(aLateArrival).returnKeyLater();
Future<Map<Band, Key>> futureKeys =
datastore.store().instances(lotsOfBands).returnKeysLater();
Notice that the fluent interface uses generics to know that the result
will be Band Keys and that a single instance will return a single Key
- return*Key*Later()
== Merged Sorted Queries ==
Handling OR queries yourself and merging the results is difficult
especially if the results are sorted. Twig makes it simple to execute
multiple queries in parallel and then return you a single iterator.
Here we define two queries which will be merged together - the results
will have duplicates filtered out and the sort order will be maintained.
datastore
.find()
.type(Band.class)
.addChildQurey() // creates a new child query that inherits
features from its parent
.addFilter("albums.sold", GREATER_THAN, 1000000)
.addChlidQuery() // creates a new child query to run in parallel
with the first
.addFilter("performanceFee", GREATER_THAN, 1000)
.returnResultsNow(); // actually executes in parallel but waits
for all queries
This returns all bands that are highly paid OR sold a platinum album.
Merged AND queries are not yet supported but will be in a future
release.
== High Performance Features ==
Parallel commands and embedded collections go a long way to speed up
your application. There are many
more performance related features designed to get the most out of your
quotas
* Low-level filters: exclude certain Entities or properties of an
entity from ever being translated
* Shortened Kind name: The name of the kind can be stored many times
in your Entities so storing just an abbreviation can save a lot of space
* Bulk storeAll() method which also batches together all referenced
instances in the same store operation.
== Type Conversion ==
Twig comes with several useful type converters or you can define
custom type converters .
class Band
{
@Type(Blob.class) Image photo; // convert the image to a blob in
the datastore
...
}
== Relational Index Entities ==
Support for Relation Index Entites as described in Bret Slatkin's talk
Lost more features not covered here. Check it out
http://code.google.com/p/twig-persist/
John
--
You received this message because you are subscribed to the Google Groups "Google
App Engine for Java" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/google-appengine-java?hl=en.