Options
All
  • Public
  • Public/Protected
  • All
Menu

Used to express an ordered set of data. A List object is reified to a Subject (unlike in JSON-LD) and so it has an @id, which can be set by the user.

Examples:


A priority list of preferences

The second subject in this array shows how the first subject (the List) can be referenced by another subject. When inserting data it might be more readable to simply nest the list under the interests property in the outer subject, fred.

[{
  "@id": "fredInterests",
  "@list": ["Lounging", "Bowling", "Pool", "Golf", "Poker"]
}, {
  "@id": "fred",
  "interests": { "@id": "fredInterests" }
}]

A chronology of referenced subjects

{
  "@id": "fredAppearsIn",
  "@list": [
    { "@type": "Episode", "name": "The Flintstone Flyer" },
    { "@type": "Episode", "name": "Hot Lips Hannigan" },
    { "@type": "Episode", "name": "The Swimming Pool" }
  ]
}

🚧 This engine does not support use of the @list keyword in a JSON-LD Context term definition.

import { clone, uuid } from 'https://js.m-ld.org/ext/index.mjs';
import { MemoryLevel } from 'https://js.m-ld.org/ext/memory-level.mjs';
import { IoRemotes } from 'https://js.m-ld.org/ext/socket.io.mjs';

// m-ld extensions are loaded using their package identity (@m-ld/m-ld/ext/..).
// In a real app, this redirection should be done with an import map.
globalThis.require = module => import(module
  .replace(/@m-ld\/m-ld\/ext\/(\w+)/, 'https://js.m-ld.org/ext/$1.mjs'));

globalThis.changeDomain = async function (domain) {
  const genesis = !domain;
  if (genesis)
    domain = `${uuid()}.public.gw.m-ld.org`;
  if (window.model) {
    await window.model.state.close();
    delete window.model;
  }
  const state = await clone(new MemoryLevel(), IoRemotes, {
    '@id': uuid(),
    '@domain': domain,
    genesis,
    io: { uri: "https://gw.m-ld.org" }
  });
  // Uncomment the next line to log individual updates as they come in
  //state.follow(update => console.info('UDPATE', JSON.stringify(update)));
  domainInput.value = domain;
  appDiv.hidden = false;
  playgroundAnchor.setAttribute('href', `https://m-ld.org/playground/#domain=${domain}`);
  // Store the "model" as a global for access by other scripts, and tell them
  window.model = { domain, state, genesis };
  document.dispatchEvent(new Event('domainChanged'));
}

/**
 * Utility to populate a template. Returns an object containing the cloned
 * children of the template, also indexed by tagName and classname.
 */
globalThis.templated = template => new Proxy({ $: template.content.cloneNode(true) }, {
  get: (t, p) => t[p] ?? t.$.querySelector(p) ?? t.$.querySelector(`.${p}`)
});

document.querySelectorAll('.help').forEach(help => helpDetails.appendChild(templated(help).$));
<div>
  <a id="playgroundAnchor" target="_blank" title="go to playground">🛝</a>
  <input id="domainInput" type="text" placeholder="domain name" onfocus="this.select()"/>
  <button onclick="changeDomain(domainInput.value)">Join</button>
  <button onclick="changeDomain()">New ⭐️</button>
  <details id="helpDetails">
    <summary>🔢 help...</summary>
    <p>This live code demo shows how to share live information with <b>m-ld</b>.</p>
    <p>To get started with a new set of information (a "domain"), click New ⭐️ above. You can then interact with the mini-application below to create some information.</p>
    <p>To share the information with a duplicate of this page:<ol><li>copy the domain name above</li><li>duplicate the browser tab</li><li>paste the domain name into the new page's domain input</li><li>click Join</li></ol></p>
    <p>You can also share with the <b>m-ld</b> playground using the 🛝 button.</p>
  </details>
  <hr/>
</div>
import { updateSubject } from 'https://js.m-ld.org/ext/index.mjs';

document.addEventListener('domainChanged', async () => {
  shoppingList.innerHTML = '';
  const { state, genesis } = window.model;
  if (genesis) {
    // Write some initial shopping items to the state
    state.write({
      '@id': 'shopping',
      '@list': ['bread', 'milk']
    });
  }
  // To use updateSubject for updating the DOM, we use a Javascript object-like
  // proxy pattern over the relevant Elements.
  const shopping = {
    '@id': 'shopping',
    '@list': {
      // For a List, updateSubject can apply the update to anything with a
      // `length` and an Array-like `splice` method.
      get length() {
        return shoppingList.childElementCount;
      },
      splice(index, deleteCount, ...items) {
        for (let i = 0; i < deleteCount; i++)
          shoppingList.children[index]?.remove();
        const { el, position } = index < this.length ?
          { el: shoppingList.children[index], position: 'beforebegin' } :
          { el: shoppingList, position: 'beforeend' };
        for (let item of items)
          el.insertAdjacentHTML(position, `<li>${item}</li>`);
      }
    }
  };

  state.read(
    async state => updateSubject(shopping, await state.get('shopping')),
    update => updateSubject(shopping, update)
  );
});

