Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Union type in actions #257

Merged
merged 8 commits into from
Jul 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions examples/3-twitter-clone/src/app/models/RootStore.base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import { ObservableMap } from "mobx"
import { types } from "mobx-state-tree"
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"
import { MessageModel, MessageModelType } from "./MessageModel"
import { messageModelPrimitives, MessageModelSelector } from "./MessageModel.base"

import { searchResultModelPrimitives, SearchResultModelSelector , SearchResultUnion } from "./"


/* The TypeScript type that explicits the refs to other models in order to prevent a circular refs issue */
Expand All @@ -22,6 +24,7 @@ type Refs = {
* Enums for the names of base graphql actions
*/
export enum RootStoreBaseQueries {
querySearch="querySearch",
queryMessages="queryMessages",
queryMessage="queryMessage",
queryMe="queryMe"
Expand All @@ -37,12 +40,17 @@ mutatePostTweet="mutatePostTweet"
*/
export const RootStoreBase = withTypedRefs<Refs>()(MSTGQLStore
.named("RootStore")
.extend(configureStoreMixin([['Message', () => MessageModel], ['User', () => UserModel]], ['Message', 'User'], "js"))
.extend(configureStoreMixin([['User', () => UserModel], ['Message', () => MessageModel]], ['Message', 'User'], "js"))
.props({
messages: types.optional(types.map(types.late((): any => MessageModel)), {}),
users: types.optional(types.map(types.late((): any => UserModel)), {})
})
.actions(self => ({
querySearch(variables: { searchText: string }, resultSelector: string | ((qb: SearchResultModelSelector) => SearchResultModelSelector) = searchResultModelPrimitives.toString(), options: QueryOptions = {}) {
return self.query<{ search: SearchResultUnion[]}>(`query search($searchText: String!) { search(searchText: $searchText) {
${typeof resultSelector === "function" ? resultSelector(new SearchResultModelSelector()).toString() : resultSelector}
} }`, variables, options)
},
queryMessages(variables: { offset?: string, count?: number, replyTo?: string }, resultSelector: string | ((qb: MessageModelSelector) => MessageModelSelector) = messageModelPrimitives.toString(), options: QueryOptions = {}) {
return self.query<{ messages: MessageModelType[]}>(`query messages($offset: ID, $count: Int, $replyTo: ID) { messages(offset: $offset, count: $count, replyTo: $replyTo) {
${typeof resultSelector === "function" ? resultSelector(new MessageModelSelector()).toString() : resultSelector}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/* This is a mst-gql generated file, don't modify it manually */
/* eslint-disable */
/* tslint:disable */

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

export type SearchResultUnion = UserModelType | MessageModelType
special-character marked this conversation as resolved.
Show resolved Hide resolved

export class SearchResultModelSelector extends QueryBuilder {
user(builder?: string | UserModelSelector | ((selector: UserModelSelector) => UserModelSelector)) { return this.__inlineFragment(`User`, UserModelSelector, builder) }
message(builder?: string | MessageModelSelector | ((selector: MessageModelSelector) => MessageModelSelector)) { return this.__inlineFragment(`Message`, MessageModelSelector, builder) }
}
export function selectFromSearchResult() {
return new SearchResultModelSelector()
}

// provides all primitive fields of union member types combined together
export const searchResultModelPrimitives = selectFromSearchResult().user(userModelPrimitives).message(messageModelPrimitives)
3 changes: 2 additions & 1 deletion examples/3-twitter-clone/src/app/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
/* eslint-disable */
/* tslint:disable */

export * from "./MessageModel"
export * from "./SearchResultModelSelector"
export * from "./UserModel"
export * from "./MessageModel"
export * from "./RootStore"
export * from "./reactUtils"
2 changes: 1 addition & 1 deletion examples/3-twitter-clone/src/app/models/reactUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import { createStoreContext, createUseQueryHook } from "mst-gql"
import * as React from "react"
import { RootStore, RootStoreType } from "./RootStore"
import { RootStoreType } from "./RootStore"

export const StoreContext = createStoreContext<RootStoreType>(React)

Expand Down
6 changes: 4 additions & 2 deletions examples/3-twitter-clone/src/server/models/RootStore.base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import { ObservableMap } from "mobx"
import { types } from "mobx-state-tree"
import { MSTGQLStore, configureStoreMixin, QueryOptions, withTypedRefs } from "mst-gql"

import { MessageModel, MessageModelType } from "./MessageModel"
import { UserModel, UserModelType } from "./UserModel"
import { MessageModel, MessageModelType } from "./MessageModel"



/* The TypeScript type that explicits the refs to other models in order to prevent a circular refs issue */
Expand All @@ -20,6 +21,7 @@ type Refs = {
* Enums for the names of base graphql actions
*/
export enum RootStoreBaseQueries {
querySearch="querySearch",
queryMessages="queryMessages",
queryMessage="queryMessage",
queryMe="queryMe"
Expand All @@ -35,7 +37,7 @@ mutatePostTweet="mutatePostTweet"
*/
export const RootStoreBase = withTypedRefs<Refs>()(types.model()
.named("RootStore")
.extend(configureStoreMixin([['Message', () => MessageModel], ['User', () => UserModel]], ['Message', 'User'], "js"))
.extend(configureStoreMixin([['User', () => UserModel], ['Message', () => MessageModel]], ['Message', 'User'], "js"))
.props({
messages: types.optional(types.map(types.late((): any => MessageModel)), {}),
users: types.optional(types.map(types.late((): any => UserModel)), {})
Expand Down
2 changes: 1 addition & 1 deletion examples/3-twitter-clone/src/server/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
/* eslint-disable */
/* tslint:disable */

export * from "./MessageModel"
export * from "./UserModel"
export * from "./MessageModel"
export * from "./RootStore"
3 changes: 3 additions & 0 deletions examples/3-twitter-clone/src/server/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type Message {
replyTo: Message
}
type Query {
search(searchText: String!): [SearchResult!]
messages(offset: ID, count: Int, replyTo: ID): [Message]
message(id: ID!): Message
me: User
Expand All @@ -24,3 +25,5 @@ type Mutation {
like(msg: ID!, user: ID!): Message
postTweet(text: String!, user: ID!, replyTo: ID): Message
}

union SearchResult = User | Message
10 changes: 10 additions & 0 deletions examples/3-twitter-clone/src/server/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ const store = RootStore.create()

export const resolvers = {
Query: {
search: (_, { searchText }) => {
const messages = store.messages
.values()
.filter(message => message.text.includes(searchText))
const user = store.users
.values()
.filter(user => user.name.includes(searchText))

return [...messages, ...user]
},
messages: (_, { offset, count, replyTo }) =>
store.allMessages(offset, count, replyTo),
message: (_, { id }) => store.getMessage(id),
Expand Down
38 changes: 35 additions & 3 deletions generator/generate.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ function generate(

const files = [] // [[name, contents]]
const objectTypes = [] // all known OBJECT types for which MST classes are generated
const unionTypes = [] // all known UNION types for which ModelSelector classes are generated
const origObjectTypes = [] // all known OBJECT types for which MST classes are generated
const inputTypes = [] // all known INPUT_OBJECT types for which MST classes are generated
const knownTypes = [] // all known types (including enums and such) for which MST classes are generated
Expand Down Expand Up @@ -317,6 +318,7 @@ ${generateFragments(name, primitiveFields, nonPrimitiveFields)}
const interfaceOrUnionType = interfaceAndUnionTypes.get(type.name)
const isUnion =
interfaceOrUnionType && interfaceOrUnionType.kind === "UNION"
if (isUnion) unionTypes.push(type.name)
const fileName = type.name + "ModelSelector"
const {
primitiveFields,
Expand All @@ -326,6 +328,7 @@ ${generateFragments(name, primitiveFields, nonPrimitiveFields)}

interfaceOrUnionType &&
interfaceOrUnionType.ofTypes.forEach(t => {
/** Base file imports */
const toBeImported = [`${t.name}ModelSelector`]
if (isUnion) toBeImported.push(`${toFirstLower(t.name)}ModelPrimitives`)
addImportToMap(
Expand All @@ -334,11 +337,34 @@ ${generateFragments(name, primitiveFields, nonPrimitiveFields)}
`${t.name}Model.base`,
...toBeImported
)

/** Imports from core model */
if (isUnion) {
// Import <model>ModelType from the core file to be used in the TS union type
addImportToMap(
imports,
fileName,
`${t.name}Model`,
`${t.name}ModelType`
)
}
})

let contents = header + "\n\n"
contents += 'import { QueryBuilder } from "mst-gql"\n'
contents += printRelativeImports(imports)

// Add the correct type for a TS union to the exports
if (isUnion) {
contents += ifTS(
`export type ${
interfaceOrUnionType.name
}Union = ${interfaceOrUnionType.ofTypes
.map(unionModel => `${unionModel.name}ModelType`)
.join(" | ")}\n\n`
)
}

contents += generateFragments(
type.name,
primitiveFields,
Expand Down Expand Up @@ -602,6 +628,12 @@ ${objectTypes
}`
)
.join("")}
${unionTypes.map(
t =>
`\nimport { ${toFirstLower(t)}ModelPrimitives, ${t}ModelSelector ${ifTS(
`, ${t}Union`
)} } from "./"`
)}
${enumTypes
.map(
t =>
Expand Down Expand Up @@ -789,9 +821,9 @@ ${enumContent}
: `<{ ${name}: ${
isScalar
? `${printTsPrimitiveType(type.name)} `
: `${returnType.name}${modelTypePostfix}${
returnsList ? "[]" : ""
}`
: `${returnType.name}${
returnType.kind === "UNION" ? "Union" : modelTypePostfix
}${returnsList ? "[]" : ""}`
}}>`

const formalArgs =
Expand Down
13 changes: 13 additions & 0 deletions tests/generator/__snapshots__/generate.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ 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 = {
users: ObservableMap<string, UserModelType>
Expand Down Expand Up @@ -429,6 +430,7 @@ import { PossiblyEmptyBoxModel, PossiblyEmptyBoxModelType } from \\"./PossiblyEm
import { possiblyEmptyBoxModelPrimitives, PossiblyEmptyBoxModelSelector } from \\"./PossiblyEmptyBoxModel.base\\"



/* The TypeScript type that explicits the refs to other models in order to prevent a circular refs issue */
type Refs = {
myUsers: ObservableMap<string, MyUserModelType>,
Expand Down Expand Up @@ -602,6 +604,7 @@ 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 = {
users: ObservableMap<string, UserModelType>
Expand Down Expand Up @@ -839,6 +842,7 @@ import { MSTGQLStore, configureStoreMixin, QueryOptions, withTypedRefs } from \\
import { UserModel, UserModelType } from \\"./UserModel\\"
import { userModelPrimitives, UserModelSelector } from \\"./UserModel.base\\"


import { Role } from \\"./RoleEnum\\"
import { interest_enum } from \\"./interest_enum\\"

Expand Down Expand Up @@ -1076,6 +1080,7 @@ import { MSTGQLStore, configureStoreMixin, QueryOptions, withTypedRefs } from \\
import { UserModel, UserModelType } from \\"./UserModel\\"
import { userModelPrimitives, UserModelSelector } from \\"./UserModel.base\\"


import { Role } from \\"./RoleEnum\\"
import { InterestEnum } from \\"./InterestEnum\\"

Expand Down Expand Up @@ -1414,6 +1419,7 @@ import { OrganizationModel, OrganizationModelType } from \\"./OrganizationModel\
import { organizationModelPrimitives, OrganizationModelSelector } from \\"./OrganizationModel.base\\"



/* The TypeScript type that explicits the refs to other models in order to prevent a circular refs issue */
type Refs = {
repos: ObservableMap<string, RepoModelType>
Expand Down Expand Up @@ -1566,9 +1572,13 @@ export const SearchResultModel = SearchResultModelBase
/* tslint:disable */

import { QueryBuilder } from \\"mst-gql\\"
import { BookModelType } from \\"./BookModel\\"
import { BookModelSelector, bookModelPrimitives } from \\"./BookModel.base\\"
import { MovieModelType } from \\"./MovieModel\\"
import { MovieModelSelector, movieModelPrimitives } from \\"./MovieModel.base\\"

export type SearchItemUnion = MovieModelType | BookModelType

export class SearchItemModelSelector extends QueryBuilder {
movie(builder?: string | MovieModelSelector | ((selector: MovieModelSelector) => MovieModelSelector)) { return this.__inlineFragment(\`Movie\`, MovieModelSelector, builder) }
book(builder?: string | BookModelSelector | ((selector: BookModelSelector) => BookModelSelector)) { return this.__inlineFragment(\`Book\`, BookModelSelector, builder) }
Expand Down Expand Up @@ -1744,6 +1754,8 @@ import { movieModelPrimitives, MovieModelSelector } from \\"./MovieModel.base\\"
import { BookModel, BookModelType } from \\"./BookModel\\"
import { bookModelPrimitives, BookModelSelector } from \\"./BookModel.base\\"

import { searchItemModelPrimitives, SearchItemModelSelector , SearchItemUnion } from \\"./\\"


/* The TypeScript type that explicits the refs to other models in order to prevent a circular refs issue */
type Refs = {
Expand Down Expand Up @@ -1917,6 +1929,7 @@ import { MovieModel, MovieModelType } from \\"./MovieModel\\"
import { movieModelPrimitives, MovieModelSelector } from \\"./MovieModel.base\\"



export type MovieInput = {
description: string[]
director?: string[]
Expand Down
2 changes: 2 additions & 0 deletions tests/lib/abstractTypes/models/RootStore.base.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { userModelPrimitives, UserModelSelector } from "./UserModel.base"
import { OrganizationModel } from "./OrganizationModel"
import { organizationModelPrimitives, OrganizationModelSelector } from "./OrganizationModel.base"

import { searchItemModelPrimitives, SearchItemModelSelector } from "./"




Expand Down
2 changes: 2 additions & 0 deletions tests/lib/abstractTypes/models/SearchItemModelSelector.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
/* eslint-disable */

import { QueryBuilder } from "mst-gql"
import { BookModelType } from "./BookModel"
import { BookModelSelector, bookModelPrimitives } from "./BookModel.base"
import { MovieModelType } from "./MovieModel"
import { MovieModelSelector, movieModelPrimitives } from "./MovieModel.base"

export class SearchItemModelSelector extends QueryBuilder {
Expand Down
1 change: 1 addition & 0 deletions tests/lib/todos/models/RootStore.base.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { todoModelPrimitives, TodoModelSelector } from "./TodoModel.base"




/**
* Store, managing, among others, all the objects received through graphQL
*/
Expand Down