Skip to content

Proposal: Improve mappingΒ #427

@nikgraf

Description

@nikgraf

Currently we use the type IDs and property IDs to map between the local Schema and the public Graph. For private spaces we use the names of the actual schema e.g.

export class Todo extends Entity.Class<Todo>('Todo')({
  name: Type.String,
  completed: Type.Boolean,
}) {}

in Automerge stores:

{
  entities: [
    {
       name: 'call CEO',
       completed: true,
       _types: ['Todo'] 
    }
  ]
}

This is problematic since it doesn't allow for interoperability in private spaces since all of them would need to implement the same Schema names. Instead we want:

{
  entities: [
    {
      'a126ca53-0c8e-48d5-b888-82c734c38935': 'call CEO',
      '1765d387-6c28-4baa-9ed8-061704fa010d': true,
      _type: ['ab700a03-ae75-4fdc-8806-cb8445dcd9b5']
    }
  ]
}

This means every Type schould have at least one valid type ID and for ever property a valid id.

Issues with the current mapping file structure

  • We don't have any validation of Schema to Mapping
  • The mapping file is globally defined and to be passed into the AppProvider. (No code-splitting possible of the mapping, not a good architecture for large applications)
  • We have several places where we map the schema/mapping and if doesn't fit we have to bail out with errors during runtime. That's quite ugly. Ideally we can throw an error right in the beginning when starting the programm.

Proposal

We inline the mapping IDs directly into the schema. This way we can have static

export class User extends Entity.Class<User>('User', '0929ef5e-746b-4cce-aaeb-2a7e101c2e55')({
  name: Type.String('a126ca53-0c8e-48d5-b888-82c734c38935'),
}) {}

export class Todo extends Entity.Class<Todo>('Todo', 'ab700a03-ae75-4fdc-8806-cb8445dcd9b5')({
  name: Type.String('a126ca53-0c8e-48d5-b888-82c734c38935'),
  completed: Type.Boolean('1765d387-6c28-4baa-9ed8-061704fa010d'),
  assignees: Type.Relation(User, '1203064e-9741-4235-89d4-97f4b22eddfb'),
}) {}

This means we also could provided default types like we provide System IDs on grc-20-ts e.g.

import { SystemTypes, SystemIds } = "@graphprotocol/hypergraph"

export class User extends Entity.Class<User>('User', '0929ef5e-746b-4cce-aaeb-2a7e101c2e55')({
  name: SystemTypes.name, // more convenient than Type.String('a126ca53-0c8e-48d5-b888-82c734c38935')
}) {}

export class Todo extends Entity.Class<Todo>('Todo', 'ab700a03-ae75-4fdc-8806-cb8445dcd9b5')({
  name: SystemTypes.name,
  completed: SystemTypes.completed,
  assignees: Type.Relation(User, SystemIds.assignees),
}) {}

Benefits

  • If you don't provide a string TS will error!
  • We can check the validity of the mapping right at the beginning when the program starts compared to when you actually start a query (better for DX)

Note: Under the hood we would attach the ID as annotation to Effect. This would be very nice to access every time we need to convert data between local version to be used by devs to the public graph/automerge storage version.

  name: Type.String.pipe(Schema.annotations({
    [Hypergraph.Symbol]: "'f60585af-71b6-4674-9a26-b74ca6c1cceb'"
  })),

Alternative design

Why I would not like to go with it:

  • Lot's of unnecessary code duplication (the whole structure is duplicated)
  • This could work, but is much harder to make type safe and afaik we can't use Effect Schema annotations
export class User extends Entity.Class<User>('User', '0929ef5e-746b-4cce-aaeb-2a7e101c2e55')({
  name: Type.String,
}) {
  mapping = {
    typeIds: ['0929ef5e-746b-4cce-aaeb-2a7e101c2e55'],
    properties: {
      name: Id('a126ca53-0c8e-48d5-b888-82c734c38935'),
    },
  }
}

export class Todo extends Entity.Class<Todo>('Todo', 'ab700a03-ae75-4fdc-8806-cb8445dcd9b5')({
  name: Type.String,
  completed: Type.Boolean,
  assignees: Type.Relation(User),
}) {
  mapping = {
    typeIds: [Id('0929ef5e-746b-4cce-aaeb-2a7e101c2e55')],
    properties: {
      name: Id('a126ca53-0c8e-48d5-b888-82c734c38935'),
      completed: Id('1765d387-6c28-4baa-9ed8-061704fa010d'),
    },
    relations: {
       assignees: ['1203064e-9741-4235-89d4-97f4b22eddfb']
    }
  }
}

Open Question

  • Can I put a 'TODO' or other placeholder there? If yes, we shouldn't could still do UUID validation, but show a warning in the console.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions