Skip to content

Commit

Permalink
Merge pull request #140 from godness84/feature/fixCircularRefs-withTy…
Browse files Browse the repository at this point in the history
…pedRefs

Feature/fix circular refs with typed refs
  • Loading branch information
chrisdrackett authored Nov 20, 2019
2 parents 0315a34 + 43c643e commit 809aeaa
Show file tree
Hide file tree
Showing 16 changed files with 239 additions and 89 deletions.
14 changes: 10 additions & 4 deletions examples/1-getting-started/src/app/models/RootStore.base.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/* This is a mst-gql generated file, don't modify it manually */
/* eslint-disable */
/* tslint:disable */
import { ObservableMap } from "mobx"
import { types } from "mobx-state-tree"
import { MSTGQLStore, configureStoreMixin, QueryOptions } from "mst-gql"
import { MSTGQLStore, configureStoreMixin, QueryOptions, withTypedRefs } from "mst-gql"

import { TodoModel, TodoModelType } from "./TodoModel"
import { todoModelPrimitives, TodoModelSelector } from "./TodoModel.base"
Expand All @@ -13,14 +14,19 @@ export type CreateTodoInput = {
text: string
complete: boolean | undefined
}
/* The TypeScript type that explicits the refs to other models in order to prevent a circular refs issue */
type Refs = {
todos: ObservableMap<string, TodoModelType>
}

