1 of 45

LDO’s New Stuff

Solid Support, React Support, API changes, NextGraph Support, Link Query, Svelte Support, and a New Data Browser

2 of 45

I’m Jackson Morgan!

Contact me at https://o.team!

3 of 45

4 of 45

5 of 45

What is LDO (Linked Data Objects)?

6 of 45

7 of 45

1. Build from Schema

PREFIX ex: <https://example.com/>

PREFIX foaf: <http://xmlns.com/foaf/0.1/>

PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

PREFIX ns: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

ex:FoafProfile EXTRA a {

foaf:name xsd:string

// rdfs:comment "A profile has 1 names" ;

foaf:title ns:langString *

// rdfs:comment "A profile has 0-∞ titles" ;

foaf:knows @ex:FoafProfile *

// rdfs:comment "A profile has 0-∞ friends." ;

}

export const foafProfileContext: ContextDefinition = {

name: {

"@id": "http://xmlns.com/foaf/0.1/name",

"@type": "http://www.w3.org/2001/XMLSchema#string",

},

title: {

"@id": "http://xmlns.com/foaf/0.1/title",

"@type": "http://www.w3.org/1999/02/22-rdf-syntax-ns#langString",

"@container": "@set",

},

knows: {

"@id": "http://xmlns.com/foaf/0.1/knows",

"@type": "@id",

"@container": "@set",

},

};

export interface FoafProfile {

"@id"?: string;

"@context"?: ContextDefinition;

name: string;

title?: string[];

knows?: FoafProfile[];

}

8 of 45

2. Parse RDF

const rawTurtle = `

@prefix example: <https://example.com/>.

@prefix foaf: <http://xmlns.com/foaf/0.1/>.

@prefix xsd: <http://www.w3.org/2001/XMLSchema#>.

@prefix ns: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.

example:Taggart

foaf:name "Peter Quincy Taggart" ;

foaf:knows example:Lazarus .

example:Lazarus

foaf:name "Lazarus of Tev'Meck" ;

foaf:title "Doctor"^^ns:langString ;

foaf:title "Docteur"@fr ;

foaf:knows example:Taggart .

`;

const ldoDataset = await parseRdf(rawTurtle, { format: "Turtle" });

9 of 45

3. Create a Linked Data Object

import { FoafProfileShapeType } from

"./ldo/foafProfile.shapeTypes";

const taggart = ldoDataset

.usingType(FoafProfileShapeType)

.setLanguagePreferences("en", "@none")

.fromSubject("https://example.com/Taggart");

10 of 45

4. Reading and Modifying Data

console.log(taggart.name);

console.log(

ldoDataset.match(

namedNode("https://example.com/Taggart"),

namedNode("http://xmlns.com/foaf/0.1/name"),

null

).toArray()[0].object.value

);

ldoDataset.deleteMatches(

namedNode("https://example.com/Taggart"),

namedNode("http://xmlns.com/foaf/0.1/name")

);

ldoDataset.add(quad(

namedNode("https://example.com/Taggart"),

namedNode("http://xmlns.com/foaf/0.1/name"),

literal("Jason Nesmith")

));

taggart.name = "Jason Nesmith";

=

=

11 of 45

Arrays are now Sets

person.roommate = {

"@id": "https://example.com/Person2",

name: [

"Garrett",

"Bobby",

"Ferguson”

]

}

import { LdSet, set } from "@ldo/ldo";

�person.roommate = {

"@id": "https://example.com/Person2",

name: set(

"Garrett",

"Bobby",

"Ferguson

)

}

OLD

NEW

12 of 45

  • LDO lets you manipulated RDF like it’s regular JavaScript
  • We start with a Schema (ShEx) and run a “build” command to generate TypeScript typings and context from it.
  • Everything you do is reading and writing to an underlying dataset.

Section Review!

13 of 45

@ldo/connected-solid

14 of 45

.getResource

import { createSolidLdoDataset } from "@ldo/connected-solid";

const solidLdoDataset = createSolidLdoDataset();

const profileResource =

solidLdoDataset.getResource("https://example.com/profile");

Fig. 6. The getResource method is used to retrieve a Resource from a SolidLdoDataset

15 of 45

Read + Error Handling

import { createSolidLdoDataset } from "@ldo/connected-solid";

import { ProfileShapeType } from "./.ldo/Profile.shapeType";

 

