diff --git a/packages/graph/src/-private/-edge-definition.ts b/packages/graph/src/-private/-edge-definition.ts index ca413348f8d..ca3928cdaa5 100644 --- a/packages/graph/src/-private/-edge-definition.ts +++ b/packages/graph/src/-private/-edge-definition.ts @@ -445,6 +445,8 @@ export function upgradeDefinition( // TODO probably dont need this assertion if polymorphic assert(`Expected the inverse model to exist`, getStore(storeWrapper).modelFor(inverseType)); inverseDefinition = null; + } else if (definition.isCollection && !definition.inverseKey) { + inverseDefinition = null; } else { inverseKey = /*#__NOINLINE__*/ inverseForRelationship(getStore(storeWrapper), identifier, propertyName); diff --git a/packages/graph/src/-private/debug/assert-polymorphic-type.ts b/packages/graph/src/-private/debug/assert-polymorphic-type.ts index 1855d91ea8f..df3d30e862b 100644 --- a/packages/graph/src/-private/debug/assert-polymorphic-type.ts +++ b/packages/graph/src/-private/debug/assert-polymorphic-type.ts @@ -39,16 +39,18 @@ if (DEBUG) { if (definition.inverseKind !== meta.kind) { errors.set('type', ` <---- should be '${definition.inverseKind}'`); } - if (definition.inverseIsAsync !== meta.options.async) { - errors.set('async', ` <---- should be ${definition.inverseIsAsync}`); + if (definition.kind !== 'collection') { + if (definition.inverseIsAsync !== meta.options?.async) { + errors.set('async', ` <---- should be ${definition.inverseIsAsync}`); + } } - if (definition.inverseIsPolymorphic && definition.inverseIsPolymorphic !== meta.options.polymorphic) { + if (definition.inverseIsPolymorphic && definition.inverseIsPolymorphic !== meta.options?.polymorphic) { errors.set('polymorphic', ` <---- should be ${definition.inverseIsPolymorphic}`); } - if (definition.key !== meta.options.inverse) { + if (definition.key !== meta.options?.inverse) { errors.set('inverse', ` <---- should be '${definition.key}'`); } - if (definition.type !== meta.options.as) { + if (definition.type !== meta.options?.as) { errors.set('as', ` <---- should be '${definition.type}'`); } @@ -59,11 +61,11 @@ if (DEBUG) { name: string; type: string; kind: string; - options: { + options?: { as?: string; - async: boolean; + async?: boolean; polymorphic?: boolean; - inverse: string | null; + inverse?: string | null; }; }; type RelationshipSchemaError = 'name' | 'type' | 'kind' | 'as' | 'async' | 'polymorphic' | 'inverse'; @@ -83,6 +85,19 @@ if (DEBUG) { } function printSchema(config: PrintConfig, errors?: Map) { + const optionLines = [ + config.options?.as ? ` as: '${config.options.as}',${errors?.get('as') || ''}` : '', + config.kind !== 'collection' ? ` async: ${config.options?.async},${errors?.get('async') || ''}` : '', + config.options?.polymorphic || errors?.get('polymorphic') + ? ` polymorphic: ${config.options?.polymorphic},${errors?.get('polymorphic') || ''}` + : '', + config.kind !== 'collection' || errors?.get('inverse') + ? ` inverse: '${config.options?.inverse}'${errors?.get('inverse') || ''}` + : '', + ] + .filter(Boolean) + .join('\n'); + return ` \`\`\` @@ -92,10 +107,7 @@ if (DEBUG) { type: '${config.type}',${errors?.get('type') || ''} kind: '${config.kind}',${errors?.get('kind') || ''} options: { - as: '${config.options.as}',${errors?.get('as') || ''} - async: ${config.options.async},${errors?.get('async') || ''} - polymorphic: ${config.options.polymorphic},${errors?.get('polymorphic') || ''} - inverse: '${config.options.inverse}'${errors?.get('inverse') || ''} +${optionLines} } } } @@ -137,6 +149,7 @@ if (DEBUG) { isAsync: definition.inverseIsAsync, isPolymorphic: true, isCollection: definition.inverseIsCollection, + isPaginated: definition.inverseIsPaginated, isImplicit: definition.inverseIsImplicit, inverseKey: definition.key, inverseType: definition.type, @@ -145,6 +158,7 @@ if (DEBUG) { inverseIsPolymorphic: definition.isPolymorphic, inverseIsImplicit: definition.isImplicit, inverseIsCollection: definition.isCollection, + inverseIsPaginated: definition.isPaginated, resetOnRemoteUpdate: definition.resetOnRemoteUpdate, }; } @@ -230,7 +244,7 @@ if (DEBUG) { meta = isLegacyField(meta) ? meta : temporaryConvertToLegacy(meta); assert( `You should not specify both options.as and options.inverse as null on ${addedIdentifier.type}.${parentDefinition.inverseKey}, as if there is no inverse field there is no abstract type to conform to. You may have intended for this relationship to be polymorphic, or you may have mistakenly set inverse to null.`, - !(meta.options.inverse === null && meta?.options.as?.length) + !(meta.options?.inverse === null && meta.options.as?.length) ); const errors = validateSchema(parentDefinition, meta); assert( diff --git a/packages/legacy-compat/src/legacy-network-handler/legacy-data-fetch.ts b/packages/legacy-compat/src/legacy-network-handler/legacy-data-fetch.ts index d1618279415..ac290ae8cec 100644 --- a/packages/legacy-compat/src/legacy-network-handler/legacy-data-fetch.ts +++ b/packages/legacy-compat/src/legacy-network-handler/legacy-data-fetch.ts @@ -183,6 +183,10 @@ function ensureRelationshipIsSetToParent( if (inverse) { const { inverseKey, kind } = inverse; + if (kind === 'collection') { + return; + } + const relationshipData = relationships[inverseKey]?.data as RelationshipData | undefined; if (DEBUG) { diff --git a/packages/model/src/-private/debug/assert-polymorphic-type.ts b/packages/model/src/-private/debug/assert-polymorphic-type.ts index 49c451e0f99..0426dde5b3b 100644 --- a/packages/model/src/-private/debug/assert-polymorphic-type.ts +++ b/packages/model/src/-private/debug/assert-polymorphic-type.ts @@ -42,7 +42,7 @@ if (DEBUG) { ); assert( `The schema for the relationship '${parentDefinition.inverseKey}' on '${addedIdentifier.type}' type does not implement '${parentDefinition.type}' and thus cannot be assigned to the '${parentDefinition.key}' relationship in '${parentIdentifier.type}'. The definition should specify 'as: "${parentDefinition.type}"' in options.`, - meta?.options.as === parentDefinition.type + meta?.options?.as === parentDefinition.type ); } }; diff --git a/packages/store/src/-types/q/ds-model.ts b/packages/store/src/-types/q/ds-model.ts index 28df41767c6..6aaf89b7df1 100644 --- a/packages/store/src/-types/q/ds-model.ts +++ b/packages/store/src/-types/q/ds-model.ts @@ -2,6 +2,7 @@ import type { TypedRecordInstance, TypeFromInstance } from '@warp-drive/core-typ import type { LegacyAttributeField, LegacyRelationshipSchema } from '@warp-drive/core-types/schema/fields'; export type KeyOrString = keyof T & string extends never ? string : keyof T & string; +export type FieldKind = 'attribute' | 'belongsTo' | 'hasMany' | 'collection'; /** * Minimum subset of static schema methods and properties on the