Annotation of parser3/src/types/pa_vtable.C, revision 1.59

1.1       parser      1: /** @file
                      2:        Parser: @b table class.
                      3: 
1.59    ! moko        4:        Copyright (c) 2001-2026 Art. Lebedev Studio (https://www.artlebedev.com)
1.51      moko        5:        Authors: Konstantin Morshnev <moko@design.ru>, Alexandr Petrosian <paf@design.ru>
1.14      paf         6: */
1.1       parser      7: 
                      8: #include "pa_vtable.h"
                      9: #include "pa_vstring.h"
1.5       parser     10: #include "pa_vhash.h"
1.22      paf        11: #include "pa_vvoid.h"
1.46      moko       12: #include "pa_request.h"
1.1       parser     13: 
1.59    ! moko       14: volatile const char * IDENT_PA_VTABLE_C="$Id: pa_vtable.C,v 1.58 2025/05/26 00:52:15 moko Exp $" IDENT_PA_VTABLE_H;
1.37      moko       15: 
1.3       parser     16: #ifndef DOXYGEN
1.1       parser     17: struct Record_info {
1.22      paf        18:        Table* table;
                     19:        HashStringValue* hash;
1.1       parser     20: };
1.3       parser     21: #endif
1.29      misha      22: 
                     23: static void store_column_item_to_hash(const String* column_name, Record_info *info) {
                     24:        const String* column_item=info->table->item(*column_name);
1.53      moko       25:        info->hash->put(*column_name, column_item  ? new VString(*column_item) : VString::empty() );
1.1       parser     26: }
1.29      misha      27: 
1.22      paf        28: Value* VTable::fields_element() {
1.29      misha      29:        Value& result=*new VHash;
1.22      paf        30:        Table& ltable=table();
1.29      misha      31:        if(!ltable.count())
                     32:                return &result;
                     33: 
                     34:        HashStringValue* hash=result.get_hash();
                     35: 
                     36:        if(Table::columns_type columns=ltable.columns()) { // named
                     37:                Record_info record_info={&ltable, hash};
1.1       parser     38:                columns->for_each(store_column_item_to_hash, &record_info);
1.29      misha      39:        } else { // nameless
                     40:                size_t row_size=ltable[ltable.current()]->count(); // number of columns in current row
                     41:                for(size_t index=0; index<row_size; index++){
                     42:                        const String* column_item=ltable.item(index);
1.58      moko       43:                        hash->put(String::Body::uitoa(index), column_item ? new VString(*column_item) : VString::empty() );
1.29      misha      44:                }
1.1       parser     45:        }
1.29      misha      46: 
                     47:        return &result;
1.1       parser     48: }
                     49: 
1.31      misha      50: Value* VTable::get_element(const String& aname) {
1.1       parser     51:        // fields
1.45      moko       52:        if(SYMBOLS_EQ(aname,FIELDS_SYMBOL))
1.1       parser     53:                return fields_element();
                     54: 
1.44      moko       55: #ifdef FEATURE_GET_ELEMENT4CALL
1.40      moko       56:        // columns first
                     57:        if(ftable) {
                     58:                int index=ftable->column_name2index(aname, false);
                     59:                if(index>=0) // column aname|number valid
                     60:                {
                     61:                        const String* string=ftable->item(index); // there is such column
1.53      moko       62:                        return string ? new VString(*string) : VString::empty();
1.40      moko       63:                }
                     64:        }
                     65: 
1.42      moko       66: #ifndef OPTIMIZE_BYTECODE_GET_ELEMENT__SPECIAL
1.44      moko       67:        // CLASS, CLASS_NAME
1.31      misha      68:        if(Value* result=VStateless_object::get_element(aname))
1.2       parser     69:                return result;
1.42      moko       70: #endif
1.2       parser     71: 
1.40      moko       72:        throw Exception(PARSER_RUNTIME, &aname, "column not found");
                     73: }
                     74: 
                     75: Value* VTable::get_element4call(const String& aname) {
1.44      moko       76:        // methods
1.52      moko       77:        if(Value* result=VStateless_object::get_element(aname))
                     78:                return result;
                     79: 
                     80:        return bark("%s method not found", &aname);
1.44      moko       81: }
1.40      moko       82: 
1.44      moko       83: #else
1.40      moko       84:        // methods first
                     85:        if(Value* result=VStateless_object::get_element(aname))
                     86:                return result;
                     87: 
1.1       parser     88:        // columns
                     89:        if(ftable) {
1.16      paf        90:                int index=ftable->column_name2index(aname, false);
                     91:                if(index>=0) // column aname|number valid
1.32      pretende   92:                {
                     93:                        const String* string=ftable->item(index); // there is such column
1.53      moko       94:                        return new string ? VString(*string) : VString::empty();
1.32      pretende   95:                }
1.1       parser     96:        }
                     97: 
1.39      moko       98:        throw Exception(PARSER_RUNTIME, &aname, "column not found");
1.1       parser     99: }
1.44      moko      100: #endif
1.33      misha     101: 
1.39      moko      102: const VJunction* VTable::put_element(const String& aname, Value* avalue) {
                    103:        if(ftable) {
                    104:                int index=ftable->column_name2index(aname, false);
                    105:                if(index>=0) // column aname|number valid
                    106:                {
1.46      moko      107:                        if(index > pa_loop_limit)
1.39      moko      108:                                throw Exception(PARSER_RUNTIME, &aname, "too big column number");
1.48      moko      109:                        const String *svalue=avalue->get_string();
                    110:                        if(!svalue)
                    111:                                throw Exception(PARSER_RUNTIME, 0, "column value must be string compatible");
                    112:                        ftable->put_item(index, svalue);
1.49      moko      113:                        return 0;
1.39      moko      114:                }
                    115:        }
                    116: 
                    117:        throw Exception(PARSER_RUNTIME, &aname, "column not found");
                    118: }