async function main() {

// Create a SolidLdoDataset

const solidLdoDataset = createSolidLdoDataset();

// Get a resource representation

const resource1 = solidLdoDataset.getResource("https://example.com/resource1");

// Read the resource

const readResult = await resource1.read();

// Handle possible errors

if (readResult.isError) {

// Different errors can be handled based on their error type. In this case,

// the "read" method could encounter one of 6 error types.

switch (readResult.type) {

case "serverError":

case "unauthenticatedError":

case "unauthorizedError":

case "noncompliantPodError":

case "unexpectedResourceError":

case "unexpectedHttpError":

console.error(result.message);

return;

}

}

16 of 45

Creating Resources and Modifying Data

// Create the resource if it was absent. (This could also be done with the

// createIfAbsent method.

if (resource1.isAbsent()) {

const createResult = await resource1.createAndOverwrite();

// ... Handle createResult

}

// Create a treansaction save some data to the resource

const transaction = solidLdoDataset.startTransaction();

// Create a linked data object for easy manipulation. Any changes on this

// linked data object will be written to resource1

const profile = solidLdoDataset

.usingType(ProfileShapeType)

.write(resource1.uri)

.fromSubject("https://example.com/resource1#profile");

profile.name = "John Doe";

// Commit the changes to the Pod

const commitResult = await transaction.commitToRemote();

// ... Handle commitResult

}

17 of 45

Problem: Two resources with the same subject

# Located at "https://example.com/profile"

@prefix prof: <https://example.com/profile#>.

@prefix foaf: <http://xmlns.com/foaf/0.1/>.

 

prof:me foaf:name "John Doe".

 

 

# Located at "https://otherSite.com/friendsList"

@prefix prof: <https://example.com/profile#>.

@prefix foaf: <http://xmlns.com/foaf/0.1/>.

 

prof:me foaf:knows <https://example.com/friend1#me>.

prof:me foaf:knows <https://example.com/friend2#me>.

Fig. 5. Two resources can contain information on the same subject.

18 of 45

Other Support

  • Managing Containers (Parent and Children)
  • Subscribing to Notifications
  • Resource Status (isLoading, isFetched, etc.)
  • Batching requests

19 of 45

  • A solidLdoDataset keeps track of both tiples and the resources that contain them.
  • You can use resource methods like “read” and “createAndOverwrite” to manipulate resources.
  • Errors are returned, not thrown.
  • Once a resource is loaded, its triples are mixed in with triples from other resources.

Section Review!

20 of 45

@ldo/connected

21 of 45

How createSolidLdoDataset works under the covers

export function createSolidLdoDataset() {

const solidLdoDataset = new ConnectedLdoDataset(

[solidConnectedPlugin],

createDatasetFactory(),

createTransactionDatasetFactory(),

);

return solidLdoDataset;

}

22 of 45

“Plugins” is an array…

export function createSolidLdoDataset() {

const solidLdoDataset = new ConnectedLdoDataset(

[solidConnectedPlugin, nextGraphConnectedPlugin],

createDatasetFactory(),

createTransactionDatasetFactory(),

);

return solidLdoDataset;

}

23 of 45

@ldo/connected-nextgraph

24 of 45

NextGraph works the same!

const resource = ldoDataset.getResource(

"did:ng:o:W6GCQRfQkNTLtSS_2-QhKPJPkhEtLVh-

B5lzpWMjGNEA:v:h8ViqyhCYMS2I6IKwPrY6UZi4ougUm1gpM4QnxlmNMQA"

);

const readResult = await resource.read();

if (!readResult.isError) {

console.log("Resource loaded!", readResult.type);

}

25 of 45

  • There’s Plugins!
  • And NextGraph is now one of them!

Section Review!

26 of 45

@ldo/react and�@ldo/solid-react

27 of 45

Initializing React

import { solidConnectedPlugin } from "@ldo/connected-solid";

import { createLdoReactMethods } from "@ldo/react";

/**

* Default exports for just Solid methods

*/

export const {

dataset,

useLdo,

useMatchObject,

useMatchSubject,

useResource,

useSubject,

useSubscribeToResource,

useLinkQuery,

} = createLdoReactMethods([solidConnectedPlugin]);

28 of 45

Or just use the solid-react library

import { solidConnectedPlugin } from "@ldo/connected-solid";

import { createLdoReactMethods } from "@ldo/react";

�/**

* Default exports for just Solid methods

*/

export const {

dataset,

useLdo,

useMatchObject,

useMatchSubject,

useResource,

useSubject,

useSubscribeToResource,

useLinkQuery,

} = createLdoReactMethods([solidConnectedPlugin]);

import {

dataset,

useLdo,

useResource,

useSubject

} from "@ldo/solid-react";

29 of 45

30 of 45

React Component

Hooks like useResource and useSubject

ldoDataset

31 of 45

useResource

import { useResource } from "@ldo/solid-react";

import React, { FunctionComponent } from "react";

 

