-
Notifications
You must be signed in to change notification settings - Fork 1
Propose targettype keyword for associations #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Signed-off-by: Simon Heimler <simon.heimler@sap.com>
@@ -1051,6 +1051,47 @@ schema definition, including in type unions. | |||
`$ref` is NOT permitted in other attributes and MUST NOT be used inside the | |||
`type` of the root object. | |||
|
|||
### `targettype` Keyword {#targettype-keyword} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other possible keyword names:
### `targettype` Keyword {#targettype-keyword} | |
### `target` Keyword {#targettype-keyword} |
### `targettype` Keyword {#targettype-keyword} | |
### `targetobject` Keyword {#targettype-keyword} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with the direction of this, but I would make this broader:
For objects and tuples, I would add a new keyword "relations" that is similar to "properties" but specifically defines relationship properties. "relations" and "properties" share a namespace, so they can't define conflicting names.
The "relations" declarations are not modeled as types, because they must be able to cross-reference properties within the same tuple/object. They are similar to properties in that they are represented just like properties in the instances.
A relation
is a named object (via the relations
map) that has two properties:
- the
targettype
declares the target type that the relation refers to - the
cardinality
declares whether the relationship point to one or more targets
the targettype's identity
declaration functions like the tuple
keyword for establishing the type of references, meaning that if the target's identity
clause references two properties, the reference value in the relation source is a tuple-encoded list of values matching that identity.
An instance of a single relation is an object with the following properties:
"ref" : a JSON pointer to the target object
"identity": a tuple that reflects the target object identity values
A relationship MAY be established either through a direct link (ref) or through an identity
match against all known instances of the target type. If both properties are defined, the identity
match is performed against all instances of the target type that exists within the scope of the ref
json pointer, i.e. are children of the identified node.
the value of relations with multiple
cardinality is an array of such objects. the value of relations with single
cardinality is a single such object.
{
"$schema": "https://json-structure.org/meta/core/v0/#",
"$id": "https://example.com/library.schema",
"$root": "#/definitions/Library/Document",
"definitions": {
"Library": {
/* 1 ───────── AUTHOR ───────── */
"Author": {
"type": "object",
"name": "Author",
"properties": {
"id": { "type": "uuid" },
"name": { "type": "string" }
},
"required": ["id", "name"],
"identity": ["id"]
},
/* 2 ──────── PUBLISHER ─────── */
"Publisher": {
"type": "object",
"name": "Publisher",
"properties": {
"id": { "type": "uuid" },
"name": { "type": "string" },
"city": { "type": "string" }
},
"required": ["id", "name"],
"identity": ["id"]
},
/* 3 ────────── BOOK ─────────── */
"Book": {
"type": "object",
"name": "Book",
/* intrinsic fields only — reference
properties are implicit via `relations` */
"properties": {
"isbn": { "type": "string" },
"title": { "type": "string" }
},
"required": ["isbn", "title"],
"identity": ["isbn"],
"relations": {
/* many Authors per Book */
"authors": {
"cardinality": "multiple",
"targettype": { "$ref": "#/definitions/Library/Author" }
},
/* exactly one Publisher per Book */
"publisher": {
"cardinality": "single",
"targettype": { "$ref": "#/definitions/Library/Publisher" }
}
}
},
/* 4 ──────── DOCUMENT ROOT ─────── */
"Document": {
"type": "object",
"name": "LibraryDocument",
"properties": {
/* list of all authors present in this file */
"authors": {
"type": "array",
"items": { "$ref": "#/definitions/Library/Author" }
},
/* list of all publishers */
"publishers": {
"type": "array",
"items": { "$ref": "#/definitions/Library/Publisher" }
},
/* list of all books */
"books": {
"type": "array",
"items": { "$ref": "#/definitions/Library/Book" }
}
}
}
}
}
}
Instance:
{
"$schema": "https://example.com/library.schema",
"authors": [
{
"id": "3aad369c-1bfb-11e5-9a21-1697f925ec7b",
"name": "Brian W. Kernighan"
},
{
"id": "b3e0fac1-603f-4960-8646-90b053b6af19",
"name": "Dennis M. Ritchie"
}
],
"publishers": [
{
"id": "9609d302-62fb-4d0a-9e71-86f744e3022c",
"name": "Prentice Hall"
}
],
"books": [
{
"isbn": "978-0131103627",
"title": "The C Programming Language",
"authors": [
{
"ref": "#/authors/0",
"identity": ["3aad369c-1bfb-11e5-9a21-1697f925ec7b"]
},
{
"ref": "#/authors/1",
"identity": ["b3e0fac1-603f-4960-8646-90b053b6af19"]
}
],
"publisher": {
"ref": "#/publishers/0",
"identity": ["9609d302-62fb-4d0a-9e71-86f744e3022c"]
}
}
]
}
I explicitly made the relation
instance an object, because that gives us the opportunity to declare a qualifier
type in the relation
which defines/references a type to qualify the relationship further, equivalent to link properties in a graph.
Example:
qualifier type:
"AuthorRole": {
"type": "string",
"enum": ["Author", "Editor", "Illustrator", "Translator"]
}
extend the relation:
"authors": {
"targettype": { "$ref": "#/definitions/Library/Author" },
"cardinality": "multiple",
/* NEW – the schema that qualifies the link *
* Every relation-instance object MUST carry a `qualifier` *
* that validates against this type. */
"qualifiertype": { "$ref": "#/definitions/Library/AuthorRole" }
}
Instance with qualifiers:
{
"$schema": "https://example.com/library.schema",
"authors": [
{ "id": "3aad369c-1bfb-11e5-9a21-1697f925ec7b", "name": "Brian W. Kernighan" },
{ "id": "b3e0fac1-603f-4960-8646-90b053b6af19", "name": "Dennis M. Ritchie" }
],
"publishers": [
{ "id": "9609d302-62fb-4d0a-9e71-86f744e3022c", "name": "Prentice Hall" }
],
"books": [
{
"isbn": "978-0131103627",
"title": "The C Programming Language",
"authors": [
{
"ref": "#/authors/0",
"identity": ["3aad369c-1bfb-11e5-9a21-1697f925ec7b"],
"qualifier": "Author" // ← validated by AuthorRole enum
},
{
"ref": "#/authors/1",
"identity": ["b3e0fac1-603f-4960-8646-90b053b6af19"],
"qualifier": "Author"
}
],
"publisher": {
"ref": "#/publishers/0",
"identity": ["9609d302-62fb-4d0a-9e71-86f744e3022c"]
/* no qualifier here because the relation *
* lacks a `qualifiertype` in the declaration. */
}
}
]
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like where this is going, thanks for creating this example!
Moving it to its own relation
property as an array of object seems like a really good idea.
Where I'm unsure is if we can assume that the instances are structured like you propose. I see how it's nice to make each reference an object and for convenience also adding a "ref", but in many real data cases I've seen the references are just a string property or an array of strings. The concept also needs to work with this. So the "reference" in the schema has to point to the property that carries the ID of the reference, too?
Let me get back on this to you when I have more time to think it through.
} | ||
~~~ | ||
|
||
The `targettype` MUST only be used on object properties. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@clemensv : Could it also appear in set and tuple?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You clarified it in another comment.
The `targettype` MUST only be used on object properties. | |
The `targettype` is optional, but only applicable for object or tuple properties. |
I think identities and relations would be a good companion spec. |
Relates #4
Builds upon #7
Adds the
targettype
keyword to indicate associations / references / pointers within the model.