Skip to content

Commit 07c9915

Browse files
committed
feat: add automatic database registration support
1 parent 4587db7 commit 07c9915

30 files changed

+171
-242
lines changed

src/database/Database.ts

Lines changed: 47 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
import { Store, Module as VuexModule } from 'vuex'
1+
import { Store } from 'vuex'
22
import { schema as Normalizr } from 'normalizr'
3-
import { Constructor } from '../types'
43
import { Schema } from '../schema/Schema'
54
import { Model } from '../model/Model'
6-
import { RootModule } from '../modules/RootModule'
7-
import { Module } from '../modules/Module'
5+
import { Relation } from '../model/attributes/relations/Relation'
86
import { State } from '../modules/State'
97
import { mutations, Mutations } from '../modules/Mutations'
108

@@ -36,15 +34,6 @@ export class Database {
3634
*/
3735
started: boolean = false
3836

39-
/**
40-
* Register the given model.
41-
*/
42-
register(model: Constructor<Model>): void {
43-
const instance = new model()
44-
45-
this.models[instance.$entity] = instance
46-
}
47-
4837
/**
4938
* Set the store.
5039
*/
@@ -67,101 +56,81 @@ export class Database {
6756
* Initialize the database before a user can start using it.
6857
*/
6958
start(): void {
70-
this.injectStoreToModels()
71-
72-
this.createSchemas()
73-
74-
this.registerModules()
59+
this.createRootModule()
7560

7661
this.started = true
7762
}
7863

7964
/**
80-
* Get a model by the specified entity name.
65+
* Register the given model.
8166
*/
82-
getModel<M extends Model>(name: string): M {
83-
return this.models[name] as M
84-
}
67+
register<M extends Model>(model: M): void {
68+
if (!this.models[model.$entity]) {
69+
this.models[model.$entity] = model
8570

86-
/**
87-
* Get schema by the specified entity name.
88-
*/
89-
getSchema(name: string): Normalizr.Entity {
90-
return this.schemas[name]
91-
}
71+
this.createModule(model)
9272

93-
/**
94-
* Inject the store instance to all registered models.
95-
*/
96-
private injectStoreToModels(): void {
97-
for (const name in this.models) {
98-
this.models[name].$setStore(this.store)
99-
}
100-
}
73+
this.createSchema(model)
10174

102-
/**
103-
* Create the schema definition from registered models and set it to the
104-
* `schema` property. This schema will be used by the Interpreter to interpret
105-
* the data before persisting them to the store.
106-
*/
107-
private createSchemas(): void {
108-
for (const name in this.models) {
109-
this.schemas[name] = this.createSchema(this.models[name])
75+
this.registerRelatedModels(model)
11076
}
11177
}
11278

11379
/**
114-
* Create schema from the given model.
80+
* Register all related models.
11581
*/
116-
private createSchema<M extends Model>(model: M): Normalizr.Entity {
117-
return new Schema(model).one()
82+
private registerRelatedModels<M extends Model>(model: M): void {
83+
for (const name in model.$fields) {
84+
const attr = model.$fields[name]
85+
86+
if (attr instanceof Relation) {
87+
attr.getRelateds().forEach((m) => {
88+
this.register(m.$setStore(this.store))
89+
})
90+
}
91+
}
11892
}
11993

12094
/**
121-
* Generate modules and register them to the store.
95+
* Get a model by the specified entity name.
12296
*/
123-
private registerModules(): void {
124-
this.store.registerModule(this.connection, this.createModule())
97+
getModel<M extends Model>(name: string): M {
98+
return this.models[name] as M
12599
}
126100

127101
/**
128-
* Create modules from the registered models and modules.
102+
* Get schema by the specified entity name.
129103
*/
130-
private createModule(): VuexModule<any, any> {
131-
const module = this.createRootModule()
132-
133-
for (const name in this.models) {
134-
module.modules[name] = this.createSubModule()
135-
}
136-
137-
return module
104+
getSchema(name: string): Normalizr.Entity {
105+
return this.schemas[name]
138106
}
139107

140108
/**
141109
* Create root module.
142110
*/
143-
private createRootModule(): RootModule {
144-
return {
145-
namespaced: true,
146-
modules: {}
147-
}
111+
private createRootModule(): void {
112+
this.store.registerModule(this.connection, {
113+
namespaced: true
114+
})
148115
}
149116

150117
/**
151118
* Create sub module.
152119
*/
153-
private createSubModule(): Module<State, any> {
154-
return {
120+
private createModule<M extends Model>(model: M): void {
121+
const preserveState = !!this.store.state[this.connection][model.$entity]
122+
123+
this.store.registerModule([this.connection, model.$entity], {
155124
namespaced: true,
156-
state: this.createSubState(),
157-
mutations: this.createSubMutations()
158-
}
125+
state: this.createState(),
126+
mutations: this.createMutations()
127+
}, { preserveState })
159128
}
160129

161130
/**
162131
* Create sub state.
163132
*/
164-
private createSubState(): State {
133+
private createState(): State {
165134
return {
166135
data: {}
167136
}
@@ -170,7 +139,14 @@ export class Database {
170139
/**
171140
* Create sub mutations.
172141
*/
173-
private createSubMutations(): Mutations<State> {
142+
private createMutations(): Mutations<State> {
174143
return mutations
175144
}
145+
146+
/**
147+
* Create schema from the given model.
148+
*/
149+
private createSchema<M extends Model>(model: M): Normalizr.Entity {
150+
return this.schemas[model.$entity] = new Schema(model).one()
151+
}
176152
}

src/model/attributes/relations/BelongsTo.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ export class BelongsTo extends Relation {
4040
this.child = child
4141
}
4242

43+
/**
44+
* Get all related models for the relationship.
45+
*/
46+
getRelateds(): Model[] {
47+
return [this.child]
48+
}
49+
4350
/**
4451
* Define the normalizr schema for the relation.
4552
*/

src/model/attributes/relations/HasMany.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ export class HasMany extends Relation {
3030
this.localKey = localKey
3131
}
3232

33+
/**
34+
* Get all related models for the relationship.
35+
*/
36+
getRelateds(): Model[] {
37+
return [this.related]
38+
}
39+
3340
/**
3441
* Define the normalizr schema for the relation.
3542
*/

src/model/attributes/relations/HasOne.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ export class HasOne extends Relation {
3030
this.localKey = localKey
3131
}
3232

33+
/**
34+
* Get all related models for the relationship.
35+
*/
36+
getRelateds(): Model[] {
37+
return [this.related]
38+
}
39+
3340
/**
3441
* Define the normalizr schema for the relation.
3542
*/

src/model/attributes/relations/Relation.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,15 @@ export abstract class Relation extends Attribute {
2929
this.related = related
3030
}
3131

32+
/**
33+
* Get all related models for the relationship.
34+
*/
35+
abstract getRelateds(): Model[]
36+
3237
/**
3338
* Get the related model of the relation.
3439
*/
35-
public getRelated(): Model {
40+
getRelated(): Model {
3641
return this.related
3742
}
3843

src/modules/Mutations.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,12 @@ import { Elements } from '../data/Data'
33
import { State } from './State'
44

55
export interface Mutations<S extends State> extends MutationTree<S> {
6-
mutate(state: S, callback: (state: S) => void): void
76
insert(state: S, records: Elements): void
87
update(state: S, records: Elements): void
98
delete(state: S, ids: string[]): void
109
flush(state: S): void
1110
}
1211

13-
/**
14-
* Execute a generic mutation.
15-
*/
16-
function mutate(state: State, callback: (state: State) => void): void {
17-
callback(state)
18-
}
19-
2012
/**
2113
* Commit `insert` change to the store.
2214
*/
@@ -54,7 +46,6 @@ function flush(state: State): void {
5446
}
5547

5648
export const mutations = {
57-
mutate,
5849
insert,
5950
update,
6051
delete: destroy,

src/plugin/Plugin.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import { mutations, Mutations } from '../modules/Mutations'
1919
export interface VuexORMPlugin {
2020
install(
2121
store: Store<any>,
22-
database: Database,
2322
components: VuexORMPluginComponents,
2423
options: any
2524
): void

src/store/Store.ts

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,9 @@ type FilledInstallOptions = Required<InstallOptions>
1212
/**
1313
* Install Vuex ORM to the store.
1414
*/
15-
export function install(
16-
database: Database,
17-
options?: InstallOptions
18-
): Plugin<any> {
15+
export function install(options?: InstallOptions): Plugin<any> {
1916
return (store) => {
20-
mixin(store, database, createOptions(options))
17+
mixin(store, createOptions(options))
2118
}
2219
}
2320

@@ -33,42 +30,39 @@ function createOptions(options: InstallOptions = {}): FilledInstallOptions {
3330
/**
3431
* Mixin Vuex ORM feature to the store.
3532
*/
36-
function mixin(
37-
store: Store<any>,
38-
database: Database,
39-
options: FilledInstallOptions
40-
): void {
41-
installPlugins(store, database)
33+
function mixin(store: Store<any>, options: FilledInstallOptions ): void {
34+
createDatabase(store, options)
4235

43-
connectDatabase(store, database, options)
36+
installPlugins(store)
4437

4538
mixinRepoFunction(store)
4639

4740
startDatabase(store)
4841
}
4942

5043
/**
51-
* Execute registered plugins.
44+
* Create a new database and connect to the store.
5245
*/
53-
function installPlugins(store: Store<any>, database: Database): void {
54-
plugins.forEach((plugin) => {
55-
const { func, options } = plugin
46+
function createDatabase(
47+
store: Store<any>,
48+
options: FilledInstallOptions
49+
): void {
50+
const database = new Database()
51+
.setStore(store)
52+
.setConnection(options.namespace)
5653

57-
func.install(store, database, components, options)
58-
})
54+
store.$database = database
5955
}
6056

6157
/**
62-
* Connect the database to the store.
58+
* Execute registered plugins.
6359
*/
64-
function connectDatabase(
65-
store: Store<any>,
66-
database: Database,
67-
options: FilledInstallOptions
68-
): void {
69-
database.setStore(store).setConnection(options.namespace)
60+
function installPlugins(store: Store<any>): void {
61+
plugins.forEach((plugin) => {
62+
const { func, options } = plugin
7063

71-
store.$database = database
64+
func.install(store, components, options)
65+
})
7266
}
7367

7468
/**
@@ -83,8 +77,15 @@ function startDatabase(store: Store<any>): void {
8377
*/
8478
function mixinRepoFunction(store: Store<any>): void {
8579
store.$repo = function (modelOrRepository: any): any {
86-
return modelOrRepository._isRepository
80+
const repository = modelOrRepository._isRepository
8781
? new modelOrRepository(this).initialize()
8882
: new Repository(this).initialize(modelOrRepository)
83+
84+
try {
85+
store.$database.register(repository.getModel())
86+
} catch (e) {
87+
} finally {
88+
return repository
89+
}
8990
}
9091
}

0 commit comments

Comments
 (0)