yosiat / panko_serializer

High Performance JSON Serialization for ActiveRecord & Ruby Objects
https://panko.dev
MIT License
592 stars 36 forks source link

Conditional inclusion of has_many association using `Panko::Serializer::SKIP` #162

Open dev-nomi opened 3 months ago

dev-nomi commented 3 months ago

Hey! I have a question regarding the performance implications for conditionally including a has_many association using Panko::Serializer::SKIP. Specifically, I am using Panko::ArraySerializer in the following implementation:

module Clients
  class QuestionSerializer < Panko::Serializer
    attributes :id, :text, :question_instructions

    def question_instructions
      return Panko::Serializer::SKIP unless object.photo_choice_question?

      Panko::ArraySerializer.new(
        object.question_instructions,
        each_serializer: Base::QuestionInstructionSerializer
      ).to_a
    end
  end
end

module Clients
  class QuestionnaireSerializer < Panko::Serializer
    attributes :id, :title

    has_many :questions, each_serializer: Clients::QuestionSerializer
  end
end

Questions:

  1. Performance Impact: Are there any known performance concerns or optimizations related to the use of Panko::ArraySerializer in this context? Specifically, how does it affect serialization performance, especially with large sets of question_instructions?
  2. Potential Improvements: Are there any potential improvements or refactorings that could be considered to enhance performance

Thank you!

yosiat commented 1 month ago

Hi,

Yes, there will be a performance impact because you're creating an array serializer repeatedly. In my codebase, we do this in some cases where it's acceptable performance-wise, but in other cases, we avoid it because it becomes too slow. I suggest running benchmarks with your data to determine if the performance hit is acceptable for your use case.

If the performance impact is too high, unfortunately, Panko doesn't currently provide a built-in solution to handle this efficiently. However, you can use a workaround like adding a method to your model, for example:

def questions_instructions_for_serializer
  return [] unless photo_choice_question?
  question_instructions
end

Then you can use questions_instructions_for_serializer as a has_many alias.

Currently, dynamic exclusions aren't supported, and adding such a feature would require significant effort without resorting to workarounds.

Hope this helps!

dev-nomi commented 1 month ago

Thanks, it helps alot