Skip to content

Commit

Permalink
stash schema record work
Browse files Browse the repository at this point in the history
  • Loading branch information
runspired committed Sep 28, 2023
1 parent 1485056 commit 3aa48e5
Show file tree
Hide file tree
Showing 11 changed files with 374 additions and 25 deletions.
1 change: 0 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,6 @@ module.exports = {
'ember-data-types/q/promise-proxies.ts',
'ember-data-types/q/minimum-serializer-interface.ts',
'ember-data-types/q/minimum-adapter-interface.ts',
'ember-data-types/q/identifier.ts',
'ember-data-types/q/fetch-manager.ts',
'ember-data-types/q/ember-data-json-api.ts',
'@types/@ember/polyfills/index.d.ts',
Expand Down
140 changes: 136 additions & 4 deletions packages/schema-record/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,138 @@
type Store = { peekRecord(identifier: StableRecordIdentifier): SchemaModel | unknown | null };
type StableRecordIdentifier = { lid: string };
// import type Store from '@ember-data/store';
type Store = { schema: SchemaService, cache: Cache };
import type { StableRecordIdentifier } from "@ember-data/types/q/identifier";
import type { Cache } from "@ember-data/types/cache/cache";

export default class SchemaModel {
constructor(store: Store, identifier: StableRecordIdentifier) {}
export const Destroy = Symbol('Destroy');
export const RecordStore = Symbol('Store');
export const Identifier = Symbol('Identifier');

export interface FieldSchema {
type: string;
name: string;
kind: 'attribute' | 'resource' | 'collection' | 'derived' | 'object' | 'array';
options?: Record<string, unknown>;
}

type FieldSpec = {
// legacy support
attributes: Record<string, FieldSchema>;
relationships: Record<string, FieldSchema>;
// new support
fields: Map<string, FieldSchema>;
}

export class SchemaService {
declare schemas: Map<string, FieldSpec>;

constructor() {
this.schemas = new Map();
}

defineSchema(name: string, fields: FieldSchema[]): void {
const fieldSpec: FieldSpec = {
attributes: {},
relationships: {},
fields: new Map(),
};

fields.forEach((field) => {
fieldSpec.fields.set(field.name, field);

if (field.kind === 'attribute') {
fieldSpec.attributes[field.name] = field;
} else if (field.kind === 'resource' || field.kind === 'collection') {
fieldSpec.relationships[field.name] = Object.assign({}, field, {
kind: field.kind === 'resource' ? 'belongsTo' : 'hasMany',
});
} else {
throw new Error(`Unknown field kind ${field.kind}`);
}
});

this.schemas.set(name, fieldSpec);
}

fields({ type }: { type: string }): FieldSpec['fields'] {
const schema = this.schemas.get(type);

if (!schema) {
throw new Error(`No schema defined for ${type}`);
}

return schema.fields;
}

attributesDefinitionFor({ type }: { type: string }): FieldSpec['attributes'] {
const schema = this.schemas.get(type);

if (!schema) {
throw new Error(`No schema defined for ${type}`);
}

return schema.attributes;
}

relationshipsDefinitionFor({ type }: { type: string }): FieldSpec['relationships'] {
const schema = this.schemas.get(type);

if (!schema) {
throw new Error(`No schema defined for ${type}`);
}

return schema.relationships;
}

doesTypeExist(type: string): boolean {
return this.schemas.has(type);
}
}

export default class SchemaRecord {
declare [RecordStore]: Store;
declare [Identifier]: StableRecordIdentifier;

constructor(store: Store, identifier: StableRecordIdentifier) {
this[RecordStore] = store;
this[Identifier] = identifier;

const schema = store.schema;
const cache = store.cache;
const fields = schema.fields(identifier);

return new Proxy(this, {
get(target, prop) {
if (prop === Destroy) {
return target[Destroy];
}

if (prop === 'id') {
return identifier.id;
}
if (prop === '$type') {
return identifier.type;
}
const field = fields.get(prop as string);
if (!field) {
throw new Error(`No field named ${String(prop)} on ${identifier.type}`);
}

if (field.kind === 'attribute') {
return cache.getAttr(identifier, prop as string);
}

throw new Error(`Unknown field kind ${field.kind}`);
},
});
}

[Destroy](): void {}
}

export function instantiateRecord(store: Store, identifier: StableRecordIdentifier): SchemaRecord {
return new SchemaRecord(store, identifier);
}

export function teardownRecord(record: SchemaRecord): void {
record[Destroy]();
}
3 changes: 3 additions & 0 deletions packages/schema-record/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@

"paths": {
"@ember-data/env": ["../../private-build-infra/virtual-packages/env.d.ts"],
"@ember-data/store": ["../../store/src"],
"@ember-data/types": ["../../../ember-data-types"],
"@ember-data/types/*": ["../../../ember-data-types/*"],
}
}
}
156 changes: 156 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 0 additions & 5 deletions tests/schema-record/app/models/user-setting.ts

This file was deleted.

Loading

0 comments on commit 3aa48e5

Please sign in to comment.