Skip to content
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

feat: update SchemaService to reflect RFC updates #9453

Merged
merged 5 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/json-api/src/-private/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1506,7 +1506,7 @@ function getDefaultValue(

// new style transforms
} else if (schema.kind !== 'attribute' && schema.type) {
const transform = store.schema.transformation(schema.type);
const transform = store.schema.transformation(schema);

if (transform?.defaultValue) {
return transform.defaultValue(options || null, identifier);
Expand Down
15 changes: 10 additions & 5 deletions packages/model/src/-private/schema-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,14 @@ import type { RecordIdentifier, StableRecordIdentifier } from '@warp-drive/core-
import type { ObjectValue } from '@warp-drive/core-types/json/raw';
import type { Derivation, HashFn, Transformation } from '@warp-drive/core-types/schema/concepts';
import type {
ArrayField,
DerivedField,
GenericField,
HashField,
LegacyAttributeField,
LegacyFieldSchema,
LegacyRelationshipSchema,
ObjectField,
ResourceSchema,
} from '@warp-drive/core-types/schema/fields';

Expand Down Expand Up @@ -55,15 +60,15 @@ export class ModelSchemaProvider implements SchemaService {
assert(`resourceHasTrait is not available with @ember-data/model's SchemaService`);
return false;
}
transformation(name: string): Transformation {
transformation(field: GenericField | ObjectField | ArrayField | { type: string }): Transformation {
assert(`transformation is not available with @ember-data/model's SchemaService`);
}
hashFn(name: string): HashFn {
assert(`hashFn is not available with @ember-data/model's SchemaService`);
}
derivation(name: string): Derivation {
derivation(field: DerivedField | { type: string }): Derivation {
assert(`derivation is not available with @ember-data/model's SchemaService`);
}
hashFn(field: HashField | { type: string }): HashFn {
assert(`hashFn is not available with @ember-data/model's SchemaService`);
}
resource(resource: StableRecordIdentifier | { type: string }): ResourceSchema {
const type = normalizeModelName(resource.type);

Expand Down
22 changes: 15 additions & 7 deletions packages/model/src/migration-support.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,15 @@ import type { StableRecordIdentifier } from '@warp-drive/core-types';
import { getOrSetGlobal } from '@warp-drive/core-types/-private';
import type { ObjectValue } from '@warp-drive/core-types/json/raw';
import type { Derivation, HashFn, Transformation } from '@warp-drive/core-types/schema/concepts';
import type { FieldSchema, ResourceSchema } from '@warp-drive/core-types/schema/fields';
import type {
ArrayField,
DerivedField,
FieldSchema,
GenericField,
HashField,
ObjectField,
ResourceSchema,
} from '@warp-drive/core-types/schema/fields';
import { Type } from '@warp-drive/core-types/symbols';
import type { WithPartial } from '@warp-drive/core-types/utils';

Expand Down Expand Up @@ -203,14 +211,14 @@ export class DelegatingSchemaService implements SchemaService {
}
return this._secondary.fields(resource);
}
transformation(name: string): Transformation {
return this._preferred.transformation(name);
transformation(field: GenericField | ObjectField | ArrayField | { type: string }): Transformation {
return this._preferred.transformation(field);
}
hashFn(name: string): HashFn {
return this._preferred.hashFn(name);
hashFn(field: HashField | { type: string }): HashFn {
return this._preferred.hashFn(field);
}
derivation(name: string): Derivation {
return this._preferred.derivation(name);
derivation(field: DerivedField | { type: string }): Derivation {
return this._preferred.derivation(field);
}
resource(resource: StableRecordIdentifier | { type: string }): ResourceSchema {
if (this._preferred.hasResource(resource)) {
Expand Down
6 changes: 2 additions & 4 deletions packages/schema-record/src/managed-array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,7 @@ export class ManagedArray {
subscribe(_SIGNAL);
}
if (field.type) {
const transform = schema.transformation(field.type);
assert(`No '${field.type}' transform defined for use by ${address.type}.${String(prop)}`, transform);
const transform = schema.transformation(field);
return transform.hydrate(val as Value, field.options ?? null, self.owner);
}
return val;
Expand Down Expand Up @@ -225,8 +224,7 @@ export class ManagedArray {
return true;
}

const transform = schema.transformation(field.type);
assert(`No '${field.type}' transform defined for use by ${address.type}.${String(prop)}`, transform);
const transform = schema.transformation(field);
const rawValue = (self[SOURCE] as ArrayValue).map((item) =>
transform.serialize(item, field.options ?? null, self.owner)
);
Expand Down
7 changes: 2 additions & 5 deletions packages/schema-record/src/managed-object.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type Store from '@ember-data/store';
import type { Signal } from '@ember-data/tracking/-private';
import { addToTransaction, createSignal, subscribe } from '@ember-data/tracking/-private';
import { assert } from '@warp-drive/build-config/macros';
import type { StableRecordIdentifier } from '@warp-drive/core-types';
import type { Cache } from '@warp-drive/core-types/cache';
import type { ObjectValue, Value } from '@warp-drive/core-types/json/raw';
Expand Down Expand Up @@ -76,8 +75,7 @@ export class ManagedObject {
let newData = cache.getAttr(self.address, self.key);
if (newData && newData !== self[SOURCE]) {
if (field.type) {
const transform = schema.transformation(field.type);
assert(`No '${field.type}' transform defined for use by ${address.type}.${String(prop)}`, transform);
const transform = schema.transformation(field);
newData = transform.hydrate(newData as ObjectValue, field.options ?? null, self.owner) as ObjectValue;
}
self[SOURCE] = { ...(newData as ObjectValue) }; // Add type assertion for newData
Expand Down Expand Up @@ -119,8 +117,7 @@ export class ManagedObject {
return true;
}

const transform = schema.transformation(field.type);
assert(`No '${field.type}' transform defined for use by ${address.type}.${String(prop)}`, transform);
const transform = schema.transformation(field);
const val = transform.serialize(self[SOURCE], field.options ?? null, self.owner);
cache.setAttr(self.address, self.key, val);
_SIGNAL.shouldReset = true;
Expand Down
27 changes: 7 additions & 20 deletions packages/schema-record/src/record.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@ function computeField(
if (!field.type) {
return rawValue;
}
const transform = schema.transformation(field.type);
assert(`No '${field.type}' transform defined for use by ${identifier.type}.${String(prop)}`, transform);
const transform = schema.transformation(field);
return transform.hydrate(rawValue, field.options ?? null, record);
}

Expand Down Expand Up @@ -146,8 +145,7 @@ function computeObject(
}
if (field.kind === 'object') {
if (field.type) {
const transform = schema.transformation(field.type);
assert(`No '${field.type}' transform defined for use by ${identifier.type}.${String(prop)}`, transform);
const transform = schema.transformation(field);
rawValue = transform.hydrate(rawValue as ObjectValue, field.options ?? null, record) as object;
}
}
Expand All @@ -172,13 +170,7 @@ function computeDerivation(
field: DerivedField,
prop: string
): unknown {
if (!field.type) {
throw new Error(`The schema for ${identifier.type}.${String(prop)} is missing the type of the derivation`);
}

const derivation = schema.derivation(field.type);
assert(`No '${field.type}' derivation defined for use by ${identifier.type}.${String(prop)}`, derivation);
return derivation(record, field.options ?? null, prop);
return schema.derivation(field)(record, field.options ?? null, prop);
}

// TODO probably this should just be a Document
Expand Down Expand Up @@ -349,7 +341,7 @@ export class SchemaRecord {
return identifier.id;
case '@hash':
// TODO pass actual cache value not {}
return schema.hashFn(field.type)({}, field.options ?? null, field.name ?? null);
return schema.hashFn(field)({}, field.options ?? null, field.name ?? null);
case '@local': {
const lastValue = computeLocal(receiver, field, prop as string);
entangleSignal(signals, receiver, prop as string);
Expand Down Expand Up @@ -423,9 +415,7 @@ export class SchemaRecord {
cache.setAttr(identifier, prop as string, value as Value);
return true;
}
const transform = schema.transformation(field.type);
assert(`No '${field.type}' transform defined for use by ${identifier.type}.${String(prop)}`, transform);

const transform = schema.transformation(field);
const rawValue = transform.serialize(value, field.options ?? null, target);
cache.setAttr(identifier, prop as string, rawValue);
return true;
Expand All @@ -448,9 +438,7 @@ export class SchemaRecord {
return true;
}

const transform = schema.transformation(field.type);
assert(`No '${field.type}' transform defined for use by ${identifier.type}.${String(prop)}`, transform);

const transform = schema.transformation(field);
const rawValue = (value as ArrayValue).map((item) =>
transform.serialize(item, field.options ?? null, target)
);
Expand Down Expand Up @@ -480,8 +468,7 @@ export class SchemaRecord {
}
return true;
}
const transform = schema.transformation(field.type);
assert(`No '${field.type}' transform defined for use by ${identifier.type}.${String(prop)}`, transform);
const transform = schema.transformation(field);
const rawValue = transform.serialize({ ...(value as ObjectValue) }, field.options ?? null, target);

cache.setAttr(identifier, prop as string, rawValue);
Expand Down
64 changes: 54 additions & 10 deletions packages/schema-record/src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@ import { getOrSetGlobal } from '@warp-drive/core-types/-private';
import type { ObjectValue, Value } from '@warp-drive/core-types/json/raw';
import type { Derivation, HashFn } from '@warp-drive/core-types/schema/concepts';
import type {
ArrayField,
DerivedField,
FieldSchema,
GenericField,
HashField,
LegacyAttributeField,
LegacyRelationshipSchema,
ObjectField,
ResourceSchema,
} from '@warp-drive/core-types/schema/fields';
import { Type } from '@warp-drive/core-types/symbols';
Expand Down Expand Up @@ -153,22 +158,61 @@ export class SchemaService implements SchemaServiceInterface {
resourceHasTrait(resource: StableRecordIdentifier | { type: string }, trait: string): boolean {
return this._schemas.get(resource.type)!.traits.has(trait);
}
transformation(name: string): Transformation {
assert(`No transformation registered with name '${name}'`, this._transforms.has(name));
return this._transforms.get(name)!;
transformation(field: GenericField | ObjectField | ArrayField | { type: string }): Transformation {
const kind = 'kind' in field ? field.kind : '<unknown kind>';
const name = 'name' in field ? field.name : '<unknown name>';
assert(
`'${kind}' fields cannot be transformed. Only fields of kind 'field' 'object' or 'array' can specify a transformation. Attempted to find '${field.type ?? '<unknown type>'}' on field '${name}'.`,
!('kind' in field) || ['field', 'object', 'array'].includes(kind)
);
assert(
`Expected the '${kind}' field '${name}' to specify a transformation via 'field.type', but none was present`,
field.type
);
assert(
`No transformation registered with name '${field.type}' for '${kind}' field '${name}'`,
this._transforms.has(field.type)
);
return this._transforms.get(field.type)!;
}
derivation(name: string): Derivation {
assert(`No derivation registered with name '${name}'`, this._derivations.has(name));
return this._derivations.get(name)!;
derivation(field: DerivedField | { type: string }): Derivation {
const kind = 'kind' in field ? field.kind : '<unknown kind>';
const name = 'name' in field ? field.name : '<unknown name>';
assert(
`The '${kind}' field '${name}' is not derived and so cannot be used to lookup a derivation`,
!('kind' in field) || kind === 'derived'
);
assert(
`Expected the '${kind}' field '${name}' to specify a derivation via 'field.type', but no value was present`,
field.type
);
assert(
`No '${field.type}' derivation registered for use by the '${kind}' field '${name}'`,
this._derivations.has(field.type)
);
return this._derivations.get(field.type)!;
}
hashFn(field: HashField | { type: string }): HashFn {
const kind = 'kind' in field ? field.kind : '<unknown kind>';
const name = 'name' in field ? field.name : '<unknown name>';
assert(
`The '${kind}' field '${name}' is not a HashField and so cannot be used to lookup a hash function`,
!('kind' in field) || kind === '@hash'
);
assert(
`Expected the '${kind}' field '${name}' to specify a hash function via 'field.type', but no value was present`,
field.type
);
assert(
`No '${field.type}' hash function is registered for use by the '${kind}' field '${name}'`,
this._hashFns.has(field.type)
);
return this._hashFns.get(field.type)!;
}
resource(resource: StableRecordIdentifier | { type: string }): ResourceSchema {
assert(`No resource registered with name '${resource.type}'`, this._schemas.has(resource.type));
return this._schemas.get(resource.type)!.original;
}
hashFn(name: string): HashFn {
assert(`No hash function registered with name '${name}'`, this._hashFns.has(name));
return this._hashFns.get(name)!;
}
registerResources(schemas: ResourceSchema[]): void {
schemas.forEach((schema) => {
this.registerResource(schema);
Expand Down
26 changes: 17 additions & 9 deletions packages/store/src/-types/q/schema-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@ import type { RecordIdentifier } from '@warp-drive/core-types/identifier';
import type { ObjectValue } from '@warp-drive/core-types/json/raw';
import type { Derivation, HashFn, Transformation } from '@warp-drive/core-types/schema/concepts';
import type {
ArrayField,
DerivedField,
FieldSchema,
GenericField,
HashField,
LegacyAttributeField,
LegacyBelongsToField,
LegacyHasManyField,
ObjectField,
ResourceSchema,
} from '@warp-drive/core-types/schema/fields';

Expand Down Expand Up @@ -126,34 +131,37 @@ export interface SchemaService {
fields(resource: { type: string } | StableRecordIdentifier): Map<string, FieldSchema>;

/**
* Returns the transformation registered with the provided name.
* Returns the transformation registered with the name provided
* by `field.type`. Validates that the field is a valid transformable.
*
* @method transformation
* @public
* @param name
* @param {TransformableField|{ type: string }} field
* @returns {Transformation}
*/
transformation(name: string): Transformation;
transformation(field: GenericField | ObjectField | ArrayField | { type: string }): Transformation;

/**
* Returns the hash function registered with the provided name.
* Returns the hash function registered with the name provided
* by `field.type`. Validates that the field is a valid HashField.
*
* @method hashFn
* @public
* @param name
* @param {HashField|{ type: string }} field
* @returns {HashFn}
*/
hashFn(name: string): HashFn;
hashFn(field: HashField | { type: string }): HashFn;

/**
* Returns the derivation registered with the provided name.
* Returns the derivation registered with the name provided
* by `field.type`. Validates that the field is a valid DerivedField.
*
* @method derivation
* @public
* @param name
* @param {DerivedField|{ type: string }} field
* @returns {Derivation}
*/
derivation(name: string): Derivation;
derivation(field: DerivedField | { type: string }): Derivation;

/**
* Returns the schema for the provided resource type.
Expand Down
Loading
Loading