/
factory.ts
135 lines (115 loc) · 3.41 KB
/
factory.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
import {
FactoryAPI,
Database,
ModelAPI,
ModelDeclaration,
EntityInstance,
ModelDictionary,
} from './glossary'
import { first } from './utils/first'
import { executeQuery } from './query/executeQuery'
import { parseModelDeclaration } from './model/parseModelDeclaration'
import { createModel } from './model/createModel'
import { invariant } from './utils/invariant'
import { updateEntity } from './model/updateEntity'
/**
* Create a database with the given models.
*/
export function factory<Dictionary extends ModelDictionary>(
dict: Dictionary,
): FactoryAPI<Dictionary> {
const db: Database = Object.keys(dict).reduce((acc, modelName) => {
acc[modelName] = new Map<string, EntityInstance<Dictionary, string>>()
return acc
}, {})
return Object.entries(dict).reduce<any>((acc, [modelName, props]) => {
acc[modelName] = createModelApi<Dictionary, typeof modelName>(
modelName,
props,
db,
)
return acc
}, {})
}
function createModelApi<
Dictionary extends ModelDictionary,
ModelName extends string
>(modelName: ModelName, declaration: ModelDeclaration, db: Database) {
const api: ModelAPI<Dictionary, ModelName> = {
create(initialValues = {}) {
const { primaryKey, properties, relations } = parseModelDeclaration<
Dictionary,
ModelName
>(modelName, declaration, initialValues)
const model = createModel<Dictionary, ModelName>(
modelName,
primaryKey,
properties,
relations,
db,
)
const modelPrimaryKey = model[model.__primaryKey]
// Prevent creation of multiple entities with the same primary key value.
invariant(
db[modelName].has(modelPrimaryKey as string),
`Failed to create "${modelName}": entity with the primary key "${modelPrimaryKey}" ("${model.__primaryKey}") already exists.`,
)
db[modelName].set(modelPrimaryKey as string, model)
return model
},
count() {
return db[modelName].size
},
findFirst(query) {
const results = executeQuery(modelName, 'PRIMARY_KEY', query, db)
return first(results)
},
findMany(query) {
return executeQuery(modelName, 'PRIMARY_KEY', query, db)
},
getAll() {
return Array.from(db[modelName].values())
},
update(query) {
const record = api.findFirst(query)
if (!record) {
return null
}
const nextRecord = updateEntity(record, query.data)
db[modelName].set(record[record.__primaryKey] as string, nextRecord)
return nextRecord
},
updateMany(query) {
const records = api.findMany(query)
const updatedRecords = []
if (!records) {
return null
}
records.forEach((record) => {
const nextRecord = updateEntity(record, query.data)
db[modelName].set(record[record.__primaryKey] as string, nextRecord)
updatedRecords.push(nextRecord)
})
return updatedRecords
},
delete(query) {
const record = api.findFirst(query)
if (!record) {
return null
}
db[modelName].delete(record[record.__primaryKey] as string)
return record
},
deleteMany(query) {
const records = api.findMany(query)
if (!records) {
return null
}
records.forEach((record) => {
db[modelName].delete(record[record.__primaryKey] as string)
})
return records
},
}
return api
}