/**
* Store, managing, among others, all the objects received through graphQL
*/
export const RootStoreBase = MSTGQLStore
export const RootStoreBase = withTypedRefs<Refs>()(MSTGQLStore
.named("RootStore")
.extend(configureStoreMixin([['Todo', () => TodoModel]], ['Todo']))
.props({
todos: types.optional(types.map(types.late(() => TodoModel)), {})
todos: types.optional(types.map(types.late((): any => TodoModel)), {})
})
.actions(self => ({
queryTodos(variables?: { }, resultSelector: string | ((qb: TodoModelSelector) => TodoModelSelector) = todoModelPrimitives.toString(), options: QueryOptions = {}) {
Expand All @@ -38,4 +44,4 @@ export const RootStoreBase = MSTGQLStore
${typeof resultSelector === "function" ? resultSelector(new TodoModelSelector()).toString() : resultSelector}
} }`, variables, optimisticUpdate)
},
}))
})))
19 changes: 13 additions & 6 deletions examples/2-scaffolding/src/models/PokemonAttackModel.base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,41 @@
/* eslint-disable */
/* tslint:disable */

import { IObservableArray } from "mobx"
import { types } from "mobx-state-tree"
import { MSTGQLRef, QueryBuilder } from "mst-gql"
import { MSTGQLRef, QueryBuilder, withTypedRefs } from "mst-gql"
import { ModelBase } from "./ModelBase"
import { AttackModel } from "./AttackModel"
import { AttackModel, AttackModelType } from "./AttackModel"
import { AttackModelSelector } from "./AttackModel.base"
import { RootStoreType } from "./index"


/* The TypeScript type that explicits the refs to other models in order to prevent a circular refs issue */
type Refs = {
fast: IObservableArray<AttackModelType>;
special: IObservableArray<AttackModelType>;
}

/**
* PokemonAttackBase
* auto generated base class for the model PokemonAttackModel.
*
* Represents a Pokémon's attack types
*/
export const PokemonAttackModelBase = ModelBase
export const PokemonAttackModelBase = withTypedRefs<Refs>()(ModelBase
.named('PokemonAttack')
.props({
__typename: types.optional(types.literal("PokemonAttack"), "PokemonAttack"),
/** The fast attacks of this Pokémon */
fast: types.union(types.undefined, types.null, types.array(types.union(types.null, MSTGQLRef(types.late(() => AttackModel))))),
fast: types.union(types.undefined, types.null, types.array(types.union(types.null, MSTGQLRef(types.late((): any => AttackModel))))),
/** The special attacks of this Pokémon */
special: types.union(types.undefined, types.null, types.array(types.union(types.null, MSTGQLRef(types.late(() => AttackModel))))),
special: types.union(types.undefined, types.null, types.array(types.union(types.null, MSTGQLRef(types.late((): any => AttackModel))))),
})
.views(self => ({
get store() {
return self.__getStore<RootStoreType>()
}
}))
})))

export class PokemonAttackModelSelector extends QueryBuilder {
fast(builder?: string | AttackModelSelector | ((selector: AttackModelSelector) => AttackModelSelector)) { return this.__child(`fast`, AttackModelSelector, builder) }
Expand Down
28 changes: 17 additions & 11 deletions examples/2-scaffolding/src/models/PokemonModel.base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,32 @@
/* eslint-disable */
/* tslint:disable */

import { IObservableArray } from "mobx"
import { types } from "mobx-state-tree"
import { MSTGQLRef, QueryBuilder } from "mst-gql"
import { MSTGQLRef, QueryBuilder, withTypedRefs } from "mst-gql"
import { ModelBase } from "./ModelBase"
import { PokemonAttackModel } from "./PokemonAttackModel"
import { PokemonAttackModel, PokemonAttackModelType } from "./PokemonAttackModel"
import { PokemonAttackModelSelector } from "./PokemonAttackModel.base"
import { PokemonDimensionModel } from "./PokemonDimensionModel"
import { PokemonDimensionModel, PokemonDimensionModelType } from "./PokemonDimensionModel"
import { PokemonDimensionModelSelector } from "./PokemonDimensionModel.base"
import { PokemonEvolutionRequirementModel } from "./PokemonEvolutionRequirementModel"
import { PokemonEvolutionRequirementModel, PokemonEvolutionRequirementModelType } from "./PokemonEvolutionRequirementModel"
import { PokemonEvolutionRequirementModelSelector } from "./PokemonEvolutionRequirementModel.base"
import { PokemonModel } from "./PokemonModel"
import { PokemonModel, PokemonModelType } from "./PokemonModel"
import { RootStoreType } from "./index"


/* The TypeScript type that explicits the refs to other models in order to prevent a circular refs issue */
type Refs = {
evolutions: IObservableArray<PokemonModelType>;
}

/**
* PokemonBase
* auto generated base class for the model PokemonModel.
*
* Represents a Pokémon
*/
export const PokemonModelBase = ModelBase
export const PokemonModelBase = withTypedRefs<Refs>()(ModelBase
.named('Pokemon')
.props({
__typename: types.optional(types.literal("Pokemon"), "Pokemon"),
Expand All @@ -32,17 +38,17 @@ export const PokemonModelBase = ModelBase
/** The name of this Pokémon */
name: types.union(types.undefined, types.null, types.string),
/** The minimum and maximum weight of this Pokémon */
weight: types.union(types.undefined, types.null, types.late(() => PokemonDimensionModel)),
weight: types.union(types.undefined, types.null, types.late((): any => PokemonDimensionModel)),
/** The minimum and maximum weight of this Pokémon */
height: types.union(types.undefined, types.null, types.late(() => PokemonDimensionModel)),
height: types.union(types.undefined, types.null, types.late((): any => PokemonDimensionModel)),
/** The classification of this Pokémon */
classification: types.union(types.undefined, types.null, types.string),
/** The type(s) of this Pokémon */
types: types.union(types.undefined, types.null, types.array(types.union(types.null, types.string))),
/** The type(s) of Pokémons that this Pokémon is resistant to */
resistant: types.union(types.undefined, types.null, types.array(types.union(types.null, types.string))),
/** The attacks of this Pokémon */
attacks: types.union(types.undefined, types.null, types.late(() => PokemonAttackModel)),
attacks: types.union(types.undefined, types.null, types.late((): any => PokemonAttackModel)),
/** The type(s) of Pokémons that this Pokémon weak to */
weaknesses: types.union(types.undefined, types.null, types.array(types.union(types.null, types.string))),
fleeRate: types.union(types.undefined, types.null, types.number),
Expand All @@ -51,7 +57,7 @@ export const PokemonModelBase = ModelBase
/** The evolutions of this Pokémon */
evolutions: types.union(types.undefined, types.null, types.array(types.union(types.null, MSTGQLRef(types.late((): any => PokemonModel))))),
/** The evolution requirements of this Pokémon */
evolutionRequirements: types.union(types.undefined, types.null, types.late(() => PokemonEvolutionRequirementModel)),
evolutionRequirements: types.union(types.undefined, types.null, types.late((): any => PokemonEvolutionRequirementModel)),
/** The maximum HP of this Pokémon */
maxHP: types.union(types.undefined, types.null, types.integer),
image: types.union(types.undefined, types.null, types.string),
Expand All @@ -60,7 +66,7 @@ export const PokemonModelBase = ModelBase
get store() {
return self.__getStore<RootStoreType>()
}
}))
})))

export class PokemonModelSelector extends QueryBuilder {
get id() { return this.__attr(`id`) }
Expand Down
17 changes: 12 additions & 5 deletions examples/2-scaffolding/src/models/RootStore.base.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/* This is a mst-gql generated file, don't modify it manually */
/* eslint-disable */
/* tslint:disable */
import { ObservableMap } from "mobx"
import { types } from "mobx-state-tree"
import { MSTGQLStore, configureStoreMixin, QueryOptions } from "mst-gql"
import { MSTGQLStore, configureStoreMixin, QueryOptions, withTypedRefs } from "mst-gql"

import { PokemonModel, PokemonModelType } from "./PokemonModel"
import { pokemonModelPrimitives, PokemonModelSelector } from "./PokemonModel.base"
Expand All @@ -16,15 +17,21 @@ import { PokemonEvolutionRequirementModel, PokemonEvolutionRequirementModelType
import { pokemonEvolutionRequirementModelPrimitives, PokemonEvolutionRequirementModelSelector } from "./PokemonEvolutionRequirementModel.base"


/* The TypeScript type that explicits the refs to other models in order to prevent a circular refs issue */
type Refs = {
pokemons: ObservableMap<string, PokemonModelType>,
attacks: ObservableMap<string, AttackModelType>
}

/**
* Store, managing, among others, all the objects received through graphQL
*/
export const RootStoreBase = MSTGQLStore
export const RootStoreBase = withTypedRefs<Refs>()(MSTGQLStore
.named("RootStore")
.extend(configureStoreMixin([['Pokemon', () => PokemonModel], ['PokemonDimension', () => PokemonDimensionModel], ['PokemonAttack', () => PokemonAttackModel], ['Attack', () => AttackModel], ['PokemonEvolutionRequirement', () => PokemonEvolutionRequirementModel]], ['Pokemon', 'Attack']))
.props({
pokemons: types.optional(types.map(types.late(() => PokemonModel)), {}),
attacks: types.optional(types.map(types.late(() => AttackModel)), {})
pokemons: types.optional(types.map(types.late((): any => PokemonModel)), {}),
attacks: types.optional(types.map(types.late((): any => AttackModel)), {})
})
.actions(self => ({
queryPokemons(variables: { first: number }, resultSelector: string | ((qb: PokemonModelSelector) => PokemonModelSelector) = pokemonModelPrimitives.toString(), options: QueryOptions = {}) {
Expand All @@ -37,4 +44,4 @@ export const RootStoreBase = MSTGQLStore
${typeof resultSelector === "function" ? resultSelector(new PokemonModelSelector()).toString() : resultSelector}
} }`, variables, options)
},
}))
})))
22 changes: 15 additions & 7 deletions examples/3-twitter-clone/src/app/models/MessageModel.base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,43 @@
/* eslint-disable */
/* tslint:disable */