addItem.addEventListener('click', () => {
  window.model.state.write({
    '@id': 'shopping',
    // When writing list items, we can use an object with integer keys instead
    // of an array. Here we're inserting at the end of the list.
    '@list': { [shoppingList.childElementCount]: itemToAdd.value }
  });
});

removeItem.addEventListener('click', () => {
  window.model.state.write({
    '@delete': {
      '@id': 'shopping',
      // When deleting list items, we can pattern-match using variables. Here,
      // we want to delete the removed item wherever it appears in the list.
      '@list': { '?': itemToRemove.value }
    }
  });
});
<div id="appDiv" hidden>
  <h2>Shopping</h2>
  <ol id="shoppingList"></ol>
  <p>
    <input id="itemToAdd" type="text" placeholder="new shopping item"/>
    <button id="addItem">+ Add</button>
  </p>
  <p>
    <input id="itemToRemove" type="text" placeholder="shopping item to remove"/>
    <button id="removeItem">- Remove</button>
  </p>
  <hr/>
</div>
see

m-ld Lists specification

see

json-rql list

Hierarchy

Indexable

[key: string]: SubjectPropertyObject | Context | undefined

Specifies a graph edge, that is, a mapping from the @id of this subject to a set of one or more values.

Examples:


A priority list of preferences

The second subject in this array shows how the first subject (the List) can be referenced by another subject. When inserting data it might be more readable to simply nest the list under the interests property in the outer subject, fred.

[{
  "@id": "fredInterests",
  "@list": ["Lounging", "Bowling", "Pool", "Golf", "Poker"]
}, {
  "@id": "fred",
  "interests": { "@id": "fredInterests" }
}]

A chronology of referenced subjects

{
  "@id": "fredAppearsIn",
  "@list": [
    { "@type": "Episode", "name": "The Flintstone Flyer" },
    { "@type": "Episode", "name": "Hot Lips Hannigan" },
    { "@type": "Episode", "name": "The Swimming Pool" }
  ]
}

🚧 This engine does not support use of the @list keyword in a JSON-LD Context term definition.

import { clone, uuid } from 'https://js.m-ld.org/ext/index.mjs';
import { MemoryLevel } from 'https://js.m-ld.org/ext/memory-level.mjs';
import { IoRemotes } from 'https://js.m-ld.org/ext/socket.io.mjs';

// m-ld extensions are loaded using their package identity (@m-ld/m-ld/ext/..).
// In a real app, this redirection should be done with an import map.
globalThis.require = module => import(module
  .replace(/@m-ld\/m-ld\/ext\/(\w+)/, 'https://js.m-ld.org/ext/$1.mjs'));

globalThis.changeDomain = async function (domain) {
  const genesis = !domain;
  if (genesis)
    domain = `${uuid()}.public.gw.m-ld.org`;
  if (window.model) {
    await window.model.state.close();
    delete window.model;
  }
  const state = await clone(new MemoryLevel(), IoRemotes, {
    '@id': uuid(),
    '@domain': domain,
    genesis,
    io: { uri: "https://gw.m-ld.org" }
  });
  // Uncomment the next line to log individual updates as they come in
  //state.follow(update => console.info('UDPATE', JSON.stringify(update)));
  domainInput.value = domain;
  appDiv.hidden = false;
  playgroundAnchor.setAttribute('href', `https://m-ld.org/playground/#domain=${domain}`);
  // Store the "model" as a global for access by other scripts, and tell them
  window.model = { domain, state, genesis };
  document.dispatchEvent(new Event('domainChanged'));
}

/**
 * Utility to populate a template. Returns an object containing the cloned
 * children of the template, also indexed by tagName and classname.
 */
globalThis.templated = template => new Proxy({ $: template.content.cloneNode(true) }, {
  get: (t, p) => t[p] ?? t.$.querySelector(p) ?? t.$.querySelector(`.${p}`)
});

