Query into dynamic data using static key paths

Hello,

I am currently porting Automerge to swift. It is a CRDT. You can create a document, sync the content to different devices, edit concurrently, sync it back and end up with consistent data on every device. (It is amazing!!!)

Internally it transforms the data heavily and just syncs operations instead of the new state of the document. This requires dynamic information of the data.
When initialising an document I transform a Codable struct in a dictionary and iterate over all keys, which gives me the required dynamic.

But when modifying the document, I use a swift key path which carries all the static information I need, but lacks the dynamic key path. As a workaround the user of the API needs to pass a string in a similar format of the key path to satisfy the required dynamic.

let trip = Trip(name, "Summer 2020", stops: [])
let document = Automerge.Document(trip)

var mutableDocument = document
mutableDocument.change { doc
  doc[\.stops, "stops"].append(Stop(name: "Munich", night: 0))
  doc[\.stops, "stops"].append(Stop(name: "Rome", night: 2))
}
mutableDocument.change { doc
  doc[\.name, "name"] = "Summer 2021"
  doc[\.stops[1].nights, "stops[1].nights"] = 3
}

This works, but obviously comes with some disadvantages.

  • Easy to mistype key paths.
  • If underlying coding keys are customised, it breaks
  • strange looking API, imagine it could be as clear as key path member lookup

I did a lot of research, but could not find a way to get dynamic coding keys of a key path. I am looking for something between dynamic member lookup and keypath member lookup.
I would support such a feature, and would like to help refine it in the future.

Cheers
Lukas

[automerge-swift](GitHub - automerge/automerge-swift: Wrapper around Swift types that can be modified concurrently by different users, and merged again automatically (a CRDT).

2 Likes

One option that is not type-safe could be dynamic member lookup that access properties through their string names with a library like Runtime. The obvious disadvantage here is that you can't type-check that a property is assigned a value of correct type.

Even though the Runtime library doesn't support key paths, I think there should be a way that allows converting fully typed keypaths to corresponding property name strings, I would be surprised if key paths don't have metadata associated with them that allows that. Even indirectly, you probably could infer property metadata from a key path object, and then get a property name from the property metadata. But that would require a deeper investigation of the runtime internals.

1 Like

If you're using a library like Runtime to access layout metadata, one thing you could do for stored keypaths is try to match the result of MemoryLayout.offset(of: keyPath) to the offsets of the fields in a struct, in order to map it to a property name that way.

3 Likes

Ok. As far as I understand it, Runtime is the way to go?.

@Joe_Groff Could you explain in a bit more detail what is necessary to achieve this ( Or give some general reference, where I can learn about the the swift runtime and how to access its meta information). I never queried into the runtime before.
Will the result be just the last key path component or the whole (".stops[1].nights") key path.

It not good enough, MemoryLayout.offset supports only Values-Type, for properties in class type, it returns nil