import { IObservableArray } from "mobx"
import { types } from "mobx-state-tree"
import { MSTGQLRef, QueryBuilder } from "mst-gql"
import { MSTGQLRef, QueryBuilder, withTypedRefs } from "mst-gql"
import { ModelBase } from "./ModelBase"
import { MessageModel } from "./MessageModel"
import { UserModel } from "./UserModel"
import { MessageModel, MessageModelType } from "./MessageModel"
import { UserModel, UserModelType } from "./UserModel"
import { UserModelSelector } from "./UserModel.base"
import { RootStoreType } from "./index"


/* The TypeScript type that explicits the refs to other models in order to prevent a circular refs issue */
type Refs = {
user: UserModelType;
likes: IObservableArray<UserModelType>;
replyTo: MessageModelType;
}

/**
* MessageBase
* auto generated base class for the model MessageModel.
*/
export const MessageModelBase = ModelBase
export const MessageModelBase = withTypedRefs<Refs>()(ModelBase
.named('Message')
.props({
__typename: types.optional(types.literal("Message"), "Message"),
id: types.identifier,
timestamp: types.union(types.undefined, types.number),
user: types.union(types.undefined, MSTGQLRef(types.late(() => UserModel))),
user: types.union(types.undefined, MSTGQLRef(types.late((): any => UserModel))),
text: types.union(types.undefined, types.string),
likes: types.union(types.undefined, types.null, types.array(MSTGQLRef(types.late(() => UserModel)))),
likes: types.union(types.undefined, types.null, types.array(MSTGQLRef(types.late((): any => UserModel)))),
replyTo: types.union(types.undefined, types.null, MSTGQLRef(types.late((): any => MessageModel))),
})
.views(self => ({
get store() {
return self.__getStore<RootStoreType>()
}
}))
})))

