dry-rb / dry-schema

Coercion and validation for data structures
https://dry-rb.org/gems/dry-schema
MIT License
417 stars 109 forks source link

How to get list of required fields, optional fields and all fields? #36

Closed maxd closed 4 years ago

maxd commented 8 years ago

Hi,

For example I have schema:

class ParamsValidator < Dry::Validation::Schema::Form
  key(:a) { ... }
  optional(:b) { ... } 
end

How can I get list of required fields ([:a]), optional fields ([:b]) and all fields ([:a, :b])?

FYI: I want to use these lists in unit-tests for check validation of optional fields.

solnic commented 8 years ago

No such API yet. I'm marking this as a feature request.

solnic commented 8 years ago

What about nested hashes? Have you thought about the structure of the object that would provide this kind of information?

joevandyk commented 8 years ago

Maybe:

attributes = ParamsValidator.attributes
a = attributes.first
a.name # :a
a.optional? # false
a.required? # true
solnic commented 8 years ago

This could be a done a separate extension. Converting rule ast into such object won't be a problem. I don't need this though, at least not now, so I won't be working on it. I'll mark this as help-wanted for now.

rx commented 8 years ago

I'm in need of this functionality. In looking at the code it seems like creating a attributes-compiler that walks the ast, similar to the hints-compiler is a good place to start? @solnic is that a reasonable way to start working on this feature?

solnic commented 8 years ago

@rx yes we could do it like that although I wonder now if that wouldn't be an overkill. Maybe it's better/simpler to mark rules with additional meta-data in the DSL, then you could simple look at Schema.rules and inspect it (this returns a hash with Symbol => Schema::Rule mapping).

rx commented 8 years ago

@solnic, @backus Here is a WIP version. https://github.com/voomify/dry-metadata

Notes: (In no particular order.)

Metadata Fields Interface

fields.each do |field|
    puts field.name      # the name of the field
    puts field.required? # if the field is required
    puts field.optional? # if the field is !required
    puts field.types     # the array of valid types
    puts field.logic     # polish notation of the logic (minus custom rules)
    puts field.fields    # nested fields or []
end

# To fetch all required fields:
fields.required_fields

# To fetch all optional fields:
fields.optional_fields

# To fetch a single field by name:
fields[:age]

# To sort by name:
fields.sort

# To get an array of hash representations suitable to serialize:
fields.to_a
rx commented 8 years ago

With Dry Validation

require 'dry-validation'

UserSchema = Dry::Validation.Schema do
  required(:name).filled
  required(:age).maybe(:int?)
  required(:address).schema do
    required(:street).filled
    required(:city).filled
    optional(:zipcode).filled
  end
end

fields = Dry::Metadata::Fields.from_validation(UserSchema)

With Dry Struct

This is experimental - not all cases have been spec'ed yet. Please report any issues you find.

require 'dry-struct'
module Types
    include Dry::Types.module
end

class Address < Dry::Types::Struct
    attribute :street, Types::Strict::String
    attribute :city, Types::Strict::String
    attribute :zipcode, Types::Strict::String.optional
end

class UserStruct < Dry::Types::Struct
    attribute :name, Types::Strict::String
    attribute :age,  Types::Strict::Int
    attribute :address, Address
end

fields = Dry::Metadata::Fields.from_struct(UserStruct)
rx commented 8 years ago

Updated to work with new dry-l, dry-v ast. This branch is pulling dry-v and dry-s from master.

https://github.com/voomify/dry-metadata/commit/bcdfe967b6c05b418ee4c29778c58a0a414bd5be

mkristian commented 7 years ago

@rx is this still used/maintained ? I did some ast visitor for my dry-validation and wonder if it is worth using your gem ?

rx commented 7 years ago

@mkristian

felixyz commented 7 years ago

@rx I am certainly interested! We wrote some code to convert dry-v forms into JSON Schema (to generate Swagger data—very nifty!) but it's very hacky and ad hoc.

mkristian commented 7 years ago

have to add my 2 cents: we also wrote a piece of code to convert dry-v to swagger json and that is where my interest in this 'gem' comes from ;)

solnic commented 7 years ago

This type of conversions are highly desired, and it's one of the reasons why dry-v uses formal AST to represent rules. This is not yet 1st-class but will be once we finally get to 1.0.0. Just remember we're still in beta phase, so AST structure may change. FWIW I don't expect to see any serious breaking changes, but we may tweak it a little bit before 1.0.0.

felixyz commented 7 years ago

@mkristian Interesting! Here's our very primitive and inflexible solution if you're interested: https://gist.github.com/felixyz/62130f9f6b9aa309c3ddfb9fd534a0fc

I will look into replacing most of it with dry-metadata or something similar next time we need to touch this code.

@solnic Looking forward to stronger support and makes sense to do that post-1.0 👍

mkristian commented 7 years ago

@felixyz thanks for the gist. next time I need to touch our AST visitor I will come back to it. right now things are working for me but always looking for more general and robust solutions in the long run.