Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic proxy resolvers #399

Open
Goues opened this issue Jan 21, 2025 · 1 comment
Open

Dynamic proxy resolvers #399

Goues opened this issue Jan 21, 2025 · 1 comment

Comments

@Goues
Copy link

Goues commented Jan 21, 2025

Hey, I'm trying to implement something that behaves as a QUERY syntax but isn't as complex to use for a non-technical user. Long story short, I have a system that allows user defined objects and properties, a user can modify object schemas to add new properties as well as create new relationships. GraphQL query would be awesome for this, but it's fairly hard to use.

+++QUERY
query getData($id: Int!) {
  reservation(id: $id) {
    location_from { name }
    brand { name }
    payments {
      timestamp
      type
      value
    }
  }
}
++++

So I wanted to try a different approach with Proxies. The POC works fine (meaning that the Proxy work, the output is empty), but the data loaders are async and DocxTemplates would currently not await the results.

const reservation = new Proxy(
  {},
  { async get(name) => { ... resolve data here ... } }
)

This way, a user can have +++ reservation.brand.name +++ directly without a query command and my code would be able to dynamically resolve the dependency just as if it was using GraphQL.

Would something like this be even possible? I can take a look into it myself, but want to save time asking because maybe you already know the answer.

Thanks

@Goues
Copy link
Author

Goues commented Jan 23, 2025

I've actually made it work using a Proxy. Let's say I have a structure, where there are entities Room, Flat, Building, Street, City, Country and Person. The relationships can be arbitrary, like Room would have flat_id and Flat would have building_id, etc.. But also, flat would have tenant as a relation to Person and owner as another relation to Person object.

The docx file can have anything like

+++ room.flat_id +++
+++ room.flat_id.flat_number +++
+++ room.flat_id.building_id.street_id.name +++

which could output something like

17 // <- the ID of the flat
401 // <- the Number of the flat
Main Street // <- the name of the street

and the proxies resolve it so that the call resolvers. The very basic an naive implementation is:

const pReduce = (promise, next) => promise.then(next)

const realproxy = (type, data) => {
	return new Proxy(data, {
		get(_, name) {
			const make = (chain, prev, type) => {
				return new Proxy(
					{},
					{
						get(_, nextName) {
							if (nextName === Symbol.toPrimitive) {
								return data[name]
							}
							if (nextName === 'id') {
								return chain
									.reduce(pReduce, Promise.resolve(data))
									.then(v => v[prev])
							}
							if (nextName === 'then') {
								return n => {
									return chain
										.reduce(pReduce, Promise.resolve(data))
										.then(v => v[prev])
										.then(n)
								}
							}
							return make(
								[
									...chain,
									data => {
										if (references[type]?.[prev]) {
											return loaders[references[type]?.[prev]](data[prev])
										}
										return data[nextName]
									},
								],
								nextName,
								references[type]?.[prev] ?? prev,
							)
						},
					},
				)
			}
			return make([], name, type)
		},
	})
}

const data = realproxy('root', root)

x
and you have to define references and loaders, which I can load up front in my app. So if anybody is interested, it's a valid approach that you can use if DOCX files are supposed to be written by users without having to use GraphQL queries directly. You can play with caching and optimizing the loader, which I will for sure do, but none of that requires changes to this library in the first place.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant