Skip to content

Commit

Permalink
Interfaces for Subscribe (#1018)
Browse files Browse the repository at this point in the history
* Interfaces for subscribe

* Update for reference updates

* Update

* changeset
  • Loading branch information
nihalbhatnagar authored Nov 26, 2024
1 parent 2da8c42 commit 1c59d93
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 25 deletions.
5 changes: 5 additions & 0 deletions .changeset/forty-ligers-scream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@osdk/client": patch
---

Allows interfaces to be used with subscribe
70 changes: 49 additions & 21 deletions packages/client/src/objectSet/ObjectSetListenerWebsocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ import WebSocket from "isomorphic-ws";
import invariant from "tiny-invariant";
import type { Logger } from "../Logger.js";
import type { ClientCacheKey, MinimalClient } from "../MinimalClientContext.js";
import { convertWireToOsdkObjects } from "../object/convertWireToOsdkObjects.js";
import {
convertWireToOsdkObjects,
convertWireToOsdkObjects2,
} from "../object/convertWireToOsdkObjects.js";

const MINIMUM_RECONNECT_DELAY_MS = 5 * 1000;

Expand Down Expand Up @@ -65,7 +68,8 @@ interface Subscription<
> {
listener: Required<ObjectSetListener<Q, P>>;
objectSet: ObjectSet;
primaryKeyPropertyName: string;
interfaceApiName?: string;
primaryKeyPropertyName?: string;
requestedProperties: Array<P>;
requestedReferenceProperties: Array<P>;
subscriptionId: string;
Expand Down Expand Up @@ -173,31 +177,49 @@ export class ObjectSetListenerWebsocket {
globalThis.crypto ??= (await import("node:crypto")).webcrypto as any;
}

const objDef = await this.#client.ontologyProvider.getObjectDefinition(
objectType.apiName,
);
const objDef = objectType.type === "object"
? await this.#client.ontologyProvider.getObjectDefinition(
objectType.apiName,
)
: await this.#client.ontologyProvider.getInterfaceDefinition(
objectType.apiName,
);

if (properties.length === 0) {
properties = Object.keys(objDef.properties) as Array<P>;
}
let objectProperties: Array<P> = [];
let referenceProperties: Array<P> = [];

const objectProperties = properties.filter((p) =>
objDef.properties[p].type !== "geotimeSeriesReference"
);
const referenceProperties = properties.filter((p) =>
objDef.properties[p].type === "geotimeSeriesReference"
);
if (objectType.type === "object") {
if (properties.length === 0) {
properties = Object.keys(objDef.properties) as Array<P>;
}

objectProperties = properties.filter((p) =>
objDef.properties[p].type !== "geotimeSeriesReference"
);

referenceProperties = properties.filter((p) =>
objDef.properties[p].type === "geotimeSeriesReference"
);
} else {
objectProperties = [];
referenceProperties = properties;
}

const sub: Subscription<Q, P> = {
listener: fillOutListener<Q, P>(listener),
objectSet,
primaryKeyPropertyName: objDef.primaryKeyApiName,
primaryKeyPropertyName: objDef.type === "interface"
? undefined
: objDef.primaryKeyApiName,
requestedProperties: objectProperties,
requestedReferenceProperties: referenceProperties,
status: "preparing",
// Since we don't have a real subscription id yet but we need to keep
// track of this reference, we can just use a random uuid.
subscriptionId: `TMP-${crypto.randomUUID()}`,
interfaceApiName: objDef.type === "object"
? undefined
: objDef.apiName,
};