export class MessageModelSelector extends QueryBuilder {
get id() { return this.__attr(`id`) }
Expand Down
4 changes: 2 additions & 2 deletions examples/3-twitter-clone/src/app/models/MessageModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export {
* MessageModel
*/
export const MessageModel = MessageModelBase.views(self => ({
get isLikedByMe() {
get isLikedByMe(): boolean {
return self.likes.includes(self.store.me)
}
})).actions(self => {
Expand All @@ -38,7 +38,7 @@ export const MessageModel = MessageModelBase.views(self => ({
},
loadReplies() {
if (!loadReplyQuery) {
loadReplyQuery = self.store.loadMessages(0, 100, self.id)
loadReplyQuery = self.store.loadMessages("", 100, self.id)
} else {
loadReplyQuery.refetch()
}
Expand Down
17 changes: 12 additions & 5 deletions examples/3-twitter-clone/src/app/models/RootStore.base.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,31 @@
/* This is a mst-gql generated file, don't modify it manually */
/* eslint-disable */
/* tslint:disable */
import { ObservableMap } from "mobx"
import { types } from "mobx-state-tree"
import { MSTGQLStore, configureStoreMixin, QueryOptions } from "mst-gql"
import { MSTGQLStore, configureStoreMixin, QueryOptions, withTypedRefs } from "mst-gql"

import { MessageModel, MessageModelType } from "./MessageModel"
import { messageModelPrimitives, MessageModelSelector } from "./MessageModel.base"
import { UserModel, UserModelType } from "./UserModel"
import { userModelPrimitives, UserModelSelector } from "./UserModel.base"


/* The TypeScript type that explicits the refs to other models in order to prevent a circular refs issue */
type Refs = {
messages: ObservableMap<string, MessageModelType>,
users: ObservableMap<string, UserModelType>
}

/**
* Store, managing, among others, all the objects received through graphQL
*/
export const RootStoreBase = MSTGQLStore
export const RootStoreBase = withTypedRefs<Refs>()(MSTGQLStore
.named("RootStore")
.extend(configureStoreMixin([['Message', () => MessageModel], ['User', () => UserModel]], ['Message', 'User']))
.props({
messages: types.optional(types.map(types.late(() => MessageModel)), {}),
users: types.optional(types.map(types.late(() => UserModel)), {})
messages: types.optional(types.map(types.late((): any => MessageModel)), {}),
users: types.optional(types.map(types.late((): any => UserModel)), {})
})
.actions(self => ({
queryMessages(variables: { offset: string | undefined, count: number | undefined, replyTo: string | undefined }, resultSelector: string | ((qb: MessageModelSelector) => MessageModelSelector) = messageModelPrimitives.toString(), options: QueryOptions = {}) {
Expand Down Expand Up @@ -56,4 +63,4 @@ export const RootStoreBase = MSTGQLStore
${typeof resultSelector === "function" ? resultSelector(new MessageModelSelector()).toString() : resultSelector}
} }`, variables, onData)
},
}))
})))
8 changes: 6 additions & 2 deletions examples/3-twitter-clone/src/app/models/RootStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { RootStoreBase } from "./RootStore.base"
import { types } from "mobx-state-tree"
import { MessageModel } from "./MessageModel"
import { selectFromMessage } from "./MessageModel.base"
import { UserModelType } from "./UserModel"

export interface RootStoreType extends Instance<typeof RootStore.Type> {}

Expand All @@ -18,10 +19,13 @@ export const RootStore = RootStoreBase.props({
// The store itself does store Messages in loading order,
// so we use an additional collection of references, to preserve the order as
// it should be, regardless whether we are loading new or old messages.
sortedMessages: types.optional(types.array(types.reference(MessageModel)), [])
sortedMessages: types.optional(
types.array(types.reference(MessageModel as any)),
[]
)
})
.views(self => ({
get me() {
get me(): UserModelType {
return self.users.get("mweststrate")
}
}))
Expand Down
22 changes: 15 additions & 7 deletions examples/3-twitter-clone/src/server/models/MessageModel.base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,41 @@
/* eslint-disable */
/* tslint:disable */

import { IObservableArray } from "mobx"
import { types } from "mobx-state-tree"
import { MSTGQLRef, QueryBuilder } from "mst-gql"
import { MSTGQLRef, QueryBuilder, withTypedRefs } from "mst-gql"
import { ModelBase } from "./ModelBase"
import { MessageModel } from "./MessageModel"
import { UserModel } from "./UserModel"
import { MessageModel, MessageModelType } from "./MessageModel"
import { UserModel, UserModelType } from "./UserModel"
import { RootStoreType } from "./index"


/* The TypeScript type that explicits the refs to other models in order to prevent a circular refs issue */
type Refs = {
user: UserModelType;
likes: IObservableArray<UserModelType>;
replyTo: MessageModelType;
}

/**
* MessageBase
* auto generated base class for the model MessageModel.
*/
export const MessageModelBase = ModelBase
export const MessageModelBase = withTypedRefs<Refs>()(ModelBase
.named('Message')
.props({
__typename: types.optional(types.literal("Message"), "Message"),
id: types.identifier,
timestamp: types.union(types.undefined, types.number),
user: types.union(types.undefined, MSTGQLRef(types.late(() => UserModel))),
user: types.union(types.undefined, MSTGQLRef(types.late((): any => UserModel))),
text: types.union(types.undefined, types.string),
likes: types.union(types.undefined, types.null, types.array(MSTGQLRef(types.late(() => UserModel)))),
likes: types.union(types.undefined, types.null, types.array(MSTGQLRef(types.late((): any => UserModel)))),
replyTo: types.union(types.undefined, types.null, MSTGQLRef(types.late((): any => MessageModel))),
})
.views(self => ({
get store() {
return self.__getStore<RootStoreType>()
}
}))
})))


Loading

0 comments on commit 809aeaa

Please sign in to comment.