--- parser3/src/classes/table.C 2021/12/22 21:59:50 1.360 +++ parser3/src/classes/table.C 2024/11/16 02:57:05 1.372 @@ -1,8 +1,8 @@ /** @file Parser: @b table parser class. - Copyright (c) 2001-2020 Art. Lebedev Studio (http://www.artlebedev.com) - Author: Alexandr Petrosian (http://paf.design.ru) + Copyright (c) 2001-2024 Art. Lebedev Studio (http://www.artlebedev.com) + Authors: Konstantin Morshnev , Alexandr Petrosian */ #include "pa_config_includes.h" @@ -24,8 +24,9 @@ #include "pa_sql_connection.h" #include "pa_vbool.h" #include "pa_array.h" +#include "pa_varray.h" -volatile const char * IDENT_TABLE_C="$Id: table.C,v 1.360 2021/12/22 21:59:50 moko Exp $"; +volatile const char * IDENT_TABLE_C="$Id: table.C,v 1.372 2024/11/16 02:57:05 moko Exp $"; // class @@ -69,19 +70,22 @@ static Table::Action_options get_action_ result.offset=source.current(); else throw Exception(PARSER_RUNTIME, &soffset, "must be 'cur' string or expression"); - } else - result.offset=r.process(*voffset).as_int(); + } else { + int offset=r.process(*voffset).as_int(); + result.offset=offset < 0 ? 0 : offset; + } } if(Value* vlimit=options->get(sql_limit_name)) { valid_options++; - result.limit=r.process(*vlimit).as_int(); + int limit=r.process(*vlimit).as_int(); + result.limit=limit < 0 ? 0: limit; } - if(Value *vreverse=(Value *)options->get(table_reverse_name)) { + if(Value *vreverse=(Value *)options->get(table_reverse_name)) { valid_options++; result.reverse=r.process(*vreverse).as_bool(); if(result.reverse && !defined_offset) result.offset=source.count()-1; - } + } if(valid_options!=options->count()) throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION); @@ -256,9 +260,9 @@ static void _create(Request& r, MethodPa if(params.count()>1) { if(params[0].is_string()){ // can be nameless only - const String& snameless=params.as_string(0, "called with more then 1 param, first param may be only string 'nameless' or junction"); + const String& snameless=params.as_string(0, "called with more than 1 param, first param may be only string 'nameless' or junction"); if(snameless!="nameless") - throw Exception(PARSER_RUNTIME, &snameless, "table::create called with more then 1 param, first param may be only 'nameless'"); + throw Exception(PARSER_RUNTIME, &snameless, "table::create called with more than 1 param, first param may be only 'nameless'"); nameless=true; data_param_index++; } @@ -485,15 +489,15 @@ static void table_to_csv(pa_stringstream if(output_column_names) { if(table.columns()) { // named table if(control_chars.encloser){ - for(Array_iterator i(*table.columns()); i.has_next(); ) { + for(Array_iterator i(*table.columns()); i; ) { enclose( result, i.next(), control_chars.encloser ); - if(i.has_next()) + if(i) result< i(*table.columns()); i.has_next(); ) { + for(Array_iterator i(*table.columns()); i; ) { result<cstr(); - if(i.has_next()) + if(i) result< i(table); if(control_chars.encloser){ - while(i.has_next()) { - for(Array_iterator c(*i.next()); c.has_next(); ) { + while(i) { + for(Array_iterator c(*i.next()); c; ) { enclose( result, c.next(), control_chars.encloser ); - if(c.has_next()) + if(c) result< c(*i.next()); c.has_next(); ) { + while(i) { + for(Array_iterator c(*i.next()); c; ) { result<cstr(); - if(c.has_next()) + if(c) result< i(*table.columns()); i.has_next(); ) { + for(Array_iterator i(*table.columns()); i; ) { enclose( result, i.next(), control_chars.encloser, control_chars.sencloser ); - if(i.has_next()) + if(i) result<<*control_chars.sseparator; } } else { - for(Array_iterator i(*table.columns()); i.has_next(); ) { + for(Array_iterator i(*table.columns()); i; ) { result<<*i.next(); - if(i.has_next()) + if(i) result<<*control_chars.sseparator; } } @@ -580,9 +584,9 @@ static void table_to_csv(String& result, if(int lsize=table.count()?table[0]->count():0) for(int column=0; column i(table); if(control_chars.encloser){ - while(i.has_next()) { - for(Array_iterator c(*i.next()); c.has_next(); ) { + while(i) { + for(Array_iterator c(*i.next()); c; ) { enclose( result, c.next(), control_chars.encloser, control_chars.sencloser ); - if(c.has_next()) + if(c) result<<*control_chars.sseparator; } result.append_know_length("\n", 1, String::L_CLEAN); } } else { - while(i.has_next()) { - for(Array_iterator c(*i.next()); c.has_next(); ) { + while(i) { + for(Array_iterator c(*i.next()); c; ) { result<<*c.next(); - if(c.has_next()) + if(c) result<<*control_chars.sseparator; } result.append_know_length("\n", 1, String::L_CLEAN); @@ -747,7 +751,7 @@ static void _offset(Request& r, MethodPa else if(whence=="set") absolute=true; else - throw Exception(PARSER_RUNTIME, &whence, "is invalid whence, valid are 'cur' or 'set'"); + throw Exception(PARSER_RUNTIME, &whence, "is an invalid whence, valid are 'cur' or 'set'"); } int offset=params.as_int(params.count()-1, "offset must be expression", r); @@ -764,7 +768,7 @@ static void _menu(Request& r, MethodPara Value* delim_maybe_code=params.count()>1?¶ms[1]:0; Table& table=GET_SELF(r, VTable).table(); - size_t saved_current=table.current(); + Temp_current tc(table); if(delim_maybe_code) { // delimiter set bool need_delim=false; @@ -797,7 +801,6 @@ static void _menu(Request& r, MethodPara break; } } - table.set_current(saved_current); } #ifndef DOXYGEN @@ -843,14 +846,14 @@ static void table_row_to_hash(Table::ele HashStringValue& hash=vhash->hash(); Table::columns_type columns=info->table->columns(); if(info->value_fields){ // selected fields (can be empty) - for(Array_iterator i(*info->value_fields); i.has_next(); ) { + for(Array_iterator i(*info->value_fields); i; ) { size_t value_field=i.next(); if(value_fieldcount()) - hash.put(columns ? *columns->get(value_field) : String(format(value_field, 0)), new VString(*row->get(value_field))); + hash.put(columns ? *columns->get(value_field) : String(pa_uitoa(value_field)), new VString(*row->get(value_field))); } } else { // all fields for(size_t index=0; indexcount(); index++) { - hash.put(columns && index < columns->count() ? *columns->get(index) : String(format(index, 0)), new VString(*row->get(index))); + hash.put(columns && index < columns->count() ? *columns->get(index) : String(pa_uitoa(index)), new VString(*row->get(index))); } } exist=info->hash->put_dont_replace(*key, vhash); @@ -972,7 +975,7 @@ static void _hash(Request& r, MethodPara if(!field_name.is_empty()) value_fields+=self_table.column_name2index(field_name, true); } else if(Table* value_fields_table=value_fields_param.get_table()) { // list of columns were specified in table - for(Array_iterator i(*value_fields_table); i.has_next(); ) { + for(Array_iterator i(*value_fields_table); i; ) { const String& value_field_name =*i.next()->get(0); value_fields +=self_table.column_name2index(value_field_name, true); } @@ -980,7 +983,7 @@ static void _hash(Request& r, MethodPara throw Exception(PARSER_RUNTIME, 0, "value field(s) must be string or table or code"); if(value_type==C_STRING && value_fields.count()>1) - throw Exception(PARSER_RUNTIME, 0, "you can't specify more then one value field with option $.type[string]"); + throw Exception(PARSER_RUNTIME, 0, "you can't specify more than one value field with option $.type[string]"); } Value* key_param=¶ms[0]; @@ -998,15 +1001,37 @@ static void _hash(Request& r, MethodPara }; info.key_field=(info.key_code ? -1 : self_table.column_name2index(key_param->as_string(), true)); - int saved_current=self_table.current(); self_table.for_each(table_row_to_hash, &info); - self_table.set_current(saved_current); result.extract_default(); r.write(result); } +static void _cells(Request& r, MethodParams& params) { + Table& self_table=GET_SELF(r, VTable).table(); + size_t row_size=self_table[self_table.current()]->count(); // number of columns in current row + + if(params.count()){ + int limit=params.as_int(params.count()-1, "offset must be expression", r); + if(limit<0) + limit=0; + if((size_t)limit3?¶ms[3]:0; Table& table=GET_SELF(r, VTable).table(); - size_t saved_current=table.current(); + Temp_current tc(table); rownum_var_name=rownum_var_name->is_empty()? 0 : rownum_var_name; value_var_name=value_var_name->is_empty()? 0 : value_var_name; @@ -1158,7 +1183,7 @@ static void _foreach(Request& r, MethodP table.set_current(row); if(rownum_var_name) - r.put_element(*var_context, *rownum_var_name, new VString(*new String(String::Body::Format(row), String::L_CLEAN))); + r.put_element(*var_context, *rownum_var_name, new VString(*new String(pa_uitoa(row), String::L_CLEAN))); if(value_var_name) r.put_element(*var_context, *value_var_name, new VTable(&table)); @@ -1183,7 +1208,7 @@ static void _foreach(Request& r, MethodP table.set_current(row); if(rownum_var_name) - r.put_element(*var_context, *rownum_var_name, new VString(*new String(String::Body::Format(row), String::L_CLEAN))); + r.put_element(*var_context, *rownum_var_name, new VString(*new String(pa_uitoa(row), String::L_CLEAN))); if(value_var_name) r.put_element(*var_context, *value_var_name, new VTable(&table)); @@ -1193,7 +1218,6 @@ static void _foreach(Request& r, MethodP break; } } - table.set_current(saved_current); } static void update_cell(HashStringValue::key_type aname, HashStringValue::value_type avalue, VTable *dest) { @@ -1219,11 +1243,10 @@ static void _append(Request& r, MethodPa HashStringValue* hash=params[0].get_hash(); if(hash){ + Temp_current tc(table); table+=new ArrayString(); - size_t saved_current=table.current(); table.set_current(table.count()-1); hash->for_each(update_cell, &vtable); - table.set_current(saved_current); } else { table+=row_from_string(r, params[0]); } @@ -1429,7 +1452,7 @@ static void _columns(Request& r, MethodP Table& source_table=GET_SELF(r, VTable).table(); if(Table::columns_type source_columns=source_table.columns()) { - for(Array_iterator i(*source_columns); i.has_next(); ) { + for(Array_iterator i(*source_columns); i; ) { Table::element_type result_row(new ArrayString); *result_row+=i.next(); result_table+=result_row; @@ -1474,7 +1497,7 @@ static void _select(Request& r, MethodPa if(offset<0) offset+=size; if(size && limit>0 && offset>=0 && (size_t)offsetcount(); i++) { + for(size_t i=0; icount(); i++) { const String *column = columns->get(i); if(Value* vto=names->get(*column)){ if(const String *sto=vto->get_string()) @@ -1534,7 +1556,7 @@ static void _rename(Request& r, MethodPa } } } else if(name_from){ - for(int i=0; icount(); i++) { + for(size_t i=0; icount(); i++) { const String *column = columns->get(i); if(*column == *name_from) columns->put(i, name_to); @@ -1592,6 +1614,10 @@ MTable::MTable(): Methoded("table") { // ^table.hash[key field name][value field name(s) string/table] add_native_method("hash", Method::CT_DYNAMIC, _hash, 1, 3); + // ^table.cells[] + // ^table.cells(limit) + add_native_method("cells", Method::CT_DYNAMIC, _cells, 0, 1); + // ^table.sort{string-key-maker} ^table.sort{string-key-maker}[desc|asc] // ^table.sort(numeric-key-maker) ^table.sort(numeric-key-maker)[desc|asc] add_native_method("sort", Method::CT_DYNAMIC, _sort, 1, 2);