diff --git a/.changeset/purple-pots-fold.md b/.changeset/purple-pots-fold.md new file mode 100644 index 000000000..c02348c86 --- /dev/null +++ b/.changeset/purple-pots-fold.md @@ -0,0 +1,5 @@ +--- +"@osdk/maker": minor +--- + +Update ontology as code interface link types to reflect internal expectations of ontology integration diff --git a/.vscode/settings.json b/.vscode/settings.json index f8830bca7..1070a890e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,7 +5,7 @@ "editor.defaultFormatter": "dprint.dprint" }, "[typescript]": { - "editor.defaultFormatter": "dprint.dprint" + "editor.defaultFormatter": "vscode.typescript-language-features" }, "[json]": { "editor.defaultFormatter": "dprint.dprint" diff --git a/packages/maker/src/api/defineInterfaceLinkConstraint.ts b/packages/maker/src/api/defineInterfaceLinkConstraint.ts index 3b2cb7d6a..c3b55cb12 100644 --- a/packages/maker/src/api/defineInterfaceLinkConstraint.ts +++ b/packages/maker/src/api/defineInterfaceLinkConstraint.ts @@ -18,68 +18,52 @@ import invariant from "tiny-invariant"; import type { InterfaceType } from "./types.js"; type Meta = { apiName: string; displayName?: string; description?: string }; -type ApiNameOrMeta = string | Meta; +type ApiNameOrInterfaceType = string | InterfaceType; -type Many = { type: InterfaceType; many: ApiNameOrMeta; one?: never }; -type One = { type: InterfaceType; one: ApiNameOrMeta; many?: never }; +type Many = { + apiName: string; + from: InterfaceType; + toMany: ApiNameOrInterfaceType; + toOne?: never; + displayName?: string; + description?: string; +}; +type One = { + apiName: string; + from: InterfaceType; + toOne: ApiNameOrInterfaceType; + toMany?: never; + displayName?: string; + description?: string; +}; export function defineInterfaceLinkConstraint( - { from, to }: { - from: Many; - to: One; - } | { - from: One; - to: One | Many; - }, + linkDef: One | Many, ) { - invariant( - (from.one == null && from.many) || (from.one && from.many == null), - "from should have either one or many, not both", - ); - - invariant( - (to.one == null && to.many) || (to.one && to.many == null), - "to should have either one or many, not both", - ); - - invariant(!(from.many && to.many), "many to many is not supported"); - - const fromLinkMeta = getLinkMeta(from.one ?? from.many); - const toLinkMeta = getLinkMeta(to.one ?? to.many); + const fromLinkMeta = getLinkMeta(linkDef); invariant( - from.type.links.find(a => a.metadata.apiName === fromLinkMeta.apiName) + linkDef.from.links.find(a => a.metadata.apiName === fromLinkMeta.apiName) == null, - `Link with apiName ${fromLinkMeta.apiName} already exists on ${from.type.apiName}`, - ); - invariant( - to.type.links.find(a => a.metadata.apiName === toLinkMeta.apiName) == null, - `Link with apiName ${toLinkMeta.apiName} already exists on ${to.type.apiName}`, + `Link with apiName ${fromLinkMeta.apiName} already exists on ${linkDef.apiName}`, ); - from.type.links.push({ - cardinality: from.many ? "MANY" : "SINGLE", - linkedEntityTypeId: getLinkedType(to.type), + linkDef.from.links.push({ + cardinality: linkDef.toMany ? "MANY" : "SINGLE", + linkedEntityTypeId: getLinkedType(linkDef.toMany ?? linkDef.toOne), metadata: fromLinkMeta, required: true, // TODO: expose this? }); - - to.type.links.push({ - cardinality: to.one ? "SINGLE" : "MANY", - linkedEntityTypeId: getLinkedType(from.type), - metadata: toLinkMeta, - required: true, // TODO: expose this? - }); } -function getLinkedType(t: InterfaceType) { +function getLinkedType(t: string | InterfaceType) { return { type: "interfaceType" as const, - interfaceType: t.apiName, + interfaceType: typeof t === "string" ? t : t.apiName, }; } -function getLinkMeta(meta: ApiNameOrMeta) { +function getLinkMeta(meta: One | Many) { return typeof meta === "string" ? withDefaults({ apiName: meta }) : withDefaults(meta); diff --git a/packages/maker/src/api/overall.test.ts b/packages/maker/src/api/overall.test.ts index 29f3c0810..15b27dd05 100644 --- a/packages/maker/src/api/overall.test.ts +++ b/packages/maker/src/api/overall.test.ts @@ -217,45 +217,12 @@ describe("Ontology Defining", () => { b = defineInterface({ apiName: "B" }); }); - it("many to many fails", () => { - expect(() => { - // @ts-expect-error - defineInterfaceLinkConstraint({ - from: { type: a, many: "manyLinks" }, // need the any to be sure it fails - to: { type: b, many: "manyLinks" }, - }); - }).toThrowErrorMatchingInlineSnapshot( - `[Error: Invariant failed: many to many is not supported]`, - ); - }); - - it("does not allow passing both one and many", () => { - expect(() => { - defineInterfaceLinkConstraint({ - // @ts-expect-error - from: { type: a, one: "singleLink", many: "manyLinks" }, // need the any to be sure it fails - to: { type: b, one: "singleLink" }, - }); - }).toThrowErrorMatchingInlineSnapshot( - `[Error: Invariant failed: from should have either one or many, not both]`, - ); - - expect(() => { - defineInterfaceLinkConstraint({ - from: { type: a, one: "singleLink" }, // need the any to be sure it fails - // @ts-expect-error - to: { type: b, one: "singleLink", many: "manyLinks" }, - }); - }).toThrowErrorMatchingInlineSnapshot( - `[Error: Invariant failed: to should have either one or many, not both]`, - ); - }); - - it("single to single works", () => { + it("single link works", () => { expect(a).not.toBeUndefined(); defineInterfaceLinkConstraint({ - from: { type: a, one: "singleLink" }, - to: { type: b, one: "singleLink" }, + from: a, + toOne: b, + apiName: "singleLink", }); expect(dumpOntologyFullMetadata()).toMatchInlineSnapshot(` @@ -312,109 +279,7 @@ describe("Ontology Defining", () => { "icon": undefined, }, "extendsInterfaces": [], - "links": [ - { - "cardinality": "SINGLE", - "linkedEntityTypeId": { - "interfaceType": "A", - "type": "interfaceType", - }, - "metadata": { - "apiName": "singleLink", - "description": "singleLink", - "displayName": "singleLink", - }, - "required": true, - }, - ], - "properties": [], - "status": { - "active": {}, - "type": "active", - }, - }, - }, - }, - "sharedPropertyTypes": {}, - } - `); - }); - - it("many to single works", () => { - defineInterfaceLinkConstraint({ - from: { type: a, many: "manyLinks" }, - to: { type: b, one: "singleLink" }, - }); - - expect(dumpOntologyFullMetadata()).toMatchInlineSnapshot(` - { - "blockPermissionInformation": { - "actionTypes": {}, - "linkTypes": {}, - "objectTypes": {}, - }, - "interfaceTypes": { - "A": { - "interfaceType": { - "allExtendsInterfaces": [], - "allLinks": [], - "allProperties": [], - "apiName": "A", - "displayMetadata": { - "description": "A", - "displayName": "A", - "icon": undefined, - }, - "extendsInterfaces": [], - "links": [ - { - "cardinality": "MANY", - "linkedEntityTypeId": { - "interfaceType": "B", - "type": "interfaceType", - }, - "metadata": { - "apiName": "manyLinks", - "description": "manyLinks", - "displayName": "manyLinks", - }, - "required": true, - }, - ], - "properties": [], - "status": { - "active": {}, - "type": "active", - }, - }, - }, - "B": { - "interfaceType": { - "allExtendsInterfaces": [], - "allLinks": [], - "allProperties": [], - "apiName": "B", - "displayMetadata": { - "description": "B", - "displayName": "B", - "icon": undefined, - }, - "extendsInterfaces": [], - "links": [ - { - "cardinality": "SINGLE", - "linkedEntityTypeId": { - "interfaceType": "A", - "type": "interfaceType", - }, - "metadata": { - "apiName": "singleLink", - "description": "singleLink", - "displayName": "singleLink", - }, - "required": true, - }, - ], + "links": [], "properties": [], "status": { "active": {}, @@ -428,10 +293,11 @@ describe("Ontology Defining", () => { `); }); - it("single to many works", () => { + it("many link works", () => { defineInterfaceLinkConstraint({ - from: { type: a, one: "singleLink" }, - to: { type: b, many: "manyLinks" }, + from: a, + toMany: b, + apiName: "manyLink", }); expect(dumpOntologyFullMetadata()).toMatchInlineSnapshot(` @@ -462,9 +328,9 @@ describe("Ontology Defining", () => { "type": "interfaceType", }, "metadata": { - "apiName": "singleLink", - "description": "singleLink", - "displayName": "singleLink", + "apiName": "manyLink", + "description": "manyLink", + "displayName": "manyLink", }, "required": true, }, @@ -488,21 +354,7 @@ describe("Ontology Defining", () => { "icon": undefined, }, "extendsInterfaces": [], - "links": [ - { - "cardinality": "MANY", - "linkedEntityTypeId": { - "interfaceType": "A", - "type": "interfaceType", - }, - "metadata": { - "apiName": "manyLinks", - "description": "manyLinks", - "displayName": "manyLinks", - }, - "required": true, - }, - ], + "links": [], "properties": [], "status": { "active": {},