1.36      moko      119: 
                    120: String& VTable::get_json_string_array(String& result, const char *indent) {
                    121:        // [
                    122:        //              ["c1",  "c2",  "c3"  ...] || null (for nameless),
                    123:        //              ["v11", "v12", "v13" ...],
                    124:        //              ["v21", "v22", "v23" ...],
                    125:        //              ...
                    126:        // ]
1.33      misha     127:        Table& ltable=table();
1.35      moko      128: 
1.36      moko      129:        // columns
                    130:        if(ltable.columns()){
                    131:                // named
                    132:                indent ? result << "\n\t" << indent << "[\"" : result << "\n[\"";
                    133: 
                    134:                bool need_delim=false;
1.54      moko      135:                for(Array_iterator<const String*> c(*ltable.columns()); c; ) {
1.36      moko      136:                        if(need_delim)
                    137:                                result << "\",\"";
                    138:                        result.append(*c.next(), String::L_JSON, true/*forced lang*/);
                    139:                        need_delim=true;
                    140:                }
                    141:                result << "\"]";
                    142:        } else {
                    143:                // nameless
                    144:                indent ? result << "\n\t" << indent << "null" : result << "\nnull";
                    145:        }
                    146: 
                    147:        // data
                    148:        if(ltable.count()){
                    149:                result << ",";
1.54      moko      150:                for(Array_iterator<ArrayString*> r(ltable); r; ) {
1.36      moko      151:                        indent ? result << "\n\t" << indent << "[\"" : result << "\n[\"";
1.33      misha     152:                        bool need_delim=false;
1.54      moko      153:                        for(Array_iterator<const String*> c(*r.next()); c; ) {
1.33      misha     154:                                if(need_delim)
                    155:                                        result << "\",\"";
                    156:                                result.append(*c.next(), String::L_JSON, true/*forced lang*/);
                    157:                                need_delim=true;
                    158:                        }
1.54      moko      159:                        r ? result << "\"]," : result << "\"]";
1.35      moko      160:                }
1.36      moko      161:        }
                    162: 
                    163:        result << "\n" << indent; 
                    164:        return result;
                    165: }
                    166: 
                    167: String& VTable::get_json_string_object(String& result, const char *indent) {
                    168:        // [
                    169:        //              {"c1":"v11", "c2":"v12", "c3":"v13"},
                    170:        //              {"c1":"v21", "c2":"v22", "c3":"v23"},
                    171:        //              ...
                    172:        // ]
                    173:        Table& ltable=table();
                    174:        ArrayString* columns=ltable.columns();
                    175:        size_t columns_count = (columns) ? columns->count() : 0;
                    176: 
1.54      moko      177:        for(Array_iterator<ArrayString*> r(ltable); r; ) {
1.36      moko      178:                indent ? result << "\n\t" << indent << "{\"" : result << "\n{\"";
1.33      misha     179: 
1.36      moko      180:                ArrayString* row=r.next();
                    181:                for(size_t index=0; index<row->count(); index++){
                    182:                        if(index)
                    183:                                result << "\",\"";
1.56      moko      184:                        result.append(index < columns_count ? *columns->get(index) : String(pa_uitoa(index)), String::L_JSON, true/*forced lang*/);
1.36      moko      185:                        result << "\":\"";
                    186:                        result.append(*row->get(index), String::L_JSON, true/*forced lang*/);
1.33      misha     187:                }
1.54      moko      188:                r ? result << "\"}," : result << "\"}\n" << indent;
1.36      moko      189:        }
                    190:        return result;
                    191: }
                    192: 
                    193: String& VTable::get_json_string_compact(String& result, const char *indent) {
                    194:        // [
                    195:        //              "v11",
                    196:        //              ["v21", "v22", "v23" ...],
                    197:        //              ...
                    198:        // ]
                    199:        Table& ltable=table();
                    200: 
1.54      moko      201:        for(Array_iterator<ArrayString*> r(ltable); r; ) {
1.36      moko      202:                ArrayString& line=*r.next();
                    203:                if (line.count()==1){
                    204:                        indent ? result << "\n\t" << indent << "\"" : result << "\n\"";
1.33      misha     205: 
1.36      moko      206:                        result.append(*line[0], String::L_JSON, true/*forced lang*/);
1.54      moko      207:                        r ? result << "\"," : result << "\"\n" << indent;
1.36      moko      208:                } else {
                    209:                        indent ? result << "\n\t" << indent << "[\"" :  result << "\n[\"";
1.33      misha     210: 
1.36      moko      211:                        bool need_delim=false;
1.54      moko      212:                        for(Array_iterator<const String*> c(line); c; ) {
1.36      moko      213:                                if(need_delim)
1.33      misha     214:                                        result << "\",\"";
1.36      moko      215:                                result.append(*c.next(), String::L_JSON, true/*forced lang*/);
                    216:                                need_delim=true;
1.33      misha     217:                        }
1.54      moko      218:                        r ? result << "\"]," : result  << "\"]\n" << indent;
1.36      moko      219:                }
                    220:        }
                    221:        return result;
                    222: }
                    223: 
1.38      moko      224: const String* VTable::get_json_string(Json_options& options) {
1.36      moko      225:        String* result = new String("[", String::L_AS_IS);
1.33      misha     226: 
1.38      moko      227:        switch(options.table){
1.36      moko      228:        case Json_options::T_ARRAY:
1.38      moko      229:                result=&get_json_string_array(*result, options.indent);
1.36      moko      230:                break;
                    231:        case Json_options::T_OBJECT:
1.38      moko      232:                result=&get_json_string_object(*result, options.indent);
1.36      moko      233:                break;
                    234:        case Json_options::T_COMPACT:
1.38      moko      235:                result=&get_json_string_compact(*result, options.indent);
1.36      moko      236:                break;
1.33      misha     237:        }
                    238: 
1.36      moko      239:        *result << "]";
                    240:        return result;
                    241: }

E-mail: