package DBIx::Class::JSON;

use JSON::Syck;

sub as_json { JSON::Syck::Dump(shift->_as_json(@_)) }

sub _as_json {
    my ($self, $attrs) = @_;

    my $dump_rels = delete $attrs->{dump_rels};
    push(@$dump_rels, $_) for @{$attrs->{dump_nested_rels}};

    my $hashref = $self->__as_json($attrs);

    for my $rel (@$dump_rels) {
        my $related = $self->$rel;
        
        if ($related->can('_as_json')) {
            $hashref->{$rel} = $related->_as_json($attrs);
        }
        elsif ($related->isa('DBIx::Class::ResultSet')) {
            
            my @subrels;
            
            for my $subrel ($related->all) {
                
                unless ($subrel->can('_as_json')) {
                    $related->result_class->load_components('JSON');
                }

                push @subrels, $subrel->_as_json($attrs);
            }

            $hashref->{$rel} = \@subrels;
        }
        elsif ($related->isa('DBIx::Class::Row')) {
            (ref $related)->load_component('JSON');
            $hashref->{$rel} = $related->_as_json($attrs);
        }
        else {
            require Carp;
            Carp::croak("Unknown relationship type");
        }
    }
    
    return $hashref;
}

sub __as_json {
    my ($self, $attrs) = @_;

    my $result_source = $self->result_source;
    my $columns = $result_source->_columns;
    
    my $hashref = { 
        map 
        { $columns->{$_}->{hide_from_json} ? () : ( $_ => __render_column($self->$_) ) } 
        $result_source->columns 
    };
}

sub __render_column {
    my ($value) = @_;
    defined $value ? ($value . "") : undef;
}

1;
