Example: Get user data with friend data


#1

I don’t know if this is a good implementation or not, please feel free to give me your feedback.

Is there any chance we’ll be getting ES6 in Gizmo? Query code would be more readable.


#2

Awesome, thanks @rm-rf-etc!

I would suggest to change node IDs and predicates to IRIs in the dataset (add <> quotes). Technically the current dataset is not a valid nquad file, although Cayley allows those.

After the dataset is changed, We can also add an example how to achieve the same result with our GraphQL dialect. It’s less flexible, but it will work extremely well for this particular use case.

Re: ES6, we will be happy to add support for it, but it relies on ES6 support in any Go implementation of JS. We currently use Goja and it only supports ES5.


#3

With Cayley’s official JavaScript client library out you can now use modern JavaScript code for queries.
Here’s a version of your code using the library:

import * as cayley from "@cayleygraph/cayley";

const { g } = cayley.Client();

async function predicatesToList(thingId) {
  const results = await g
    .V(thingId)
    .out(g.V(), "property")
    .tag("value")
    .all();
  return results.map(result => [result.property, result.value]);
}

async function followLinks(options, data) {
  if (options && Object.keys(options).length) {
    await Promise.all(Object.entries(options).filter(([key]) => key).map(async ([action, predicate]) => {
      if (action === "follow") {
        await Promise.all(Array.from(data[predicate].entries(), async ([idx, nodeId]) => {
          data[predicate][idx] = await getThing(nodeId, { omit: "<friend>" });
        }))
      } else if (action === "omit") {
        delete data[predicate];
      }
    }))
  }
  return data;
}

function collapseArray(array) {
  const result = {};
  for (const [key, val] of array) {
    if (key.startsWith("<") && key.endsWith(">")) {
      result[key] = result[key] || [];
      result[key].push(val);
    } else {
      result[key] = val;
    }
  }
  return result;
}

async function getThing(thingId, options) {
  var asArray = await predicatesToList(thingId);
  var asObject = collapseArray(asArray);
  var finalResults = await followLinks(options, asObject);
  finalResults.id = thingId;
  return finalResults;
}

g.emit(getThing("uuid12345", { follow: "<friend>" }));

#4

Thanks for the feedback, guys. @dennwc, are IRI’s in the docs? The angle brackets in some of the examples didn’t make sense to me. Why do subjects and predicates both need angle brackets, but objects do not?

And what does IRI stand for?


#5

The angle brackets represents RDF identifiers (IRI / BNode). In RDF subjects are always identifiers and predicates are always IRIs.