document.querySelectorAll('.help').forEach(help => helpDetails.appendChild(templated(help).$));
<div>
  <a id="playgroundAnchor" target="_blank" title="go to playground">🛝</a>
  <input id="domainInput" type="text" placeholder="domain name" onfocus="this.select()"/>
  <button onclick="changeDomain(domainInput.value)">Join</button>
  <button onclick="changeDomain()">New ⭐️</button>
  <details id="helpDetails">
    <summary>🔢 help...</summary>
    <p>This live code demo shows how to share live information with <b>m-ld</b>.</p>
    <p>To get started with a new set of information (a "domain"), click New ⭐️ above. You can then interact with the mini-application below to create some information.</p>
    <p>To share the information with a duplicate of this page:<ol><li>copy the domain name above</li><li>duplicate the browser tab</li><li>paste the domain name into the new page's domain input</li><li>click Join</li></ol></p>
    <p>You can also share with the <b>m-ld</b> playground using the 🛝 button.</p>
  </details>
  <hr/>
</div>
import { updateSubject } from 'https://js.m-ld.org/ext/index.mjs';

document.addEventListener('domainChanged', async () => {
  shoppingList.innerHTML = '';
  const { state, genesis } = window.model;
  if (genesis) {
    // Write some initial shopping items to the state
    state.write({
      '@id': 'shopping',
      '@list': ['bread', 'milk']
    });
  }
  // To use updateSubject for updating the DOM, we use a Javascript object-like
  // proxy pattern over the relevant Elements.
  const shopping = {
    '@id': 'shopping',
    '@list': {
      // For a List, updateSubject can apply the update to anything with a
      // `length` and an Array-like `splice` method.
      get length() {
        return shoppingList.childElementCount;
      },
      splice(index, deleteCount, ...items) {
        for (let i = 0; i < deleteCount; i++)
          shoppingList.children[index]?.remove();
        const { el, position } = index < this.length ?
          { el: shoppingList.children[index], position: 'beforebegin' } :
          { el: shoppingList, position: 'beforeend' };
        for (let item of items)
          el.insertAdjacentHTML(position, `<li>${item}</li>`);
      }
    }
  };

  state.read(
    async state => updateSubject(shopping, await state.get('shopping')),
    update => updateSubject(shopping, update)
  );
});

addItem.addEventListener('click', () => {
  window.model.state.write({
    '@id': 'shopping',
    // When writing list items, we can use an object with integer keys instead
    // of an array. Here we're inserting at the end of the list.
    '@list': { [shoppingList.childElementCount]: itemToAdd.value }
  });
});

removeItem.addEventListener('click', () => {
  window.model.state.write({
    '@delete': {
      '@id': 'shopping',
      // When deleting list items, we can pattern-match using variables. Here,
      // we want to delete the removed item wherever it appears in the list.
      '@list': { '?': itemToRemove.value }
    }
  });
});
<div id="appDiv" hidden>
  <h2>Shopping</h2>
  <ol id="shoppingList"></ol>
  <p>
    <input id="itemToAdd" type="text" placeholder="new shopping item"/>
    <button id="addItem">+ Add</button>
  </p>
  <p>
    <input id="itemToRemove" type="text" placeholder="shopping item to remove"/>
    <button id="removeItem">- Remove</button>
  </p>
  <hr/>
</div>
see

m-ld Lists specification

see

json-rql list

Index

json-rql Properties

Other Properties

json-rql Properties

Subject

Subject: SubjectConstructor = class implements Subject {[key: string]: Subject['any'];constructor(value: Subject) {Object.assign(this, value);}}

Constructor of subjects from subjects: used similarly to e.g. Number

Other Properties

Optional @context

@context: Context

A JSON-LD Context for the query. In an API, this will frequently be implicit. For example, using json-rql as the body of a POST to http://example.com/my-api/v1/person/query might have the implicit context of a Person (possibly found at http://example.com/my-api/v1/person).

see

examples

Optional @id

@id: Iri | Variable

The unique identity of the subject in the domain.

🚧 Subjects strictly need not be identified with an @id, but the data of such Subjects cannot be retrieved with a simple Describe query.

@list

@list: SubjectPropertyObject[] | {}

An array or indexed-object representation of the list contents. Each "item" in the list can be any of the normal subject property objects, such as strings, numbers, booleans or References to other subjects.

The indexed-object notation is used to insert or delete items at a specific list index, expressed as a number or numeric string. For more explanation, see the m-ld Lists specification.

Optional @type

@type: Iri | Variable | Iri[] | Variable[]

The type of the subject, as an IRI or set of IRIs. (@type is actually shorthand for the RDF property rdf:type.)

Legend

  • Constructor
  • Property
  • Method
  • Property
  • Method
  • Inherited property
  • Inherited method
  • Static property
  • Static method
  • Protected method

Generated using TypeDoc. Delivered by Vercel. @m-ld/m-ld - v0.10.0 Source code licensed MIT. Privacy policy