luislavena / radix

Radix Tree implementation for Crystal
MIT License
102 stars 13 forks source link

Is it possible to add Sub Trees ? #34

Open dinkopehar opened 1 year ago

dinkopehar commented 1 year ago

Hello.

I found your project radix to be really useful and I discovered it because it's used inside Kemal web framework. Although Kemal is great, I'm looking into making my own simple router using your project.

I'm wondering, is there some solution to sub mounting routes ? For example, Starlette framework has support for that.

I tried some solution, but I end up getting a Tree instead of Result:

require "radix"

users_router = Radix::Tree(String).new
pets_router = Radix::Tree(String).new

users_router.add "/", "All Users"
users_router.add "/login", "Login Users"
users_router.add "/logout", "logout Users"

pets_router.add "/", "Pets"
pets_router.add "/:pet", "Specific Pet"

main_router = Radix::Tree(Radix::Tree(String)).new

main_router.add "/users/", users_router
main_router.add "/pets/", pets_router

result = main_router.find "/users/login" # ???

What I was hoping for is that result would return "All Users" instead of Nil. I assume I'm doing a long stretch here but I'm just curious if this is possible.

Thank you.

luislavena commented 1 year ago

Hello @dinko-pehar, thank you for your patience.

Can you explain a bit further the thing you're trying to achieve?

This radix implementation is a bit complex and serves only as lookup, but is not a router. Each time a new entry is added the tree gets updated. To perform something like you're asking, it will require to iterate over the inner trees and map that, resulting in duplicate entries in memory. Basically: the pet and user routers only serve to provide the list of entries, but no tree resolution by itself. If not, once find discover another tree as payload, it returns payload.find on that, which might defeat the purpose of having a single radix tree in the first place.

But I might be missing details of what you want to achieve, so it will be better if you can give more concrete examples.

Thank you.

dinkopehar commented 1 year ago

@luislavena

I was hoping for result = main_router.find "/users/login" in above example to return "Login Users". I didn't really dig exactly into implementation of this radix tree but something similar I found yesterday was on project that is stated in Implementation of README.


For me, I thought to use it with HTTP handlers from Crystal. Basically, having a HTTP Server that first gets a route name with find and than executes HTTP Handler function. I hoped that I could group my project by feature:

| README.md
| shards.yml
| src
  | main.cr              -> Here would be like main router, for example /api/.
  | users
    | models.cr
    | controllers.cr. -> Subrouter that is is registered in main router, so /api/users 
  | pets
    | models.cr.      -> /api/pets
    | controllers.cr
  | shalters
    | models.cr.      
    | controllers.cr

Register subrouter (subtree) in main tree. Tree inside Tree. Not sure if it's clear enough...