Comments (11)
I like the idea of introducing Type safety for the info object. Basically, all the information should already be available, because type definitions are generated for the entire schema, so it should be possible to use a type safe info object from it, which is basically an object for every root field with all it's scalar fields set to boolean.
from prisma-binding.
It would also be helpful to have an object to merge requested fields from the user, with required fields from the system. For example, when running a create
mutation, you need the ID field, but the user may not have requested it
async function resolver (parent, { input }, ctx, info) {
const resp = await ctx.db.mutation.createSite(
{
data: {
name,
},
},
info, // Info is provided by the user
)
// ID will only be available if the user requested it
// but I may want to use the ID
const id = resp.id
return resp
}
from prisma-binding.
@jide sorry, it's my script, I didn't publish it yet.
import {merge} from "lodash";
import {parse} from "graphql";
import {EnumType, VariableType} from "json-to-graphql-query";
export default function graphQLQueryToJson() {
let tree;
let info = arguments[0];
let keepRoot = arguments[1];
let fieldNodes = info && (info.fieldASTs || info.fieldNodes);
// let querySelections = info.operation?.selectionSet?.selections;
if (fieldNodes) {
// (info, keepRoot)
tree = fieldTreeFromAST([...fieldNodes], info.fragments);
if (!keepRoot) {
let key = Object.keys(tree)[0];
tree = tree[key]
}
} else if (typeof info === "string") {
const ast = parse(info);
tree = fieldTreeFromAST(ast.definitions[0].selectionSet.selections);
if (!keepRoot) {
let key = Object.keys(tree)[0];
tree = tree[key]
}
} else {
// (asts, fragments, fieldTree)
tree = fieldTreeFromAST(...arguments)
}
return tree
}
function fieldTreeFromAST (asts, fragments = {}, init = {}) {
asts = asts instanceof Array ? asts : [asts];
return asts.reduce(function (tree, val) {
// console.log(val);
let kind = val.kind;
let name = val.name && val.name.value;
let fragment;
if (kind === 'Field') {
if (val.selectionSet) {
tree[name] = tree[name] || {};
fieldTreeFromAST(val.selectionSet.selections, fragments, tree[name]);
if (val.arguments?.length) {
tree[name].__args = graphQLArgumentsToJson(val.arguments);
}
} else {
tree[name] = true
}
} else if (kind === 'FragmentSpread') {
fragment = fragments[name];
fieldTreeFromAST(fragment.selectionSet.selections, fragments, tree)
} else if (kind === 'InlineFragment') {
fragment = val;
fieldTreeFromAST(fragment.selectionSet.selections, fragments, tree)
} // else ignore
return tree
}, init)
}
function graphQLArgumentsToJson(args) {
let tree = {};
// this will ensure that it is a graphql ast collecton or an array
if (!args.forEach) args = [args];
args.forEach(arg => {
let tmp = [];
let fields = arg.value.fields;
if (!fields) {
tree[arg.name.value] = arg.value.kind === 'EnumValue' ? new EnumType(arg.value.value) : arg.value.value;
} else {
fields.forEach(f => {
if (f.value.fields) {
tree[arg.name.value] = merge(tree[arg.name.value] || {}, graphQLArgumentsToJson(f));
} else {
let value;
switch (f.value.kind) {
case 'Variable':
value = new VariableType(f.value.name.value);
break;
case 'EnumValue':
value = new EnumType(f.value.value);
break;
case 'ListValue':
value = [];
f.value.values.forEach(v => value.push(v.value));
break;
case 'ObjectValue':
value = graphQLArgumentsToJson({value: f});
break;
default:
value = f.value.value;
}
tmp.push({[f.name.value]: value});
tree[arg.name.value] = merge(tree[arg.name.value] || {}, ...tmp);
}
});
}
});
return tree;
}
from prisma-binding.
For this you can use a package: https://github.com/dupski/json-to-graphql-query
But this approach really don't handle lots of issues.
You still will have problems proxying variables or using fragments. Bindings semantics is very limited. It really should accept a GraphQLResolveInfo-like object (or sort of) that will take query/operation, fragments, variableValues. I need a lot of times to alter incoming request. For example to ensure return fields for usage in nested resolvers, or to change some props at query, keeping args and variables in place. Now it is VERY hard to do
from prisma-binding.
@calummoore yes, this is so common case that I don't understand why there is no method for this. I am going to try making sort of ensureSelection
helper, but yet had no time for this
from prisma-binding.
@calummoore I've came along with such thing:
import {graphQLQueryToJson, jsonToGraphQLQuery} from "../graphql/query";
import {merge, head} from "lodash";
import {GraphQLResolveInfo, parse, print, visit, Kind, Source} from "graphql";
export function copyFieldNodes({fieldNodes, operation}) {
return print(fieldNodes)
.map(i => {
const parsedSource = parse(new Source(`${operation.operation} { ${i} }`));
return parsedSource.definitions[0].selectionSet.selections[0];
})
}
export function copyResolverInfo(info: GraphQLResolveInfo, overrides = {}): GraphQLResolveInfo {
return Object.assign({}, info,
{
fieldNodes: copyFieldNodes(info),
fieldName: info.fieldName,
...overrides
}
)
}
export function transformResolverInfoSelection(info: GraphQLResolveInfo, actions: {forceSelection?: string, rootFieldOverride?: string}) {
const {forceSelection, rootFieldOverride} = actions;
const {fieldName} = info;
let resultSelection = graphQLQueryToJson(info, true);
if (forceSelection) {
const requiredSelection = graphQLQueryToJson(`{ ${fieldName} ${forceSelection} }`, true);
resultSelection = merge(resultSelection, requiredSelection);
}
if (rootFieldOverride) {
resultSelection = {[rootFieldOverride]: head(Object.values(resultSelection))};
}
const parsed = parse(`{ ${jsonToGraphQLQuery(resultSelection)} }`);
const infoCopy = copyResolverInfo(info);
infoCopy.fieldNodes[0].selectionSet = parsed.definitions[0].selectionSet.selections[0].selectionSet;
if (rootFieldOverride) {
infoCopy.fieldNodes[0].name.value = rootFieldOverride;
}
return infoCopy;
}
This allows to minimally transform input query (reassign root field, add some selections) to pass down to prisma or other graphql endpoint. Minimal and far from perfect, but something.
But in general query transforms when working graphql-to-graphql are very needed and a library for this should be developed
from prisma-binding.
That would be helpful, not straightforward though! Basically, we need to merge two or more sets of fields together (which would be easiest if we could simply merge JS objects, as per this issue).
As a workaround for now, I am making the initial request with the system fields I require, and then a secondary request for fields the user wants. Not ideal obviously, as that's two round trips to the server.
from prisma-binding.
@terion-name Where does import {graphQLQueryToJson, jsonToGraphQLQuery} from "../graphql/query";
come from ? jsonToGraphQLQuery id probably https://www.npmjs.com/package/json-to-graphql-query but I could not find the opposite.
from prisma-binding.
I'm contemplating using the Prisma typescript bindings as ORM in my backend (non-resolver) code and type safety for the info object would be super useful here.
I second @kbrandwijk's notion of re-using the existing type definitions, when I have a little more time I'll try to wrap my head around a solution.
I feel there's huge potential here to ditch TypeORM, etc. altogether when using Prisma. 😄
Especially the powerful filtering/querying on data from relations is just plain amazing and very cumbersome to do in any of the typical ORMs.
from prisma-binding.
Hey @berstend, that sounds super interesting. We are working on improving exactly this use case, and I would love to hear your input on it. Could you ping me in Slack (my handle is @nilan)? 🙂
from prisma-binding.
Hey 👋, I believe this issue is no longer in sync with the current version of prisma-binding
. In need for gaining a better overview of the issues facing the current version, I'll close it.
Feel free to reopen the issue if you believe we should further discuss its context. 🙂
from prisma-binding.
Related Issues (20)
- how to submit many transactions
- Connect Prisma Bindings to mock server
- Calling a query from Yoga to Prisma does nothing. HOT 5
- Case Sensitive Query Adjustments. HOT 2
- Calling multiple prisma requests returns same error to all the request if any one of them gives error.
- forwardTo() without having to specify resolver keys
- Cannot set property 'fragmentReplacements' of undefined HOT 1
- forwardTo with type rename
- how to get the count of records
- Howto define subscription endpoint
- Sub-selecting custom fields HOT 2
- Subscription Implementation with Prisma Binding
- Improve Code Readability
- error when trying to call aggregate function HOT 1
- Aliases still not works correctly
- How to filter `Where null` HOT 1
- Prisma() not recognized as a constructor HOT 1
- Import error on IResolvers from graphql-tools
- The automated release is failing 🚨
- Version of this for graphql-code-generator ?
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from prisma-binding.