Giter Club home page Giter Club logo

Comments (12)

eyal-elkevity avatar eyal-elkevity commented on May 30, 2024 2

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.

Mando75 avatar Mando75 commented on May 30, 2024

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.

eyal-elkevity avatar eyal-elkevity commented on May 30, 2024

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:

image

maybe we have different versions of typeorm? I'm using 0.2.26

from typeorm-graphql-loader.

Mando75 avatar Mando75 commented on May 30, 2024

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.

eyal-elkevity avatar eyal-elkevity commented on May 30, 2024

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.

Mando75 avatar Mando75 commented on May 30, 2024

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.

eyal-elkevity avatar eyal-elkevity commented on May 30, 2024

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.

Mando75 avatar Mando75 commented on May 30, 2024

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.

eyal-elkevity avatar eyal-elkevity commented on May 30, 2024

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.

Mando75 avatar Mando75 commented on May 30, 2024

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.

Mando75 avatar Mando75 commented on May 30, 2024

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.

eyal-elkevity avatar eyal-elkevity commented on May 30, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.