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

Support for (virtual) array attributes #408

Closed
oneiros opened this issue Jun 26, 2020 · 7 comments · Fixed by #847
Closed

Support for (virtual) array attributes #408

oneiros opened this issue Jun 26, 2020 · 7 comments · Fixed by #847
Assignees

Comments

@oneiros
Copy link
Contributor

oneiros commented Jun 26, 2020

I tried to setup a Avram::Operation with an array attribute:

class CreateRoles < Avram::Operation
  attribute role_names : Array(String)
end

Sadly this will not compile, because crystal does not currently support nested constants in generics. In #151 @jwoertink added array support for column values and found a nice workaround.

So as a first step, I tried to use this workaround and change

parse_result = {{ type }}::Lucky.parse({{ name }}_param)

to

parse_result = {{ type }}.adapter.parse({{ name }}_param)

Then my app did compile successfully. I have not checked if it actually works yet, because I thought this would be a nice little fix I could prepare a PR for.

Sadly, I failed because when I tried to add specs, they blew up:

There was a problem expanding macro 'setter'

Code in src/avram/attribute.cr:4:3

 4 | setter :value
     ^
Called macro defined in macro 'macro_139913478760976'

 483 | macro setter(*names)

Which expanded to:

 > 1 |       
 > 2 |         
 > 3 |           def value=(@value)
                            ^----
Error: instance variable '@value' of Avram::Attribute(Array(String) | Nil) must be (Array(String) | Nil), not (String | Nil)

I think the reason is that the specs use Avram::Params which only supports a flat String => String mapping. If my theory is correct, my app compiles, because it uses Lucky::Params which does support nested structures.

If someone knows an easy fix, I would be happy to continue the work on a PR.

But more importanty I think this could be valuable input for luckyframework/lucky#1209

@wout
Copy link
Contributor

wout commented Jun 26, 2020

I've been in the same place while testing file params. The way I worked around this was to create a subclass for Avram::Params just for testing purposes:

https://github.com/luckyframework/avram/pull/404/files#diff-dcf82d31916d537fe7e9380227ffc216

But that's obviously not an ideal solution. I think Avram::Params needs some work to bring it more in line with Lucky::Params.

@matthewmcgarvey
Copy link
Member

I'd like to refactor Avram to be able to remove Avram::Paramable and Avram::Params. They are rough stand-ins for Lucky::Params. This won't be usable until luckyframework/lucky#1380 is finished but I'd like to cut the dependency and allow Avram::Attribute to be any type as long as it can extract the type from whatever object is passed in (like Lucky::Params)

@matthewmcgarvey
Copy link
Member

Now that luckyframework/lucky#1380 is done, here's what we need to do:

I think that will get array attributes working

@matthewmcgarvey matthewmcgarvey self-assigned this Jan 19, 2021
@matthewmcgarvey
Copy link
Member

matthewmcgarvey commented Jan 19, 2021

Unfortunately I was wrong. luckyframework/lucky#1380 added get_all at the top level but we need it under a nested key. A query param would look like example.com?post:tags[]=crystal&post:tags[]=lucky. Calling params.nested("post") returns a Hash(String, String) right now. We should probably get it to return another param object or something equivalent to JSON::Any...

@jwoertink Got any opinions on this?

@jwoertink
Copy link
Member

params.many_nested is already a method. We should be using that within the operations itself.

@matthewmcgarvey
Copy link
Member

@jwoertink many_nested returns Array(Hash(String, String)) it's meant for nested operations not a nested array of strings.

This is kind of why I think Lucky::Params needs to be overhauled. The API is pretty confusing

@jwoertink
Copy link
Member

Oh that's right. Yeah, the params definitely need a bit of thought. @paulcsmith and I have tried to tackle it a few times, but it's not an easy problem to solve. I have some ideas that I think I sent over to you before, but I can send those again. I'm just limited on time at the moment to really sit down and attack it.

Does doing something like this work? params.nested("post").get_all("tags")? Probably not because nested() returns a Hash or something instead of returning a param object... 🤔 Oh, what about something like params.get_all("#{param_key}:tags")?

I think it all just goes back to the fact that Avram shouldn't care about HTTP Params. We should bring back this discussion luckyframework/lucky#727. Though, that's about just the Lucky side.

Let's figure out a time we can hop on a chat to go over a path for this. Then we can document that path, and figure out if there's an easy migration/change, or if it'll just be a single massive overhaul from the ground up (most likely lol)

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

Successfully merging a pull request may close this issue.

4 participants