Skip to content
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
df8d4f4
feat(discriminators): add composeWithMongooseDiscriminators
mernxl Jul 4, 2018
16b1b33
test(discriminators): add few test, proof of concept
mernxl Jul 4, 2018
9c6bf26
fix: eslint and prettier errors
nodkz Jul 6, 2018
78f0ea4
test: use `mongodb-memory-server` in tests, instead of locally instal…
nodkz Jul 6, 2018
f443704
test: fix flowtype errors
nodkz Jul 6, 2018
b5981d8
refactor: move `pagination` resolver code to its own file with tests …
nodkz Jul 9, 2018
20d283e
refactor: move `connection` resolver code to /resolvers folder (Requi…
nodkz Jul 9, 2018
87e6cf0
Merge branch 'refactor_resolvers' into mongoose-discriminantors
nodkz Jul 9, 2018
5d5b6c6
refactor(discriminators): rename and move discriminator files to sepa…
mernxl Jul 10, 2018
50fd202
refactor(discriminators): revert ChildDiscriminator class to TypeComp…
mernxl Jul 10, 2018
eb46780
refactor(discriminators): move EMCResolvers mapping to resolvers/index
mernxl Jul 10, 2018
4878844
fix: mongoose 5.2.0 now uses `countDocuments` instead of `count`
nodkz Jul 10, 2018
922a302
feat: already generated TC may be obtained via schemaComposer.getTC(m…
nodkz Jul 10, 2018
d31de65
feat(discriminator): add ability to merge customization options
mernxl Jul 10, 2018
e93a6ab
Merge branch 'master' into mongoose-discriminantors
mernxl Jul 10, 2018
c4eae4d
test(discriminator): add test suits for _disTypes, minor refactor
mernxl Jul 11, 2018
50d1a2b
test: remove redundant cleaning of _gqcTypeComposer property
nodkz Jul 11, 2018
dad2397
style: fix flowtype error and use `getFieldConfig` method
nodkz Jul 11, 2018
62946c3
chore: update dependencies
nodkz Jul 12, 2018
8d460b1
fix: better to give new name to Interface rather than user type
nodkz Jul 12, 2018
1634944
fix: remove YAGNI method getGQC(), rename GQC to schemaComposer
nodkz Jul 12, 2018
5500456
refactor: `_disTypes` replaced via new schemaComposer.addSchemaMustHa…
nodkz Jul 12, 2018
b60d243
refactor(discriminator): move DiscriminatorTypeComposer to own file
mernxl Jul 13, 2018
2ae085b
refactor(discriminator): replace getDBaseName() with getTypeName()
mernxl Jul 13, 2018
e8a6b1c
feat(discriminator): override more TypeComposer field change methods
mernxl Jul 13, 2018
0aa9b99
doc(README.md): add discriminator example and use case
mernxl Jul 13, 2018
156c21f
refactor(DiscriminatorTC): change constructor on static method `creat…
nodkz Jul 16, 2018
17bb1a7
chore: update graphql-compose to 4.7.1 version as minimal required ve…
nodkz Jul 16, 2018
1b39922
fix(Flowtype): improve flowtype type definitions
nodkz Jul 16, 2018
8a244cc
refactor: replace `GraphQLInterfaceType` by `InterfaceTypeComposer`
nodkz Jul 16, 2018
4279a7b
chore: fix flowtype definitions and cove rest tests files by flow
nodkz Jul 16, 2018
90f2723
refactor(discriminators): rename 'Options' to 'DiscriminatorOptions'
mernxl Jul 16, 2018
2bb447e
fix: expose composeWithMongooseDiscriminators, other utils to src/ind…
mernxl Jul 16, 2018
331e410
fix(discriminators): fix own member object iteration on prepare-resol…
mernxl Jul 16, 2018
15de649
fix(discriminators): fix grammatical error on error message
mernxl Jul 16, 2018
73afb58
test(discriminators): rearrange test files and test cases
mernxl Jul 16, 2018
f511059
test(discriminators): add tests for DiscriminatorTypeComposer methods
mernxl Jul 17, 2018
41c2cfe
test: refactor try catch with arrow function
nodkz Jul 17, 2018
0b2d024
chore: update flowtype defs and fix its errors
nodkz Jul 17, 2018
bdee04a
refactor: simplify discriminators directory structure
nodkz Jul 17, 2018
de1dca6
refactor: remove `customizationOptions` property from options
nodkz Jul 17, 2018
1b256d5
ci: remove greenkeeper
nodkz Jul 17, 2018
6a7b2b0
build: fix `es` build
nodkz Jul 17, 2018
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
6 changes: 6 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"env": {
"cjs": {
"plugins": [
"transform-class-properties",
["transform-runtime", { "polyfill": false }]
],
"presets": [
Expand All @@ -17,6 +18,7 @@
]
},
"mjs": {
"plugins": ["transform-class-properties"],
"presets": [
[
"env",
Expand All @@ -34,6 +36,7 @@
},
"node8": {
"plugins": [
"transform-class-properties",
["transform-runtime", { "polyfill": false }]
],
"presets": [
Expand All @@ -47,6 +50,9 @@
]
},
"test": {
"plugins": [
"transform-class-properties",
],
"presets": [
["env", {
"targets": {
Expand Down
123 changes: 123 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,129 @@ You think that is to much code?
I don't think so, because by default internally was created about 55 graphql types (for input, sorting, filtering). So you will need much much more lines of code to implement all these CRUD operations by hands.


### Working with Mongoose Collection Level Discriminators
Variable Namings
* `...DTC` - Suffix for a `DiscriminatorTypeComposer` instance, which is also an instance of `TypeComposer`. All fields and Relations manipulations on this instance affects all registered discriminators and the Discriminator Interface.

```js
import mongoose from 'mongoose';
import { schemaComposer } from 'graphql-composer';
import { composeWithMongooseDiscriminators } from 'graphql-compose-mongoose';

// pick a discriminatorKey
const DKey = 'type';

const enumCharacterType = {
PERSON: 'Person',
DROID: 'Droid',
};

// DEFINE BASE SCHEMA
const CharacterSchema = new mongoose.Schema({
// _id: field...
name: String,

type: {
type: String,
require: true,
enum: (Object.keys(enumCharacterType): Array<string>),
},

friends: [String], // another Character
appearsIn: [String], // movie
});

// DEFINE DISCRIMINATOR SCHEMAS
const DroidSchema = new Schema({
makeDate: Date,
modelNumber: Number,
primaryFunction: [String],
});

const PersonSchema = new Schema({
dob: Number,
starShips: [String],
totalCredits: Number,
});

// set discriminator Key
CharacterSchema.set('discriminatorKey', DKey);

// create base Model
const CharacterModel = mongoose.model('Character', CharacterSchema);

// create mongoose discriminator models
const DroidModel = CharacterModel.discriminator(enumCharacterType.DROID, DroidSchema);
const PersonModel = CharacterModel.discriminator(enumCharacterType.PERSON, PersonSchema);

// create DiscriminatorTypeComposer
// discrimatorOptions
const baseOptions = {
customizationOptions: { // regular TypeConverterOptions, passed to composeWithMongoose
fields: {
remove: ['friends'],
}
}
}
const CharacterDTC = composeWithMongooseDiscriminators(CharacterModel, baseOptions);

// create Discriminator Types
const droidTypeConverterOptions = { // this options will be merged with baseOptions -> customisationsOptions
fields: {
remove: ['makeDate'],
}
};
const DroidTC = CharacterDTC.discriminator(DroidModel, droidTypeConverterOptions);
const PersonTC = CharacterDTC.discriminator(PersonModel); // baseOptions -> customisationsOptions applied

// You may now use CharacterDTC to add fields to all Discriminators
// Use DroidTC, `PersonTC as any other TypeComposer.
schemaComposer.rootMutation().addFields({
droidCreate: DroidTC.getResolver('createOne'),
personCreate: PersonTC.getResolver('createOne'),
});

const schema = schemaComposer.buildSchema();

describe('createOne', () => {
it('should create child document without specifying DKey', async () => {
const res = await graphql.graphql(
schema,
`mutation CreateCharacters {
droidCreate(record: {name: "Queue XL", modelNumber: 360 }) {
record {
__typename
type
name
modelNumber
}
}

personCreate(record: {name: "mernxl", dob: 57275272}) {
record {
__typename
type
name
dob
}
}
}`
);

expect(res).toEqual({
data: {
droidCreate: {
record: { __typename: 'Droid', type: 'Droid', name: 'Queue XL', modelNumber: 360 },
},
personCreate: {
record: { __typename: 'Person', type: 'Person', name: 'mernxl', dob: 57275272 },
},
},
});
});
});
```

## FAQ

### Can I get generated vanilla GraphQL types?
Expand Down
58 changes: 47 additions & 11 deletions flow-typed/npm/mongoose_v4.x.x.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,12 @@ type Mongoose$SchemaHookTypes =
| "save"
| "validate"
| "find"
| "findOne"
| "count"
| "update"
| "remove"
| "findOneAndRemove"
| "findOneAndUpdate"
| "init";

type Mongoose$SchemaPlugin<Opts> = (
Expand Down Expand Up @@ -252,7 +255,7 @@ declare class Mongoose$Document {
): Promise<UpdateResult> & { exec(): Promise<UpdateResult> };
static create(doc: $Shape<this> | Array<$Shape<this>>): Promise<this>;
static where(criteria?: Object): Mongoose$Query<this, this>;
static aggregate(pipeline: Object[]): Promise<any>;
static aggregate(pipeline: Object[]): Aggregate$Query;
static bulkWrite(ops: Object[]): Promise<any>;
static deleteMany(criteria: Object): Promise<any>;
static deleteOne(criteria: Object): Promise<any>;
Expand Down Expand Up @@ -420,6 +423,38 @@ declare class Mongoose$Query<Result, Doc> extends Promise<Result> {
toConstructor(): Class<Mongoose$Query<Result, Doc>>;
}

declare class Aggregate$Query extends Promise<any> {
exec(): Promise<any>;
allowDiskUse(bool: boolean): Aggregate$Query;
addCursorFlag(str: string, bool: boolean): Aggregate$Query;
addFields(opts?: Object): Aggregate$Query;
append(opts?: Object): Aggregate$Query;
collation(opts?: Object): Aggregate$Query;
count(str: string): Promise<number>;
cursor(opts?: Object): Mongoose$QueryCursor<Object>;
exec(cb?:Function): Promise<any>;
explain(cb?:Function): Aggregate$Query;
facet(opts?: Object): Aggregate$Query;
graphLookup(opts?: Object): Aggregate$Query;
group(opts?: Object): Aggregate$Query;
hint(opts?: Object): Aggregate$Query;
limit(n: number): Aggregate$Query;
lookup(opts?: Object): Aggregate$Query;
match(opts?: Object): Aggregate$Query;
model(opts?: Object): Aggregate$Query;
near(opts?: Object): Aggregate$Query;
option(opts?: Object): Aggregate$Query;
pipeline(): Object[];
project(opts?: Object): Aggregate$Query;
read(str: string): Aggregate$Query;
replaceRoot(opts?: Object): Aggregate$Query;
sample(n: number): Aggregate$Query;
skip(n: number): Aggregate$Query;
sort(options: {} | string): Aggregate$Query;
sortByCount(options: {} | string): Aggregate$Query;
unwind(str: string): Aggregate$Query;
}

declare class Mongoose$QueryCursor<Doc> {
on(type: "data" | "end" | string, cb: Function): void;
next(cb?: (err: Error, doc: Doc) => void): Promise<?Doc>;
Expand Down Expand Up @@ -498,15 +533,15 @@ declare class Mongoose$Connection {
}

declare module "mongoose" {
declare type MongooseConnection = Mongoose$Connection;
declare type MongoId = MongoId;
declare type BSONObjectId = bson$ObjectId;
declare type ObjectId = bson$ObjectId;
declare type MongooseQuery<Result, Doc> = Mongoose$Query<Result, Doc>;
declare type MongooseDocument = Mongoose$Document;
declare type MongooseModel = typeof Mongoose$Document;
declare type MongooseSchema<Doc> = Mongoose$Schema<Doc>;
declare type MongooseSchemaField<Schema> = Mongoose$SchemaField<
declare export type MongooseConnection = Mongoose$Connection;
declare export type MongoId = MongoId;
declare export type BSONObjectId = bson$ObjectId;
declare export type ObjectId = bson$ObjectId;
declare export type MongooseQuery<Result, Doc> = Mongoose$Query<Result, Doc>;
declare export type MongooseDocument = Mongoose$Document;
declare export type MongooseModel = typeof Mongoose$Document;
declare export type MongooseSchema<Doc> = Mongoose$Schema<Doc>;
declare export type MongooseSchemaField<Schema> = Mongoose$SchemaField<
Schema
>;

Expand All @@ -515,9 +550,10 @@ declare module "mongoose" {
Types: Mongoose$Types,
Promise: any,
model: $PropertyType<Mongoose$Connection, "model">,
models: { [name: string]: typeof Mongoose$Document },
createConnection(uri?: string, options?: Object): Mongoose$Connection,
set: (key: string, value: string | Function | boolean) => void,
connect: (uri: string, options?: Object) => void,
connect: (uri?: string, options?: Object) => void,
connection: Mongoose$Connection,
connections: Mongoose$Connection[],
Query: typeof Mongoose$Query,
Expand Down
15 changes: 8 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,15 @@
"graphql-compose-pagination": ">=3.3.0"
},
"peerDependencies": {
"graphql-compose": ">=4.0.0",
"graphql-compose": ">=4.7.1",
"mongoose": ">=4.0.0 || >=5.0.0"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-core": "^6.26.3",
"babel-eslint": "^8.2.5",
"babel-jest": "^23.2.0",
"babel-eslint": "^8.2.6",
"babel-jest": "^23.4.0",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-flow-strip-types": "^6.22.0",
"babel-plugin-transform-object-rest-spread": "^6.13.0",
"babel-plugin-transform-runtime": "^6.23.0",
Expand All @@ -56,16 +57,16 @@
"eslint-plugin-prettier": "^2.6.2",
"flow-bin": "^0.76.0",
"graphql": "0.13.2",
"graphql-compose": "^4.4.1",
"graphql-compose": "^4.7.1",
"graphql-compose-connection": ">=3.2.0",
"graphql-compose-pagination": ">=3.3.0",
"jest": "^23.3.0",
"jest": "^23.4.1",
"mongodb-memory-server": "^1.9.0",
"mongoose": "^5.2.2",
"mongoose": "^5.2.3",
"prettier": "^1.13.7",
"request": "^2.87.0",
"rimraf": "^2.6.2",
"semantic-release": "^15.6.3"
"semantic-release": "^15.7.2"
},
"config": {
"commitizen": {
Expand Down
65 changes: 65 additions & 0 deletions src/__mocks__/characterModels.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/* @flow */

import { mongoose, Schema, Types } from './mongooseCommon';
import { DroidSchema } from './droidSchema';
import { PersonSchema } from './personSchema';

const enumCharacterType = {
PERSON: 'Person',
DROID: 'Droid',
};

export const CharacterObject = {
_id: {
type: String,
default: () => new Types.ObjectId(),
},
name: String,

type: {
type: String,
require: true,
enum: (Object.keys(enumCharacterType): Array<string>),
},
kind: {
type: String,
require: true,
enum: (Object.keys(enumCharacterType): Array<string>),
},

friends: [String], // another Character
appearsIn: [String], // movie
};

const CharacterSchema = new Schema(CharacterObject);
const ACharacterSchema = new Schema(Object.assign({}, CharacterObject));

export function getCharacterModels(DKey: string) {
CharacterSchema.set('discriminatorKey', DKey);

const CharacterModel = mongoose.models.Character
? mongoose.models.Character
: mongoose.model('Character', CharacterSchema);

const PersonModel = mongoose.models[enumCharacterType.PERSON]
? mongoose.models[enumCharacterType.PERSON]
: CharacterModel.discriminator(enumCharacterType.PERSON, PersonSchema);

const DroidModel = mongoose.models[enumCharacterType.DROID]
? mongoose.models[enumCharacterType.DROID]
: CharacterModel.discriminator(enumCharacterType.DROID, DroidSchema);

return { CharacterModel, PersonModel, DroidModel };
}

export function getCharacterModelClone() {
const NoDKeyCharacterModel = mongoose.model('NoDKeyCharacter', ACharacterSchema);

/*
const APersonModel = ACharacterModel.discriminator('A' + enumCharacterType.PERSON, PersonSchema.clone());

const ADroidModel = ACharacterModel.discriminator('A' + enumCharacterType.DROID, DroidSchema.clone());
*/

return { NoDKeyCharacterModel }; // APersonModel, ADroidModel };
}
9 changes: 9 additions & 0 deletions src/__mocks__/droidSchema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/* @flow */

import { Schema } from './mongooseCommon';

export const DroidSchema = new Schema({
makeDate: Date,
modelNumber: Number,
primaryFunction: [String],
});
4 changes: 2 additions & 2 deletions src/__mocks__/mongooseCommon.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* @flow */
/* eslint-disable no-param-reassign, no-console */

import mongoose, { Schema } from 'mongoose';
import mongoose, { Schema, Types } from 'mongoose';
import MongodbMemoryServer from 'mongodb-memory-server';

mongoose.Promise = Promise;
Expand Down Expand Up @@ -35,4 +35,4 @@ mongoose.connect = (async () => {
});
}: any);

export { mongoose, Schema };
export { mongoose, Schema, Types };
Loading