this.#subscriptions.set(sub.subscriptionId, sub);
Expand Down Expand Up @@ -273,7 +295,12 @@ export class ObjectSetListenerWebsocket {
const subscribe: ObjectSetStreamSubscribeRequests = {
id,
requests: readySubs.map<ObjectSetStreamSubscribeRequest>((
{ objectSet, requestedProperties, requestedReferenceProperties },
{
objectSet,
requestedProperties,
requestedReferenceProperties,
interfaceApiName,
},
) => {
return {
objectSet: objectSet,
Expand Down Expand Up @@ -432,15 +459,17 @@ export class ObjectSetListenerWebsocket {
);
const osdkObjectsWithReferenceUpdates = await Promise.all(
referenceUpdates.map(async (o) => {
const osdkObjectArray = await convertWireToOsdkObjects(
const osdkObjectArray = await this.#client.objectFactory(
this.#client,
[{
__apiName: o.objectType,
__primaryKey: o.primaryKey[sub.primaryKeyPropertyName],
__primaryKey: sub.primaryKeyPropertyName != null
? o.primaryKey[sub.primaryKeyPropertyName]
: undefined,
...o.primaryKey,
[o.property]: o.value,
}],
undefined,
sub.interfaceApiName,
) as Array<Osdk.Instance<any, never, any>>;
const singleOsdkObject = osdkObjectArray[0] ?? undefined;
return singleOsdkObject != null
Expand All @@ -465,11 +494,10 @@ export class ObjectSetListenerWebsocket {
for (const key of keysToDelete) {
delete o.object[key];
}

const osdkObjectArray = await this.#client.objectFactory(
this.#client,
[o.object],
undefined,
sub.interfaceApiName,
) as Array<Osdk.Instance<any, never, any>>;
const singleOsdkObject = osdkObjectArray[0] ?? undefined;
return singleOsdkObject != null
Expand Down
23 changes: 22 additions & 1 deletion packages/e2e.generated.catchall/ontology.json
Original file line number Diff line number Diff line change
Expand Up @@ -245,13 +245,18 @@
"visibility": "NORMAL"
},
"linkTypes": [],
"implementsInterfaces": ["FooInterface"],
"implementsInterfaces": ["FooInterface", "OsdkTestInterface"],
"implementsInterfaces2": {
"FooInterface": {
"properties": {
"name": "osdkObjectName",
"description": "description"
}
},
"OsdkTestInterface": {
"properties": {
"objectDescription": "description"
}
}
},
"sharedPropertyTypeMapping": {}
Expand Down Expand Up @@ -1294,6 +1299,22 @@
},
"rid": "ri.ontology.main.interface-type.1b1b1b1b-1b1b-1b1b-1b1b-1b1b1b1b1b1b",
"status": "ACTIVE"
},
"OsdkTestInterface": {
"apiName": "OsdkTestInterface",
"displayName": "OsdkTestInterface",
"description": "OsdkTestInterface",
"properties": {
"objectDescription": {
"rid": "ri.ontology.main.shared-property.751ed7ee-5d2c-41a1-bf60-9cbef5623f23",
"apiName": "objectDescription",
"dataType": {
"type": "string"
}
}
},
"rid": "ri.ontology.main.interface.06c534fd-4f68-44d9-b268-72729a47eaab",
"status": "ACTIVE"
}
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export {
editOsdkTestObject,
} from './ontology/actions.js';
export * as $Actions from './ontology/actions.js';
export { FooInterface, InterfaceNoProps } from './ontology/interfaces.js';
export { FooInterface, InterfaceNoProps, OsdkTestInterface } from './ontology/interfaces.js';
export * as $Interfaces from './ontology/interfaces.js';
export {
BoundariesUsState,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { FooInterface } from './interfaces/FooInterface.js';
export { InterfaceNoProps } from './interfaces/InterfaceNoProps.js';
export { OsdkTestInterface } from './interfaces/OsdkTestInterface.js';
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import type { PropertyDef as $PropertyDef } from '@osdk/client';
import { $osdkMetadata } from '../../OntologyMetadata.js';

import type {
InterfaceDefinition as $InterfaceDefinition,
ObjectSet as $ObjectSet,
Osdk as $Osdk,
PropertyValueWireToClient as $PropType,
} from '@osdk/client';

export type OsdkObjectLinks$OsdkTestInterface = {};

export namespace OsdkTestInterface {
export type PropertyKeys = 'objectDescription';

export interface Props {
readonly objectDescription: $PropType['string'] | undefined;
}
export type StrictProps = Props;

export interface ObjectSet extends $ObjectSet<OsdkTestInterface, OsdkTestInterface.ObjectSet> {}

export type OsdkInstance<
OPTIONS extends never | '$rid' = never,
K extends keyof OsdkTestInterface.Props = keyof OsdkTestInterface.Props,
> = $Osdk.Instance<OsdkTestInterface, OPTIONS, K>;

/** @deprecated use OsdkInstance */
export type OsdkObject<
OPTIONS extends never | '$rid' = never,
K extends keyof OsdkTestInterface.Props = keyof OsdkTestInterface.Props,
> = OsdkInstance<OPTIONS, K>;
}

export interface OsdkTestInterface extends $InterfaceDefinition {
osdkMetadata: typeof $osdkMetadata;
type: 'interface';
apiName: 'OsdkTestInterface';
__DefinitionMetadata?: {
objectSet: OsdkTestInterface.ObjectSet;
props: OsdkTestInterface.Props;
linksType: OsdkObjectLinks$OsdkTestInterface;
strictProps: OsdkTestInterface.StrictProps;
apiName: 'OsdkTestInterface';
description: 'OsdkTestInterface';
displayName: 'OsdkTestInterface';
links: {};
properties: {
/**
* (no ontology metadata)
*/
objectDescription: $PropertyDef<'string', 'nullable', 'single'>;
};
rid: 'ri.ontology.main.interface.06c534fd-4f68-44d9-b268-72729a47eaab';
type: 'interface';
};
}

export const OsdkTestInterface: OsdkTestInterface = {
type: 'interface',
apiName: 'OsdkTestInterface',
osdkMetadata: $osdkMetadata,
};
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,24 @@ export interface OsdkTestObject extends $ObjectTypeDefinition {
color: '#4C90F0';
name: 'cube';
};
implements: ['FooInterface'];
implements: ['FooInterface', 'OsdkTestInterface'];
interfaceMap: {
FooInterface: {
name: 'osdkObjectName';
description: 'description';
};
OsdkTestInterface: {
objectDescription: 'description';
};
};
inverseInterfaceMap: {
FooInterface: {
osdkObjectName: 'name';
description: 'description';
};
OsdkTestInterface: {
description: 'objectDescription';
};
};
links: {};
pluralDisplayName: 'Osdk Test Objects';
Expand Down
29 changes: 28 additions & 1 deletion packages/e2e.sandbox.catchall/src/runSubscriptionsTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ import {
__EXPERIMENTAL__NOT_SUPPORTED_YET__preexistingObjectSet,
__EXPERIMENTAL__NOT_SUPPORTED_YET_subscribe,
} from "@osdk/api/unstable";
import { $Actions, MtaBus, OsdkTestObject } from "@osdk/e2e.generated.catchall";
import {
$Actions,
MtaBus,
OsdkTestInterface,
OsdkTestObject,
} from "@osdk/e2e.generated.catchall";
import { client, dsClient } from "./client.js";

export async function runSubscriptionsTest() {
Expand Down Expand Up @@ -67,6 +72,28 @@ export async function runSubscriptionsTest() {
{ properties: ["stringProperty"] },
);

const interfaceSubscription = client(OsdkTestInterface).subscribe({
onChange(object) {
console.log(
"Interface with primaryKey ",
object.object.$primaryKey,
" changed objectDescription to ",
object.object.objectDescription,
);
},
async onSuccessfulSubscription() {
console.log("Successfully subscribed to OsdkTestInterface");
await client($Actions.createOsdkTestObject).applyAction({
description: "test",
osdk_object_name: "OsdkTestObject",
string_property: "test",
});
},
onError(err) {
console.error("Error in interface subscription: ", err);
},
});

const mtaBusSubscription = dsClient(
__EXPERIMENTAL__NOT_SUPPORTED_YET_subscribe,
).subscribe(
Expand Down

0 comments on commit 1c59d93

Please sign in to comment.