Skip to content

Commit

Permalink
improve express starter, can correctly load models and dataSources
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-burel committed Mar 31, 2022
1 parent c012d51 commit e8d6155
Show file tree
Hide file tree
Showing 11 changed files with 417 additions and 135 deletions.
25 changes: 24 additions & 1 deletion packages/graphql/extendModel.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ import cloneDeep from "lodash/cloneDeep.js";
import isEmpty from "lodash/isEmpty.js";

import merge from "lodash/merge.js";
import { Connector } from "@vulcanjs/crud/server";
import { DataSource } from "apollo-datasource";
/**
* This type is meant to be exposed server side
*  @server-only
Expand All @@ -49,6 +51,19 @@ export interface GraphqlModelOptionsServer extends GraphqlModelOptions {
/** Custom mutation resolvers (create, update, delete). Set to "null" if you don't want Vulcan to set any resolvers. Leave undefined if you want to use default resolvers. */
mutationResolvers?: Partial<MutationResolverDefinitions> | null;
callbacks?: MutationCallbackDefinitions;
/**
* Create a database connector. As a default, Vulcan Next will setup a Mongoose connector
* but it's better to set it explicitely.
*
* NOTE: we can't pass the connector directly, because it usually depends on the model itself
*/
createConnector?: (self: VulcanGraphqlModelServer) => Connector;
/**
* Create a data source creator (/!\ it must be a closure)
*/
makeCreateDataSource?: (
self: VulcanGraphqlModelServer
) => () => DataSource | undefined;
}

/**
Expand Down Expand Up @@ -118,6 +133,7 @@ export const extendModelServer =
const {
mutationResolvers: mutationResolversFromOptions,
queryResolvers: queryResolversFromOptions,
createConnector,
} = options;
let mutationResolvers = mutationResolversFromOptions,
queryResolvers = queryResolversFromOptions;
Expand All @@ -142,8 +158,15 @@ export const extendModelServer =
mutationResolvers: mutationResolvers ? mutationResolvers : undefined,
queryResolvers: queryResolvers ? queryResolvers : undefined,
};

/** Generate the model schema */
finalModel.schema = extendSchemaServer(finalModel.schema);
const name = model.name;

/** Final step: generate the connector if possible*/
if (createConnector) {
finalModel.graphql.connector = createConnector(finalModel);
}

return finalModel;
};

Expand Down
24 changes: 1 addition & 23 deletions packages/mongo-apollo/addDefaultMongoConnector.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,6 @@
import { VulcanGraphqlModelServer } from "@vulcanjs/graphql/server";
import { createMongooseConnector } from "@vulcanjs/mongo";
import type { Connector } from "@vulcanjs/crud/server";
import { MongoDataSource } from "apollo-datasource-mongodb";
import type { Model } from "mongoose";
/**
* Create a mongoose data source
* @param model
* @param connector
* @returns
*/
const createMongooseDataSource = (
model: VulcanGraphqlModelServer,
connector: Connector
) => {
const rawCollection = connector.getRawCollection();
if (!rawCollection) {
console.warn(`Model ${model.name} has no rawCollection in its connector. If it is not a Mongoose model, please
manually provide a dataSource in model.graphql options.`);
return undefined;
}
// TODO: check that it's a mongoose model?
const mongooseModel = rawCollection as unknown as Model<any>;
return new MongoDataSource(mongooseModel);
};
import { createMongooseDataSource } from "./createMongooseDataSource";

/**
* Add default Mongo connector and dataSource to models
Expand Down
25 changes: 25 additions & 0 deletions packages/mongo-apollo/createMongooseDataSource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { VulcanGraphqlModelServer } from "@vulcanjs/graphql/server";
import type { Connector } from "@vulcanjs/crud/server";
import { MongoDataSource } from "apollo-datasource-mongodb";
import type { Model } from "mongoose";

/**
* Create a mongoose data source
* @param model
* @param connector
* @returns
*/
export const createMongooseDataSource = (
model: VulcanGraphqlModelServer,
connector: Connector
) => {
const rawCollection = connector.getRawCollection();
if (!rawCollection) {
console.warn(`Model ${model.name} has no rawCollection in its connector. If it is not a Mongoose model, please
manually provide a dataSource in model.graphql options.`);
return undefined;
}
// TODO: check that it's a mongoose model?
const mongooseModel = rawCollection as unknown as Model<any>;
return new MongoDataSource(mongooseModel);
};
1 change: 1 addition & 0 deletions packages/mongo-apollo/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./addDefaultMongoConnector";
export * from "./createMongooseDataSource";
206 changes: 206 additions & 0 deletions packages/schema/simpleSchemaSimplifiedTypings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
/**
* Vulcan do not use all features of simpl-schema anymore,
* only a simplified version
*/

type Integer = RegExp;

type SchemaType =
| String
| Number
| Integer
| Boolean
| Object
| ArrayLike<any>
| SchemaDefinition<any>
| Date;
//| SimpleSchema
//| SimpleSchemaGroup;

type SimpleSchemaGroup = { definitions: ArrayLike<{ type: SchemaType }> };

