/
supabase.ts
138 lines (122 loc) · 3.77 KB
/
supabase.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import RESTSerializer from '@ember-data/serializer/rest';
import { underscore } from '@ember/string';
import { pluralize } from 'ember-inflector';
import type Store from '@ember-data/store';
import type Model from '@ember-data/model';
import type ModelRegistry from 'ember-data/types/registries/model';
type ModelClass = Model & {
modelName: keyof ModelRegistry;
};
type RelationshipValue = string | { id: string } | { id: string }[] | null;
export default class SupabaseSerializer extends RESTSerializer {
public keyForAttribute(key: string): string {
return underscore(key);
}
public extractRelationships(
modelClass: Model,
resourceHash: Record<string, unknown>
): Record<string, unknown> {
const links: Record<string, string> = {};
modelClass.eachRelationship((name, { kind, type }) => {
if (kind === 'belongsTo') {
const id = resourceHash[name];
if (id) {
links[name] = `${type}/${id}`;
}
} else if (kind === 'hasMany') {
links[name] = type;
}
});
resourceHash.links = links;
return super.extractRelationships(modelClass, resourceHash);
}
public normalizeResponse(
store: Store,
primaryModelClass: ModelClass,
payload: Record<string, unknown>,
id: string | number,
requestType: string
): Record<string, unknown> {
const type = pluralize(primaryModelClass.modelName);
const newPayload = {
[type]: payload,
};
return super.normalizeResponse(
store,
primaryModelClass,
newPayload,
id,
requestType
);
}
public normalizeSingleResponse(
store: Store,
primaryModelClass: ModelClass,
payload: Record<string, Record<string, unknown>>,
id: string,
requestType: string
): Record<string, unknown> {
const record = payload[pluralize(primaryModelClass.modelName)];
this.appendIncludedRecordsToPayload(primaryModelClass, payload, record);
return super.normalizeSingleResponse(
store,
primaryModelClass,
payload,
id,
requestType
);
}
public normalizeArrayResponse(
store: Store,
primaryModelClass: ModelClass,
payload: Record<string, []>,
id: string,
requestType: string
): Record<string, unknown> {
const records = payload[pluralize(primaryModelClass.modelName)];
records.forEach((record) => {
this.appendIncludedRecordsToPayload(primaryModelClass, payload, record);
});
return super.normalizeArrayResponse(
store,
primaryModelClass,
payload,
id,
requestType
);
}
/**
* Brings nested records up to top level for sideloading.
* @param primaryModelClass
* @param payload
* @param record
*/
private appendIncludedRecordsToPayload(
primaryModelClass: ModelClass,
payload: Record<string, Record<string, any> | Record<string, unknown>[]>,
record: Record<string, unknown>
): void {
primaryModelClass.eachRelationship((name, { kind, type }) => {
const value = record[this.keyForAttribute(name)] as RelationshipValue;
if (value && typeof value === 'object') {
const includedType = pluralize(type);
if (!Array.isArray(payload[includedType])) {
payload[includedType] = [];
}
if (kind === 'belongsTo' && !Array.isArray(value)) {
payload[includedType].push(value);
record[name] = value.id;
} else if (kind === 'hasMany' && Array.isArray(value)) {
payload[includedType].push(...value);
record[name] = value.map((record) => record.id);
}
}
});
}
}
// DO NOT DELETE: this is how TypeScript knows how to look up your serializers.
declare module 'ember-data/types/registries/serializer' {
export default interface SerializerRegistry {
supabase: SupabaseSerializer;
}
}