export const Component: FunctionComponent = () => {

// Trigger the useResource hook

const resource = useResource("https://example.com/some_container/", {

// If true, this will not trigger a "read" operation automatically

suppressInitialRead: false,

// If true, this will trigger the "read" operation every time this component

// mounts.

reloadOnMount: false

});

 

// Use the "isLoading" API on the Resource class

if (resource.isLoading()) {

return <p>Loading...</p>

}

return (

<ul>

{/* Access the "children" API on the Container class */}

{resource.children().map((child) => (

<li>{child.uri}</li>

))}

</ul>

);

}

32 of 45

useSubject

import { useSubject } from "@ldo/solid-react";

import React, { FunctionComponent } from "react";

import { ProfileShapeType } from "./.ldo/Profile.shapeType";

 

export const Component: FunctionComponent = () => {

// Get a linked data object of type "Profile" with the id

// "https://example.com/profile#me"

const profile = useSubject(ProfileShapeType, "https://example.com/profile#me");

 

return <div>

{/* Render the name of the profile */}

<p>Name: {profile?.name}</p>

<p>Friends:</p>

<ul>

{/* Render the name of all the profile's friends */}

{profile?.knows((friend) => {

return <li>{friend.name}</li>

})}

</ul>

</div>

}

33 of 45

  • LDO’s react support follows the react state flow.
  • useResource is a react hook that fetches a resource and lets you keep track of its status
  • Hooks like useSubject will give you data from the dataset and trigger a rerender if it’s changed

Section Review!

34 of 45

Link Query

35 of 45

Example Data

@prefix foaf: <http://xmlns.com/foaf/0.1/> .

@prefix : <#> .

:me a foaf:Person ;

foaf:name "Main User" ;

foaf:knows <http://localhost:3005/test-container/otherProfile.ttl#me> .

@prefix foaf: <http://xmlns.com/foaf/0.1/> .

@prefix : <#> .

:me a foaf:Person ;

foaf:name "Other User" .

http://localhost:3005/test-container/mainProfile.ttl

http://localhost:3005/test-container/otherProfile.ttl

36 of 45

Performing a Link Query

const data = await solidLdoDataset

.usingType(SolidProfileShapeShapeType)

.startLinkQuery(

mainProfileResource,

"http://localhost:3005/test-container/mainProfile.ttl",

{

name: true,

knows: {

name: true,

},

},

)

.run();

37 of 45

Intellisense

38 of 45

Link Query in React

const linkQuery = {

name: true,

knows: {

name: true,

},

} as const;

const Component: FunctionComponent = () => {

const profile = useLinkQuery(

SolidProfileShapeShapeType,

MAIN_PROFILE_URI,

MAIN_PROFILE_SUBJECT,

linkQuery,

);

if (!profile) return <p>Loading</p>;

return (

<div>

<p role="profile-name">{profile.name}</p>

<ul role="list">

{profile.knows?.map((nestedProfile) => (

<li key={nestedProfile["@id"]}>{nestedProfile.name}</li>

))}

</ul>

</div>

);

};

39 of 45

  • Link Query allows you to gather data from multiple documents through link traversal
  • The documents are defined by a type-enforced query object
  • Support for both regular TypeScript, React, and a special third thing…

Section Review!

40 of 45

@ldo/svelte

41 of 45

Initializing Svelte

import { createLdoSvelteMethods } from "@ldo/svelte";

import { solidConnectedPlugin } from "@ldo/connected-solid";

export const {

dataset,

useLdo,

useMatchObject,

useMatchSubject,

useResource,

useSubject,

useSubscribeToResource,

useLinkQuery,

} = createLdoSvelteMethods([solidConnectedPlugin]);

42 of 45

Svelte Example

<script lang="ts">

import { SolidProfileShapeShapeType } from "./.ldo/solidProfile.shapeTypes.js";

import { useResource, useSubject } from "./ldoSvelteMethods.js";

const SAMPLE_DATA_URI =

"http://localhost:3004/example/link-query/main-profile.ttl";

const resource = useResource(SAMPLE_DATA_URI);

const webId = `${SAMPLE_DATA_URI}#me`;

const profile = useSubject(SolidProfileShapeShapeType, webId);

$: friendArray = $profile?.knows?.toArray() || [];

$: firstFriendId =

friendArray.length > 0 ? friendArray[0]?.["@id"] : undefined;

</script>

<h1>LDO Svelte Support Demo</h1>

{#if $resource.isLoading() || !$profile}

<p>loading</p>

{:else}

<div>

{#if firstFriendId}

<p>{firstFriendId}</p>

{:else}

<p>No friend found or friend has no @id.</p>

{/if}

43 of 45

  • All the react hooks also have a counterpart in Svelte!

Section Review!

44 of 45

Linked Data Browser (LDB)

45 of 45

In conclusion

  • There’s a ton of stuff
  • See documentation at https://ldo.js.org
  • Reach out to me at https://o.team