Comments (12)
Hey bro, just wanted to let you know I got derailed from my project and only now got back to it, and the eject method is working awesome!!! thank you SO much this lib is da best :) <3
from typeorm-graphql-loader.
Thanks! I'm happy that it has been working for you.
Regarding the hashed table aliases, this was implemented to prevent SQL errors from the loader-generated aliases becoming too long. For reference, see this issue. At some point I would like to revisit the alias generation to see if there is a way to make it more deterministic for cases like this, but for now, you should be able to use the TypeORM Brackets
syntax for the where
clauses. The Bracket gives you access to the loader's internal TypeORM QueryBuilder it is using to resolve the requested GraphQL data, which you can use to specify your own joins with a custom alias.
Essentially, your loader call could look something like this:
function itemsByCategoryNameResolver(obj, args, context, info) {
return context.loader
.loadEntity(Item, 'item')
.info(info)
.where(new Brackets(qb => {
qb.innerJoin("item.category", "category")
qb.where("category.name = :name", { name: args.name })
})
.loadMany()
}
When performing joins inside the Bracket, I would make sure you are joining without selection. This will make TypeORM more performant since the loader is already selecting the data needed to resolve the query.
A word of warning, using the Brackets is basically ejecting you from the loader wrapper and allowing you to manipulate the generated query yourself. Be aware that doing so may not always play nice with some of the things the loader is doing internally. For a simple things like adding additional where clauses, etc, it isn't a problem, but if you plan on using it to inject complex resolution logic, you are probably better off just using a custom resolver written in the native TypeORM query builder.
Unfortunately, the built in search helper only works on the top level entity, but you should be able to just build your own using a custom where clause and Brackets.
from typeorm-graphql-loader.
hey @Mando75 thanks for the amazingly quick and detailed response!!
I went ahead to implement those brackets, and discovered that innerJoin / where functions don't exist for "qb" (which is of type whereExpression
) and instead I have these functions:
maybe we have different versions of typeorm? I'm using 0.2.26
from typeorm-graphql-loader.
I looked at the TypeORM types and you are correct, apparently that doesn't work anymore. Sorry about that! With this being the case, there is currently no good way to accomplish what you are describing, which I am not satisfied with as this is a pretty common use case. I'll need to check to see what alternatives TypeORM offers in terms of subqueries and see if I can make that compatible with the loader.
Just a heads up, I am moving about 2050km across the country this week, so I won't have a lot of time to dedicate to providing a solution to this until I am settled into my new place (hopefully by the end of next week). I appreciate your patience with that delay, and I'll be sure to address this as soon as I can.
from typeorm-graphql-loader.
congrats on the move, and thank you so much for the work and dedication. not an obvious thing <3
I've been all over the place with typeorm docs, maybe there's a way with union or something with SelectQueryBuilder?? I don't know, guess you have much more experience with it. if you happen to fix it and remember me, drop a note here... thanks again and enjoy the 2050km (!!!) ride :)
from typeorm-graphql-loader.
Thanks!
I'm thinking that the best way to deal with this would be for the loader to expose the full query builder in the form of a callback that you can use to eject at db query resolve time. That should provide a fix this issue while still remaining compatible with any future TypeORM changes.
An example of what I will try and implement
function itemsByCategoryNameResolver(obj, args, context, info) {
return context.loader
.loadEntity(Item, 'item')
.info(info)
.ejectQueryBuilder((qb: SelectQueryBuilder): SelectQueryBuilder => {
qb.innerJoin("item.category", "category")
return qb.where("category.name = :name", { name: args.name })
})
.loadMany()
}
Implementing something like this would come with the same caveats that I mentioned about the Brackets, mainly that once you start manipulating the SelectQueryBuilder yourself, there is no guarantee that it will always play nicely with what the loader does, but there isn't really anything I can do about that 🙁
Obviously, the actual implementation may look slightly different, but I think something like this could be pretty useful for a lot of things and would make the loader a lot more flexible for complex resolve logic.
from typeorm-graphql-loader.
that indeed sounds like a plan. and we'll tackle the caveats as they come along. at least for my scenario it's not over complifying the query I hope :)
and say - another small issue - when loading the loader in the ApolloServer initialization under the context property, before I integrated your wonderfull lib I used to have a function in the context, for adding user info to the context. but now - I need to choose between the loader and the function. I've tried defining the loader in the function, since it returns an object (don't remember the type) - and it worked, but then it initialized the connection per request and eventually failed. it feels like there should be a way to joined initialization.. I've tried stuff like:
const loader = new GraphQLDatabaseLoader(connection);
const server = new ApolloServer({
schema,
playground: true,
introspection: true,
context: { ...gqlContext, loader },
uploads: true,
});
server.applyMiddleware({ app });
where gqlContext
is my function. but it didn't work :(
oh and again - I have this feeling that you're packing you bags and I'm interrupted, feel free to not answer right away :) I really appreciate your responsiveness but also understand life :) :)
from typeorm-graphql-loader.
You should be able to use a function to create a context. I do the same whenever I use the loader. I would suggest passing the connection into your context function so that you aren't creating duplicate connections like so:
function createContext(db: Connection) {
return {
loader: new GraphQLDatabaseLoader(db)
// other fields
}
}
// Connect to Database
const db = await createConnection()
const apolloServer = new ApolloServer({
schema,
context: createContext(db),
});
from typeorm-graphql-loader.
thanks again! it was a bit different for me, because you can pass a function to create context (or an object), but if you pass a function - it only has req/res as params (and also connection which is undefined, I think it's a websocket connection). but I just moved the function to the area of the server initialization, and then it had access to the connection object (yey closures!)
thanks again for your help, and crossing fingers for you to solve that relation-in-a-where clause (or order, btw). good luck with the move :)
from typeorm-graphql-loader.
Initial implementation is done. Need to add some more testing and perhaps more documentation. Feature can be tracked here: https://gitlab.com/Mando75/typeorm-graphql-loader/-/merge_requests/24
from typeorm-graphql-loader.
v1.6.0 of the loader has been published which adds an ejectQueryBuilder
method to the GraphQLQueryBuilder class. This can be used to directly interact with the underlying TypeORM SelectQueryBuilder, which should fix your issue. See the documentation here: https://gql-loader.bmuller.net/classes/graphqlquerybuilder.html#ejectquerybuilder.
I added a test case that does pretty much exactly what you are trying to do, so I think we should be covered. Feel free to reopen if you are still having trouble.
from typeorm-graphql-loader.
Great news!!! thanks!!! I'll integrate it in the coming days, thanks for the ever-so-quick fix!
from typeorm-graphql-loader.
Related Issues (16)
- Question : How can i use this loader without attaching GraphQLDatabaseLoader with predefined TypeOrm connection in GQL config? HOT 3
- export builder and other important types in the entry file please HOT 2
- Support for named columns HOT 4
- column "createdat" does not exist HOT 5
- Thanks! HOT 1
- ConfigureLoader Not working! HOT 13
- Support Data Mapper entities HOT 1
- Ordering of sub relations
- Redundant typeof BaseEntity typing HOT 1
- How to properly implement resolvers? HOT 5
- [Question] How does this library handle field resolvers? HOT 2
- Small fix for graphqlQueryBuilder.ts HOT 2
- Pagination query not selecting correct fields HOT 5
- Support nested/inherited types fields HOT 10
- Incorrect typing for `where` HOT 1
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 typeorm-graphql-loader.