interface CleanOption {
filter?: boolean;
autoConvert?: boolean;
removeEmptyStrings?: boolean;
trimStrings?: boolean;
getAutoValues?: boolean;
isModifier?: boolean;
extendAutoValueContext?: boolean;
}

export type AutoValueFunctionSelf<T> = {
key: string;
closestSubschemaFieldName: string | null;
isSet: boolean;
unset: () => void;
value: T; // | Mongo.Modifier<T>;
operator: string;
field(otherField: string): {
isSet: boolean;
value: any;
operator: string;
};
siblingField(otherField: string): {
isSet: boolean;
value: any;
operator: string;
};
parentField(otherField: string): {
isSet: boolean;
value: any;
operator: string;
};
};

type ValidationError = {
name: string;
type: string;
value: any;
};

type AutoValueFunction<T> = (this: AutoValueFunctionSelf<T>) => T | undefined;

interface ValidationFunctionSelf<T> {
value: T;
key: string;
genericKey: string;
definition: SchemaDefinition<T>;
isSet: boolean;
operator: any;
//validationContext: ValidationContext;
field: (fieldName: string) => any;
siblingField: (fieldName: string) => any;
addValidationErrors: (errors: ValidationError[]) => {};
}

type ValidationFunction = (
this: ValidationFunctionSelf<any>
) => string | undefined;

export interface SchemaDefinition<T> {
type: SchemaType;
label?: string; // | Function;
optional?: boolean; // | Function;
min?: number | boolean | Date; // | Function;
max?: number | boolean | Date; // | Function;
minCount?: number; // | Function;
maxCount?: number; // | Function;
allowedValues?: any[]; // | Function;
decimal?: boolean;
exclusiveMax?: boolean;
exclusiveMin?: boolean;
regEx?: RegExp | RegExp[];
custom?: ValidationFunction;
blackbox?: boolean;
autoValue?: AutoValueFunction<T>;
defaultValue?: any;
trim?: boolean;

// allow custom extensions
[key: string]: any;
}

export interface EvaluatedSchemaDefinition {
type: ArrayLike<{ type: SchemaType }>;
label?: string;
optional?: boolean;
min?: number | boolean | Date;
max?: number | boolean | Date;
minCount?: number;
maxCount?: number;
allowedValues?: any[];
decimal?: boolean;
exclusiveMax?: boolean;
exclusiveMin?: boolean;
regEx?: RegExp | RegExp[];
blackbox?: boolean;
defaultValue?: any;
trim?: boolean;

// allow custom extensions
[key: string]: any;
}

interface ValidationOption {
modifier?: boolean;
upsert?: boolean;
clean?: boolean;
filter?: boolean;
upsertextendedCustomContext?: boolean;
extendedCustomContext: any;
}

interface SimpleSchemaValidationContext {
validate(obj: any, options?: ValidationOption): boolean;

validateOne(doc: any, keyName: string, options?: ValidationOption): boolean;

resetValidation(): void;

isValid(): boolean;

invalidKeys(): { name: string; type: string; value?: any }[];

addInvalidKeys(errors: ValidationError[]): void;

keyIsInvalid(name: any): boolean;

keyErrorMessage(name: any): string;

getErrorObject(): any;

validationErrors(): Array<{ type?: string; name?: string }>;
}

interface MongoObjectStatic {
forEachNode(func: Function, options?: { endPointsOnly: boolean }): void;

getValueForPosition(position: string): any;

setValueForPosition(position: string, value: any): void;

removeValueForPosition(position: string): void;

getKeyForPosition(position: string): any;

getGenericKeyForPosition(position: string): any;

getInfoForKey(key: string): any;

getPositionForKey(key: string): string;

getPositionsForGenericKey(key: string): string[];

getValueForKey(key: string): any;

addKey(key: string, val: any, op: string): any;

removeGenericKeys(keys: string[]): void;

removeGenericKey(key: string): void;

removeKey(key: string): void;

removeKeys(keys: string[]): void;

filterGenericKeys(test: Function): void;

setValueForKey(key: string, val: any): void;

setValueForGenericKey(key: string, val: any): void;

getObject(): any;

getFlatObject(options?: { keepArrays?: boolean }): any;

affectsKey(key: string): any;

affectsGenericKey(key: string): any;

affectsGenericKeyImplicit(key: string): any;
}

interface MongoObject {
expandKey(val: any, key: string, obj: any): void;
}
2 changes: 1 addition & 1 deletion packages/schema/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
"compilerOptions": {
"outDir": "./dist"
},
}
}
3 changes: 2 additions & 1 deletion packages/schema/typings/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
* When calling SimpleSchema(schema), you get an EvaluatedSchemaDefinition. We do not
* use them in Vulcan core anymore.
*/
import { SchemaDefinition /*, EvaluatedSchemaDefinition*/ } from "simpl-schema";
//import { SchemaDefinition /*, EvaluatedSchemaDefinition*/ } from "simpl-schema";
import type { SchemaDefinition } from "../simpleSchemaSimplifiedTypings";
import { VulcanFieldInput } from "./form";

export type FieldTypeName =
Expand Down

0 comments on commit e8d6155

Please sign in to comment.