dawarich/lib/json_stream_handler.rb
2025-10-05 20:59:03 +02:00

79 lines
1.9 KiB
Ruby

# frozen_string_literal: true
# Streaming JSON handler relays sections and streamed values back to the importer instance.
class JsonStreamHandler < Oj::Saj
HashState = Struct.new(:hash, :root, :key)
ArrayState = Struct.new(:array, :key)
StreamState = Struct.new(:key)
def initialize(processor)
super()
@processor = processor
@stack = []
end
def hash_start(key = nil, *_)
state = HashState.new({}, @stack.empty?, normalize_key(key))
@stack << state
end
def hash_end(key = nil, *_)
state = @stack.pop
value = state.hash
parent = @stack.last
dispatch_to_parent(parent, value, normalize_key(key) || state.key)
end
def array_start(key = nil, *_)
normalized_key = normalize_key(key)
parent = @stack.last
if parent.is_a?(HashState) && parent.root && @stack.size == 1 && Users::ImportData::STREAMED_SECTIONS.include?(normalized_key)
@stack << StreamState.new(normalized_key)
else
@stack << ArrayState.new([], normalized_key)
end
end
def array_end(key = nil, *_)
state = @stack.pop
case state
when StreamState
@processor.send(:finish_stream, state.key)
when ArrayState
value = state.array
parent = @stack.last
dispatch_to_parent(parent, value, normalize_key(key) || state.key)
end
end
def add_value(value, key)
parent = @stack.last
dispatch_to_parent(parent, value, normalize_key(key))
end
private
def normalize_key(key)
key&.to_s
end
def dispatch_to_parent(parent, value, key)
return unless parent
case parent
when HashState
if parent.root && @stack.size == 1
@processor.send(:handle_section, key, value)
else
parent.hash[key] = value
end
when ArrayState
parent.array << value
when StreamState
@processor.send(:handle_stream_value, parent.key, value)
end
end
end