X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=lib%2FMojoFacets%2FData.pm;h=1c5f551f362fce911058ec2f4d97cb3d6cd59167;hb=810b23461ea7679c065c82487d64b2f67052f896;hp=1a08e3c2e9d61e3a2465cbd75f3c8792d720fe44;hpb=45bba92c2606ec5506865f75835ad308409d4b68;p=MojoFacets.git diff --git a/lib/MojoFacets/Data.pm b/lib/MojoFacets/Data.pm index 1a08e3c..1c5f551 100644 --- a/lib/MojoFacets/Data.pm +++ b/lib/MojoFacets/Data.pm @@ -12,6 +12,7 @@ use locale; use File::Find; use Storable; use Time::HiRes qw(time); +use File::Path qw(mkpath); use MojoFacets::Import::File; use MojoFacets::Import::HTMLTable; @@ -26,14 +27,14 @@ sub index { die "no data dir $data_dir" unless -d $data_dir; my @files; - my $edits; + my $changes; find( sub { my $file = $File::Find::name; if ( -f $file && $file =~ m/\.(js(on)?|txt)$/ ) { $file =~ s/$data_dir\/*//; push @files, $file; - } elsif ( -f $file && $file =~ m/([^\/]+)\.edits\/(\d+\.\d+.+)/ ) { - push @{ $edits->{$1} }, $2 + } elsif ( -f $file && $file =~ m/([^\/]+)\.changes\/(\d+\.\d+.+)/ ) { + push @{ $changes->{$1} }, $2 } elsif ( -d $file && $file =~ m/\.html$/ ) { $file =~ s/$data_dir\/*//; push @files, $file; @@ -52,7 +53,7 @@ sub index { loaded => $loaded, filters => $filters, dump_path => { map { $_ => $self->_dump_path($_) } @files }, - edits => $edits, + changes => $changes, ); } @@ -129,7 +130,7 @@ sub __stats { } if ( $unique ) { $stats->{$n}->{unique} = 1; - warn "# $n unique ",dump( $unique ); + #warn "# $n unique ",dump( $unique ); } } } @@ -225,7 +226,6 @@ sub load { $self->_load_path( $path ); $self->session( 'path' => $path ); - $self->session( 'modified' => $loaded->{$path}->{modified} ); my $redirect_to = '/data/items'; @@ -252,6 +252,18 @@ sub _loaded { my ( $self, $name ) = @_; my $path = $self->session('path') || $self->param('path'); $self->redirect_to('/data/index') unless $path; + + if ( $loaded->{$path}->{modified} > 1 ) { + my $caller = (caller(1))[3]; + if ( $caller =~ m/::edit/ ) { + warn "rebuild stats for $path ignored caller $caller\n"; + } else { + warn "rebuild stats for $path FORCED by modified caller $caller\n"; + $loaded->{$path}->{stats} = __stats( $loaded->{$path}->{data}->{items} ); + $loaded->{$path}->{modified} = 1; + } + } + if ( ! defined $loaded->{$path}->{$name} ) { warn "$path $name isn't loaded\n"; $self->_load_path( $path ); @@ -262,6 +274,9 @@ sub _loaded { $loaded->{$path}->{stats} = __stats( $loaded->{$path}->{data}->{items} ); } } + + $self->session( 'modified' => $loaded->{$path}->{modified} ); + return $loaded->{$path}->{$name}; } @@ -283,10 +298,12 @@ sub _permanent_path { sub _export_path { my $self = shift; my $path = $self->_param_or_session('path'); - my $dir = $self->app->home->rel_dir('public') . '/export/'; - mkdir $dir unless -e $dir; - $dir .= $path; - mkdir $dir unless -e $dir; + if ( ! $path ) { + warn "no path in param or session"; + return; + } + my $dir = $self->app->home->rel_dir('public') . "/export/$path"; + mkpath $dir unless -e $dir; $dir . '/' . join('.', @_); } @@ -501,7 +518,7 @@ sub _data_sorted_by { } } map { [ $nr++, exists $_->{$order} ? join('', @{$_->{$order}}) : $missing ] - } @{ $data->{items} } + } grep { ref $_->{$order} eq 'ARRAY' } @{ $data->{items} } ; warn "sorted: $order numeric: $numeric items: ", $#sorted + 1, "\n"; @@ -582,17 +599,39 @@ sub items { warn "all_filters $all_filters produced ", $#$filtered + 1, " items\n" if $filtered; - my $sorted_items; my $data = $self->_loaded('data'); + + my $code = $self->param('code'); + if ( $self->param('commit') ) { + warn "# commit $code"; + foreach ( 0 .. $#{ $data->{items} } ) { + my $rec = $data->{items}->[ $_ ]; + eval $code; + } + undef $code; + } + + my $sorted_items; my $from_end = $sort eq 'd' ? $#$filtered : 0; foreach ( 0 .. $limit ) { my $i = $_ + $offset; last unless defined $filtered->[$i]; $i = $from_end - $i if $from_end; my $id = $filtered->[$i]; - push @$sorted_items, - my $item = $data->{items}->[ $id ]; - $item->{_row_id} ||= $id; + my $rec = $data->{items}->[ $id ]; + $rec->{_row_id} ||= $id; + if ( $code ) { + $rec = Storable::dclone $rec; + eval $code; + if ( $@ ) { + warn "ERROR evaling\n$code\n$@"; + undef $code; + $self->stash('eval_error', $@) if $@; + } else { + warn "EVAL $code ",dump($rec); + } + } + push @$sorted_items, $rec; } warn "# sorted_items ", $#$sorted_items + 1, " offset $offset limit $limit order $sort"; @@ -725,9 +764,34 @@ sub facet { ); } + +sub __invalidate_path_column { + my ( $path, $name ) = @_; + + if ( defined $loaded->{$path}->{sorted}->{$name} ) { + delete $loaded->{$path}->{sorted}->{$name}; + warn "# invalidate $path sorted $name\n"; + } + + foreach ( grep { m/$name/ } keys %{ $loaded->{$path}->{filtered} } ) { + delete $loaded->{$path}->{filtered}->{$_}; + warn "# invalidate $path filtered $_\n"; + } +} + +sub __path_modified { + my ( $path, $value ) = @_; + $value = 1 unless defined $value; + + $loaded->{$path}->{modified} = $value; + + warn "# __path_modified $path $value\n"; +} + sub edit { my $self = shift; my $new_content = $self->param('new_content'); + $new_content ||= $self->param('content'); # backward compatibility with old actions my $i = $self->param('_row_id'); die "invalid _row_id ",dump($i) unless $i =~ m/^\d+$/; @@ -752,7 +816,7 @@ sub edit { if ( $old ne $new && ! ( $old eq 'undef' && length($new_content) == 0 ) # new value empty, previous undef ) { - my $edit = { + my $change = { path => $path, column => $name, pos => $i, @@ -766,29 +830,21 @@ sub edit { keys %{ $loaded->{$path}->{stats} } }, }; - my $edit_path = $self->_permanent_path( 'edits' ); - mkdir $edit_path unless -d $edit_path; - $edit_path .= '/' . $edit->{time}; - store $edit, $edit_path; - utime $edit->{time}, $edit->{time}, $edit_path; - warn "# $edit_path ", dump($edit); - - warn "# edit $path $i $old -> $new\n"; + my $change_path = $self->_permanent_path( 'changes' ); + mkdir $change_path unless -d $change_path; + $change_path .= '/' . $change->{time}; + store $change, $change_path; + utime $change->{time}, $change->{time}, $change_path; + warn "# $change_path ", dump($change); + + warn "# change $path $i $old -> $new\n"; $loaded->{$path}->{data}->{items}->[$i]->{$name} = $v; - if ( defined $loaded->{$path}->{sorted}->{$name} ) { - delete $loaded->{$path}->{sorted}->{$name}; - warn "# invalidate $path sorted $name\n"; - } - - foreach ( grep { m/$name/ } keys %{ $loaded->{$path}->{filtered} } ) { - delete $loaded->{$path}->{filtered}->{$_}; - warn "# invalidate $path filtered $_\n"; - } + __invalidate_path_column( $path, $name ); $status = 201; # created - $loaded->{$path}->{modified} = 1; - $self->session( 'modified' => 1 ); + # modified = 2 -- force rebuild of stats + __path_modified( $path, 2 ); $new_content = join("\xB6",@$v); @@ -814,16 +870,30 @@ sub save { my $self = shift; my $path = $self->_param_or_session('path'); my $dump_path = $self->_save( $path ); - $loaded->{$path}->{modified} = 0; - $self->session( 'modified' => 0 ); + __path_modified( $path, 0 ); $self->redirect_to( '/data/items' ); } sub export { my $self = shift; + + if ( my $import = $self->param('import') ) { + + if ( $import =~ m{/filter\.(.+?)\..+} ) { + my $name = $1; + my @vals = map { chomp; $_ } + read_file $self->app->home->rel_dir('public') . "/export/$import"; + $self->_remove_filter( $name ); + $self->_filter_on_data( $name, @vals ); + $self->session( 'offset' => 0 ); + $self->redirect_to('/data/items'); + } else { + warn "UNKNOWN IMPORT $import"; + } + } + $self->render( export => [ - map { s{^.+/public/export/}{}; $_ } glob( $self->_export_path . '*' ) ] ); }