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

break: Simplify context, add execute function #39

Merged
merged 3 commits into from
Aug 23, 2023
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
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,52 @@

Welcome to graphql-magic!

## Usage

### Prerequisites

* Next.js
* TypeScript
* Knex.js
* Postgresql

### Setup

Dependencies:

```
npm i @smartive/graphql-magic
```

Dev Dependencies:

```
npm i -D @graphql-codegen/add @graphql-codegen/cli @graphql-codegen/schema-ast @graphql-codegen/typescript @graphql-codegen/typescript-compatibility @graphql-codegen/typescript-operations @graphql-codegen/typescript-resolvers simple-git
```

Create and add the following files:

* `src/generated/api/.gitkeep`
* `src/generated/client/.gitkeep`
* `src/generated/client/.gitkeep`

Add the following scripts to your package:

```
"gqm:local": "(cd ../graphql-magic && npm run build && npm pack) && npm i ../graphql-magic/smartive-graphql-magic-0.0.0-development.tgz",
"gqm:upgrade": "npm rm @smartive/graphql-magic && npm i @smartive/graphql-magic",
"generate": "npm run generate:db && npm run generate:graphql:schema && npm run generate:graphql:api && npm run generate:graphql:client",
"generate:db": "npm run ts-node scripts/generate-db-models",
"generate:graphql:schema": "npm run ts-node scripts/generate-schema",
"generate:graphql:api": "graphql-codegen --config graphql-codegen.yml",
"generate:graphql:client": "graphql-codegen --config client-codegen.yml",
"db:migrate:generate": "npm run ts-node scripts/generate-migrations",
```

To be continued...

## Development

```
npm bootstrap
```
Expand Down
45 changes: 45 additions & 0 deletions src/api/execute.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { makeExecutableSchema } from '@graphql-tools/schema';
import { IResolvers } from '@graphql-tools/utils';
import { GraphQLResolveInfo, Source, execute as graphqlExecute, parse } from 'graphql';
import { Context, generate, get, getResolvers } from '..';

export const execute = async ({
additionalResolvers,
body,
...ctx
}: {
additionalResolvers?: IResolvers<any, any>;
body: any;
} & Omit<Context, 'document'>) => {
const document = generate(ctx.rawModels);

const generatedResolvers = getResolvers(ctx.models);

const schema = makeExecutableSchema({
typeDefs: document,
resolvers: {
...generatedResolvers,
...additionalResolvers,
},
});

const contextValue: Context = {
document,
...ctx,
};

const result = await graphqlExecute({
schema,
document: parse(new Source(body.query, 'GraphQL request')),
contextValue,
variableValues: body.variables,
operationName: body.operationName,
fieldResolver: (parent, _args, _ctx, info: GraphQLResolveInfo) => {
const node = get(info.fieldNodes, 0);
const alias = node.alias;
return parent[alias ? alias.value : node.name.value];
},
});

return result;
};
3 changes: 3 additions & 0 deletions src/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// created from 'create-ts-index'

export * from './execute';
4 changes: 2 additions & 2 deletions src/client/queries.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import upperFirst from 'lodash/upperFirst';
import { Field } from '..';
import { Model, Models, Relation, ReverseRelation } from '../models';
import { Model, Models, Relation, ReverseRelation } from '../models/models';
import {
actionableRelations,
and,
Expand All @@ -14,7 +14,7 @@ import {
not,
summonByName,
typeToField,
} from '../utils';
} from '../models/utils';

export const getUpdateEntityQuery = (
model: Model,
Expand Down
4 changes: 1 addition & 3 deletions src/context.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import { DocumentNode, GraphQLResolveInfo } from 'graphql';
import { IncomingMessage } from 'http';
import { Knex } from 'knex';
import { DateTime } from 'luxon';
import { Entity, Models, MutationHook, RawModels } from './models';
import { Entity, Models, MutationHook, RawModels } from './models/models';
import { Permissions } from './permissions/generate';
import { AliasGenerator } from './resolvers/utils';

// Minimal user structure required by graphql-magic
export type User = { id: string; role: string };

export type Context = {
req: IncomingMessage;
now: DateTime;
knex: Knex;
document: DocumentNode;
Expand Down
4 changes: 2 additions & 2 deletions src/generate/generate.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { buildASTSchema, DefinitionNode, DocumentNode, GraphQLSchema, print } from 'graphql';
import flatMap from 'lodash/flatMap';
import { RawModels } from '../models';
import { RawModels } from '../models/models';
import {
getModelPluralField,
getModels,
Expand All @@ -11,7 +11,7 @@ import {
isRelation,
isScalarModel,
typeToField,
} from '../utils';
} from '../models/utils';
import { document, enm, Field, input, object, scalar } from './utils';

export const generateDefinitions = (rawModels: RawModels): DefinitionNode[] => {
Expand Down
2 changes: 1 addition & 1 deletion src/generate/mutations.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import upperCase from 'lodash/upperCase';
import { Models } from '../models';
import { Models } from '../models/models';

const constantCase = (str: string) => upperCase(str).replace(/ /g, '_');

Expand Down
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// created from 'create-ts-index'

export * from './api';
export * from './client';
export * from './db';
export * from './generate';
export * from './migrations';
export * from './models';
export * from './permissions';
export * from './resolvers';
export * from './context';
export * from './errors';
export * from './models';
export * from './utils';
export * from './values';
4 changes: 2 additions & 2 deletions src/migrations/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { SchemaInspector } from 'knex-schema-inspector';
import { Column } from 'knex-schema-inspector/dist/types/column';
import { SchemaInspector as SchemaInspectorType } from 'knex-schema-inspector/dist/types/schema-inspector';
import lowerFirst from 'lodash/lowerFirst';
import { EnumModel, Model, ModelField, Models, RawModels } from '../models';
import { get, getModels, isEnumModel, summonByName, typeToField } from '../utils';
import { EnumModel, Model, ModelField, Models, RawModels } from '../models/models';
import { get, getModels, isEnumModel, summonByName, typeToField } from '../models/utils';
import { Value } from '../values';

type Callbacks = (() => void)[];
Expand Down
4 changes: 4 additions & 0 deletions src/models/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// created from 'create-ts-index'

export * from './models';
export * from './utils';
8 changes: 4 additions & 4 deletions src/models.ts → src/models/models.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { DateTime } from 'luxon';
import { Field } from '.';
import type { Context } from './context';
import type { OrderBy } from './resolvers/arguments';
import type { Value } from './values';
import { Field } from '..';
import type { Context } from '../context';
import type { OrderBy } from '../resolvers/arguments';
import type { Value } from '../values';

export type RawModels = RawModel[];

Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions src/permissions/check.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Knex } from 'knex';
import { FullContext } from '../context';
import { NotFoundError, PermissionError } from '../errors';
import { Model } from '../models';
import { Model } from '../models/models';
import { get, getModelPlural, isRelation, summonByName } from '../models/utils';
import { AliasGenerator, hash, ors } from '../resolvers/utils';
import { get, getModelPlural, isRelation, summonByName } from '../utils';
import { BasicValue } from '../values';
import { PermissionAction, PermissionLink, PermissionStack } from './generate';

Expand Down
4 changes: 2 additions & 2 deletions src/permissions/generate.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Models } from '../models';
import { isRelation, summonByName } from '../utils';
import { Models } from '../models/models';
import { isRelation, summonByName } from '../models/utils';

export type PermissionAction = 'READ' | 'CREATE' | 'UPDATE' | 'DELETE' | 'RESTORE' | 'LINK';

Expand Down
2 changes: 1 addition & 1 deletion src/resolvers/arguments.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { GraphQLObjectType, GraphQLSchema, TypeDefinitionNode, TypeNode, ValueNode } from 'graphql';
import { Kind } from 'graphql';
import { summonByKey } from '../utils';
import { summonByKey } from '../models/utils';
import { Value } from '../values';
import { FieldResolverNode } from './node';
import { Maybe, VariableValues } from './utils';
Expand Down
2 changes: 1 addition & 1 deletion src/resolvers/filters.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Knex } from 'knex';
import { ForbiddenError, UserInputError } from '../errors';
import { get, summonByName } from '../utils';
import { get, summonByName } from '../models/utils';
import { OrderBy, Where, normalizeArguments } from './arguments';
import { FieldResolverNode, WhereNode } from './node';
import { Joins, Ops, addJoin, apply, ors } from './utils';
Expand Down
4 changes: 2 additions & 2 deletions src/resolvers/mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { DateTime } from 'luxon';
import { v4 as uuid } from 'uuid';
import { Context, FullContext } from '../context';
import { ForbiddenError, GraphQLError } from '../errors';
import { Entity, Model, ModelField } from '../models';
import { Entity, Model, ModelField } from '../models/models';
import { get, isEnumList, it, summonByName, typeToField } from '../models/utils';
import { applyPermissions, checkCanWrite, getEntityToMutate } from '../permissions/check';
import { get, isEnumList, it, summonByName, typeToField } from '../utils';
import { resolve } from './resolver';
import { AliasGenerator } from './utils';

Expand Down
4 changes: 2 additions & 2 deletions src/resolvers/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import type {
} from 'graphql';

import { FullContext } from '../context';
import { Model } from '../models';
import { get, isRawObjectModel, summonByKey, summonByName } from '../utils';
import { Model } from '../models/models';
import { get, isRawObjectModel, summonByKey, summonByName } from '../models/utils';
import {
getFragmentTypeName,
getNameOrAlias,
Expand Down
2 changes: 1 addition & 1 deletion src/resolvers/resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import cloneDeep from 'lodash/cloneDeep';
import flatMap from 'lodash/flatMap';
import { Context, FullContext } from '../context';
import { NotFoundError, PermissionError } from '../errors';
import { get, summonByKey } from '../models/utils';
import { applyPermissions } from '../permissions/check';
import { PermissionStack } from '../permissions/generate';
import { get, summonByKey } from '../utils';
import { applyFilters } from './filters';
import {
FieldResolverNode,
Expand Down
4 changes: 2 additions & 2 deletions src/resolvers/resolvers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Models } from '../models';
import { getModelPluralField, merge, typeToField } from '../utils';
import { Models } from '../models/models';
import { getModelPluralField, merge, typeToField } from '../models/utils';
import { mutationResolver } from './mutations';
import { queryResolver } from './resolver';

Expand Down
2 changes: 1 addition & 1 deletion src/resolvers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type {
import { Kind } from 'graphql';
import { Knex } from 'knex';
import { UserInputError } from '../errors';
import { get, it } from '../utils';
import { get, it } from '../models/utils';
import { Value } from '../values';
import { FieldResolverNode } from './node';

Expand Down
23 changes: 4 additions & 19 deletions tests/unit/resolve.spec.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import { makeExecutableSchema } from '@graphql-tools/schema';
import { execute, parse, Source } from 'graphql';
import knex from 'knex';
import { DateTime } from 'luxon';
import { execute } from '../../src';
import { gql } from '../../src/client/gql';
import { Context } from '../../src/context';
import { generate } from '../../src/generate';
import { getResolvers } from '../../src/resolvers';
import { models, permissions, rawModels } from '../utils/models';

const test = async (operationName: string, query: string, variableValues: object, responses: unknown[]) => {
const test = async (operationName: string, query: string, variables: object, responses: unknown[]) => {
const knexInstance = knex({
client: 'postgresql',
});
Expand All @@ -25,28 +22,16 @@ const test = async (operationName: string, query: string, variableValues: object
});

const user = await knexInstance('User').where({ id: 1 }).first();
const typeDefs = generate(rawModels);
const contextValue: Context = {
req: null as any,
const result = await execute({
knex: knexInstance,
document: typeDefs,
locale: 'en',
locales: ['en'],
user,
rawModels,
models,
permissions,
now: DateTime.fromISO('2020-01-01T00:00:00.000Z'),
};
const result = await execute({
schema: makeExecutableSchema({
typeDefs,
resolvers: getResolvers(models),
}),
document: parse(new Source(query, 'GraphQL request')),
contextValue,
variableValues,
operationName,
body: { operationName, query, variables }
});

expect(result).toMatchSnapshot();
Expand Down
2 changes: 1 addition & 1 deletion tests/utils/models.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { RawModels } from '../../src/models';
import { getModels } from '../../src/models/utils';
import { generatePermissions, PermissionsConfig } from '../../src/permissions/generate';
import { getModels } from '../../src/utils';

export const rawModels: RawModels = [
{
Expand Down
Loading