Skip to content
This repository has been archived by the owner on Mar 13, 2024. It is now read-only.

Capturing Variables #13

Open
amilner42 opened this issue Nov 15, 2016 · 2 comments
Open

Capturing Variables #13

amilner42 opened this issue Nov 15, 2016 · 2 comments
Labels

Comments

@amilner42
Copy link
Owner

Sometimes in our imperative-messes we do get the usefulness of "capturing" variables so if we need them we don't need to re-query.

To give an example, when we query the database to check if a users password is good (in the restriction), it's useful to "capture" that user so if it is good we can return that user. At the moment, this cant be done with the library, you can though put a let user: User at the top and capture it yourself, but that's ugly and is coupling the schema to random external lines of code.

The plan is to allow capturing through the resolve, the benefit being we can stay at one method, it doesn't make things much more complicated, and now we can just resolve with whatever we want as opposed to void.

Also, it should work with nesting nicely, so I'll have to think about how exactly to do this. Eg. An outer restriction requiring a variable from an inner restriction.

@amilner42
Copy link
Owner Author

Ok so far the brainstorming:

  1. Any time schema can resolve with data in the restriction, any data allowed.
  2. The object schema, array schema, and reference schema when pointing to those two schemas, will allow you to work with this captured data. In primitives, nothing could emit the captured data, in unions there are no restrictions, hence these 2 don't apply.
    • In an object, you'd recieve an object of captured params, keys: propertyName, values: capturedParams
    • In an array you'd get a matching array of captured args.
  3. The object/array can use those captured params if needed for their restrictions
  4. Again, all restrictable schemas can capture params, so it's up to the schema to "continue" the chain.
  5. If it is the outermost schema, it will actually resolve the captrued params to the .then, this means that when we do things like validUserForLoginSchema we could actually be given the user upon success.

NOTE: If you just have a primitive at root level for instance, you can still resolve captured params to the .then, even though you can't use captured params in your own restriction because nothing "beneath" you.

@amilner42
Copy link
Owner Author

A bit of code and a lot of playing around with the type system and it seems that the type system in Typescript won't hold up for the previous design. The root of the problem is that:

  • Implying a generic dependence is no longer supported without explicitly listing out the extra generic, so it'll force the user to always specify too many generics (4 for a typeSchema). That's no good.
  • Ideally we have simply "in" and "out" on the typeSchema generic-wise, but doing this won't work nicely with the current design, *the requirement for the objectSchema generics will be stricter than the requirement for the typeSchema so it won't even allow that. (Same with Array).
  • If you think about it, with the current design, typeSchema<Input,Output> doesn't even make sense because if it was something like a number as input we cant have this in the objectSchema. Hence why it doesn't allow it (bullet point above).

Capture Design 2.0

I started designing a new approach last night, it goes like this:

  • typeSchema will define it's generics, again going for <Input, Output>
    • Both Input and Output will always be maps. The values can be any type.
  • Every property in an object has to return Input type.
  • Every element in an array has to return Input type.
    • With these restrictions, we get a nice connection between typeSchemas and hence compile-time-type-checking
  • An object can have properties which return different types of course, so how do we get away with having one Input type? Well Input is a map, and if the user property returns a: number, and the other property returns b: number, then the typing on the Input type will be:
  • Input: { a: number, b: number } or Input: {a?: number, b?: number} if it complains about a/b being missing.
  • Each property in the object is a typeSchema itself, and will be given it's own captured properties, but what else we'll do is we'll update the captured objects for a property as the other properties complete, same applies to array, why?
    • The reason is that for an array for example, we have the same logic being executed x times and it would be nice if we could get an array of results under a single key in the captureMap. To do this, we'd need to update the map as the array runs so it can check if an array already exists and push it's result to that array.
  • In terms of types as things stack, this is where things really fit nicely, I though it would be nice for the full output of a schema to be Input & Output. That way we have this map that we propagate through the code, ad typescript can actually type check for us! If we have a nested user property even 5 objects deep, we can still resort to the value it sends in it's map. This is convenient because most schemas won't care about capturing, so it makes it simpler to use if a schema is not forced to always have to resolve, unless it has anything additional to capture.

Still Unsure About:

  • I quickly double checked this:
interface x {
    x: number;
}

interface x2 {
    x: string;
}

type y = x & x2;

And it seems that y is now an impossible type. It forced x to be both a string and a number. This means that the capture map cannot overwrite values, this may be a problem, I'm not sure yet.

  • Not sure about returning an intersection of Input and Output. The biggest benefit is that schemas would (I think) be more re-usuable. You could plug in a schema to another schema and now a schema above both would be able to use captures from both, this seems like a big benefit but im not sure.

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

No branches or pull requests

1 participant