Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit bb60157
Showing
13 changed files
with
7,745 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
/node_modules | ||
/yarn-error.log | ||
/lib | ||
/src/docs/.next | ||
/public |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
tabWidth: 4 | ||
arrowParens: avoid | ||
trailingComma: all | ||
printWidth: 120 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
-/node_modules | ||
-/examples/*/node_modules | ||
-/lib |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
{ | ||
"name": "greldal", | ||
"version": "0.3.0", | ||
"description": "A simple micro-framework to expose your relational datastore as a GraphQL API (powered by Node.js).", | ||
"homepage": "https://lorefnon.gitlab.io/greldal", | ||
"bugs": "https://gitlab.com/lorefnon/greldal/issues", | ||
"main": "lib/index.js", | ||
"umd:main": "lib/index.umd.js", | ||
"module": "lib/index.mjs", | ||
"source": "src/index.ts", | ||
"repository": "https://gitlab.com/lorefnon/greldal", | ||
"author": "lorefnon <lorefnon@gmail.com> (https://lorefnon.tech)", | ||
"license": "MIT", | ||
"private": false, | ||
"files": [ | ||
"lib" | ||
], | ||
"scripts": { | ||
"prebuild": "rimraf lib", | ||
"format": "prettier --write \"src/**/*.ts\"", | ||
"build:tsc": "tsc", | ||
"build:docs": "yarn run build:docs:site && yarn run build:docs:api", | ||
"build:docs:api": "typedoc --out ./public/api --ignoreCompilerErrors --exclude ./src/__specs__ ./src", | ||
"build:docs:site": "node scripts/generate-docs.js", | ||
"build": "yarn run build:tsc && yarn run build:docs", | ||
"test": "jest", | ||
"test:watch": "jest --watch", | ||
"test:prod": "yarn run lint && yarn run test -- --no-cache", | ||
"docs:dev-server": "next src/docs" | ||
}, | ||
"jest": { | ||
"transform": { | ||
".(ts|tsx)": "ts-jest" | ||
}, | ||
"testEnvironment": "node", | ||
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$", | ||
"moduleFileExtensions": [ | ||
"ts", | ||
"tsx", | ||
"js" | ||
], | ||
"coveragePathIgnorePatterns": [ | ||
"/node_modules/", | ||
"/test/" | ||
], | ||
"coverageThreshold": { | ||
"global": { | ||
"branches": 90, | ||
"functions": 95, | ||
"lines": 95, | ||
"statements": 95 | ||
} | ||
}, | ||
"collectCoverage": false | ||
}, | ||
"devDependencies": { | ||
"@react-pdf/renderer": "^1.0.0-alpha.25", | ||
"@types/debug": "^0.0.31", | ||
"@types/graphql": "^14.0.3", | ||
"@types/graphql-iso-date": "^3.3.1", | ||
"@types/inflection": "^1.5.28", | ||
"@types/jest": "^23.3.10", | ||
"@types/knex": "^0.15.0", | ||
"@types/lodash": "^4.14.118", | ||
"@types/rimraf": "^2.0.2", | ||
"@zeit/next-css": "^1.0.1", | ||
"@zeit/next-mdx": "^1.2.0", | ||
"cli-glob": "^0.1.0", | ||
"cross-env": "^5.2.0", | ||
"file-loader": "^2.0.0", | ||
"graphql": "^14.0.2", | ||
"jest": "^23.6.0", | ||
"knex": "^0.15.2", | ||
"mdx-table-of-contents": "^0.1.0", | ||
"next": "^7.0.2", | ||
"normalize.css": "^8.0.1", | ||
"prettier": "^1.15.2", | ||
"react": "^16.6.3", | ||
"react-dom": "^16.6.3", | ||
"reflect-metadata": "^0.1.12", | ||
"remark-autolink-headings": "^5.0.0", | ||
"remark-emoji": "^2.0.2", | ||
"remark-highlight.js": "^5.0.0", | ||
"remark-html": "^9.0.0", | ||
"remark-html-emoji-image": "^1.0.0", | ||
"remark-mermaid": "^0.2.0", | ||
"remark-slug": "^5.1.1", | ||
"rimraf": "^2.6.2", | ||
"shelljs": "^0.8.3", | ||
"sqlite3": "^4.0.3", | ||
"ts-jest": "^23.10.5", | ||
"typedoc": "^0.13.0", | ||
"typescript": "^3.2.2" | ||
}, | ||
"dependencies": { | ||
"core-decorators": "^0.20.0", | ||
"debug": "^4.1.0", | ||
"graphql-iso-date": "^3.6.1", | ||
"graphql-parse-resolve-info": "^4.0.0", | ||
"graphql-type-uuid": "^0.2.0", | ||
"inflection": "^1.12.0", | ||
"io-ts": "^1.5.0", | ||
"lodash": "^4.17.11", | ||
"lodash-decorators": "^6.0.0" | ||
}, | ||
"peerDependencies": { | ||
"knex": "^0.15.2" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { DataSourceMapping, MappedDataSource } from "./MappedDataSource"; | ||
|
||
export interface AssociationMapping<T extends DataSourceMapping> { | ||
from: () => MappedDataSource<T>; | ||
join: any; | ||
preFetch: any; | ||
postFetch: any; | ||
reverseAssociateWithParents: any; | ||
} | ||
|
||
export class MappedAssociation<T extends AssociationMapping<any>> { | ||
constructor(private mapping: T) {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import {dataSource} from "./MappedDataSource"; | ||
|
||
test("name mapping", () => { | ||
const user = dataSource({ | ||
name: "User" | ||
}); | ||
expect(user.storedName).toEqual("users"); | ||
expect(user.mappedName).toEqual("User"); | ||
const productDetails = dataSource({ | ||
name: "productDetails" | ||
}); | ||
expect(productDetails.storedName).toEqual("product_details"); | ||
expect(productDetails.mappedName).toEqual("ProductDetail"); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { getTypeAccessorError } from "./errors"; | ||
import { Memoize } from "lodash-decorators"; | ||
import { Mapped, TypeGuard, Dict, MaybeMapped, MaybeArray, NNil } from "./util-types"; | ||
import { isString, transform, camelCase, upperFirst, snakeCase } from "lodash"; | ||
import * as t from "io-ts"; | ||
import { GraphQLInputType, GraphQLOutputType } from "graphql"; | ||
import { FieldMapping, MappedField } from "./MappedField"; | ||
import { AssociationMapping, MappedAssociation } from "./MappedAssociation"; | ||
import { singularize, pluralize } from "inflection"; | ||
|
||
export interface DataSourceMapping { | ||
name: MaybeMapped<string>; | ||
description?: string; | ||
fields?: Dict<FieldMapping<any, any>> | ||
associations?: Dict<AssociationMapping<any>> | ||
} | ||
|
||
type ShallowRecordType<T extends DataSourceMapping> = { | ||
[K in keyof T["fields"]]: t.TypeOf<NNil<T["fields"]>[K]["type"]> | ||
} | ||
|
||
type NestedRecordType<T extends DataSourceMapping> = ShallowRecordType<T> & { | ||
[K in keyof T["associations"]]: ReturnType<NNil<T["associations"]>[K]["from"]>["NestedRecordType"] | ||
} | ||
|
||
export class MappedDataSource<T extends DataSourceMapping> { | ||
fields: {[K in keyof T["fields"]]: MappedField<NNil<T["fields"]>[K]>}; | ||
associations: {[K in keyof T["associations"]]: MappedAssociation<NNil<T["associations"]>[K]>}; | ||
|
||
constructor(private mapping: T) { | ||
this.fields = transform(mapping.fields!, (result, fieldMapping, name) => { | ||
result[name] = new MappedField(fieldMapping); | ||
}, {}) as any; | ||
this.associations = transform(mapping.associations!, (result, associationMapping, name) => { | ||
result[name] = new MappedAssociation(associationMapping); | ||
}, {}) as any; | ||
} | ||
|
||
@Memoize | ||
get mappedName() { | ||
return (isString as TypeGuard<string>)(this.mapping.name) | ||
? upperFirst(camelCase(singularize(this.mapping.name))) | ||
: this.mapping.name.mapped; | ||
} | ||
|
||
@Memoize | ||
get storedName() { | ||
return (isString as TypeGuard<string>)(this.mapping.name) | ||
? snakeCase(pluralize(this.mapping.name)) | ||
: this.mapping.name.stored; | ||
} | ||
|
||
get ShallowRecordType(): ShallowRecordType<T> { | ||
throw getTypeAccessorError('ShallowRecordType', 'MappedDataSource'); | ||
} | ||
|
||
get NestedRecordType(): NestedRecordType<T> { | ||
throw getTypeAccessorError('NestedRecordType', 'MappedDataSource'); | ||
} | ||
} | ||
|
||
export const dataSource = <T extends DataSourceMapping> (mapping: T) => new MappedDataSource<T>(mapping); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import * as t from "io-ts"; | ||
import { MaybeArray } from "./util-types"; | ||
import { GraphQLInputType, GraphQLOutputType } from "graphql"; | ||
import { getTypeAccessorError } from "./errors"; | ||
|
||
export interface FieldMapping<TMapped extends t.Type<any>, TArgs extends {}> { | ||
type: TMapped; | ||
from?: MaybeArray<keyof TArgs>; | ||
to?: { | ||
input: GraphQLInputType, | ||
output: GraphQLOutputType | ||
}; | ||
description?: string; | ||
derive?: (args: TArgs) => t.TypeOf<TMapped>; | ||
} | ||
|
||
export class MappedField<T extends FieldMapping<any, any>> { | ||
constructor(private mapping: T) { | ||
} | ||
get Type(): t.TypeOf<T["type"]> { | ||
throw getTypeAccessorError('Type', 'MappedField'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export const getTypeAccessorError = (name: string, parent: string) => new Error( | ||
`Property ${name} must not be accessed directly. ` + | ||
`Use typeof ${parent}Instance.${name} to get the ${name} type for this ${parent}` | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import * as Knex from "knex"; | ||
import { Maybe } from "./util-types"; | ||
|
||
export interface QBFactory { | ||
(alias: Maybe<string>): Knex.QueryBuilder; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { Dictionary, Omit } from "lodash"; | ||
|
||
/** Convenience utility types */ | ||
|
||
export type Maybe<T> = null | undefined | T; | ||
|
||
export type NNil<T> = Exclude<T, undefined | null>; | ||
|
||
export interface Dict<T = any> extends Dictionary<T> {} | ||
|
||
export interface Lazy<T> { | ||
(): T; | ||
} | ||
|
||
export type MaybeLazy<T> = T | Lazy<T>; | ||
export type MaybeArray<T> = T | T[]; | ||
|
||
export interface Factory<T> { | ||
(...args: any[]): T; | ||
} | ||
|
||
export interface Newable<T> { | ||
new (...args: any[]): T; | ||
} | ||
|
||
export type StrKey<T> = keyof T & string; | ||
export type IdxKey<T> = keyof T & number; | ||
|
||
export type Normalizer<PreNormalizedT, NormalizedT> = (v: PreNormalizedT) => NormalizedT; | ||
|
||
export type MandateProps<T, P extends keyof T> = Omit<T, P> & { [K in keyof Pick<T, P>]-?: T[K] }; | ||
|
||
export type ReturnType<T extends (...args: any[]) => any> = T extends (...args: any[]) => infer R ? R : any; | ||
|
||
export type Fn<A extends any[] = any[], R = any> = (...args: A) => R; | ||
|
||
export type TypeGuard<S> = (v: any) => v is S; | ||
|
||
export type Omit<T, K> = Pick<T, Exclude<keyof T, K>>; | ||
|
||
export type ReplaceWith<TSource, TKey, TSub = never> = { | ||
[K in keyof TSource]: K extends TKey ? TSub : TSource[K]; | ||
} | ||
|
||
export interface Mapped<TMapped, TStored = TMapped> { | ||
mapped: TMapped, | ||
stored: TStored | ||
} | ||
|
||
export type MaybeMapped<T> = T | Mapped<T>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
{ | ||
"compilerOptions": { | ||
"moduleResolution": "node", | ||
"target": "es6", | ||
"module": "commonjs", | ||
"lib": ["es2015", "es2016", "es2017", "dom", "esnext.asynciterable"], | ||
"strict": true, | ||
"sourceMap": true, | ||
"declaration": true, | ||
"allowSyntheticDefaultImports": true, | ||
"experimentalDecorators": true, | ||
"emitDecoratorMetadata": true, | ||
"declarationDir": "lib", | ||
"outDir": "lib", | ||
"esModuleInterop": true, | ||
"typeRoots": [ | ||
"node_modules/@types" | ||
] | ||
}, | ||
"include": [ | ||
"src" | ||
], | ||
"exclude": [ | ||
"src/__fixtures__/**/*", | ||
"src/__snapshots__/**/*" | ||
] | ||
} |
Oops, something went wrong.