Annotation of parser3/src/types/pa_vtable.C, revision 1.52
1.1 parser 1: /** @file
2: Parser: @b table class.
3:
1.51 moko 4: Copyright (c) 2001-2023 Art. Lebedev Studio (http://www.artlebedev.com)
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.52 ! moko 14: volatile const char * IDENT_PA_VTABLE_C="$Id: pa_vtable.C,v 1.51 2023/09/26 20:49:13 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.45 moko 25: info->hash->put(*column_name, (column_item && !column_item->is_empty()) ? new VString(*column_item) : new VString() );
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={<able, 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);
43: hash->put(String::Body::Format(index),
44: (column_item && !column_item->is_empty())
45: ?new VString(*column_item)
46: :new VString()
47: );
48: }
1.1 parser 49: }
1.29 misha 50:
51: return &result;
1.1 parser 52: }
53:
1.31 misha 54: Value* VTable::get_element(const String& aname) {
1.1 parser 55: // fields
1.45 moko 56: if(SYMBOLS_EQ(aname,FIELDS_SYMBOL))
1.1 parser 57: return fields_element();
58:
1.44 moko 59: #ifdef FEATURE_GET_ELEMENT4CALL
1.40 moko 60: // columns first
61: if(ftable) {
62: int index=ftable->column_name2index(aname, false);
63: if(index>=0) // column aname|number valid
64: {
65: const String* string=ftable->item(index); // there is such column
66: return new VString(string ? *string : String::Empty);
67: }
68: }
69:
1.42 moko 70: #ifndef OPTIMIZE_BYTECODE_GET_ELEMENT__SPECIAL
1.44 moko 71: // CLASS, CLASS_NAME
1.31 misha 72: if(Value* result=VStateless_object::get_element(aname))
1.2 parser 73: return result;
1.42 moko 74: #endif
1.2 parser 75:
1.40 moko 76: throw Exception(PARSER_RUNTIME, &aname, "column not found");
77: }
78:
79: Value* VTable::get_element4call(const String& aname) {
1.44 moko 80: // methods
1.52 ! moko 81: if(Value* result=VStateless_object::get_element(aname))
! 82: return result;
! 83:
! 84: return bark("%s method not found", &aname);
1.44 moko 85: }
1.40 moko 86:
1.44 moko 87: #else
1.40 moko 88: // methods first
89: if(Value* result=VStateless_object::get_element(aname))
90: return result;
91:
1.1 parser 92: // columns
93: if(ftable) {
1.16 paf 94: int index=ftable->column_name2index(aname, false);
95: if(index>=0) // column aname|number valid
1.32 pretende 96: {
97: const String* string=ftable->item(index); // there is such column
98: return new VString(string ? *string : String::Empty);
99: }
1.1 parser 100: }
101:
1.39 moko 102: throw Exception(PARSER_RUNTIME, &aname, "column not found");
1.1 parser 103: }
1.44 moko 104: #endif
1.33 misha 105:
1.39 moko 106: const VJunction* VTable::put_element(const String& aname, Value* avalue) {
107: if(ftable) {
108: int index=ftable->column_name2index(aname, false);
109: if(index>=0) // column aname|number valid
110: {
1.46 moko 111: if(index > pa_loop_limit)
1.39 moko 112: throw Exception(PARSER_RUNTIME, &aname, "too big column number");
1.48 moko 113: const String *svalue=avalue->get_string();
114: if(!svalue)
115: throw Exception(PARSER_RUNTIME, 0, "column value must be string compatible");
116: ftable->put_item(index, svalue);
1.49 moko 117: return 0;
1.39 moko 118: }
119: }
120:
121: throw Exception(PARSER_RUNTIME, &aname, "column not found");
122: }
1.36 moko 123:
124: String& VTable::get_json_string_array(String& result, const char *indent) {
125: // [
126: // ["c1", "c2", "c3" ...] || null (for nameless),
127: // ["v11", "v12", "v13" ...],
128: // ["v21", "v22", "v23" ...],
129: // ...
130: // ]
1.33 misha 131: Table& ltable=table();
1.35 moko 132:
1.36 moko 133: // columns
134: if(ltable.columns()){
135: // named
136: indent ? result << "\n\t" << indent << "[\"" : result << "\n[\"";
137:
138: bool need_delim=false;
139: for(Array_iterator<const String*> c(*ltable.columns()); c.has_next(); ) {
140: if(need_delim)
141: result << "\",\"";
142: result.append(*c.next(), String::L_JSON, true/*forced lang*/);
143: need_delim=true;
144: }
145: result << "\"]";
146: } else {
147: // nameless
148: indent ? result << "\n\t" << indent << "null" : result << "\nnull";
149: }
150:
151: // data
152: if(ltable.count()){
153: result << ",";
154: for(Array_iterator<ArrayString*> r(ltable); r.has_next(); ) {
155: indent ? result << "\n\t" << indent << "[\"" : result << "\n[\"";
1.33 misha 156: bool need_delim=false;
1.36 moko 157: for(Array_iterator<const String*> c(*r.next()); c.has_next(); ) {
1.33 misha 158: if(need_delim)
159: result << "\",\"";
160: result.append(*c.next(), String::L_JSON, true/*forced lang*/);
161: need_delim=true;
162: }
1.36 moko 163: r.has_next() ? result << "\"]," : result << "\"]";
1.35 moko 164: }
1.36 moko 165: }
166:
167: result << "\n" << indent;
168: return result;
169: }
170:
171: String& VTable::get_json_string_object(String& result, const char *indent) {
172: // [
173: // {"c1":"v11", "c2":"v12", "c3":"v13"},
174: // {"c1":"v21", "c2":"v22", "c3":"v23"},
175: // ...
176: // ]
177: Table& ltable=table();
178: ArrayString* columns=ltable.columns();
179: size_t columns_count = (columns) ? columns->count() : 0;
180:
181: for(Array_iterator<ArrayString*> r(ltable); r.has_next(); ) {
182: indent ? result << "\n\t" << indent << "{\"" : result << "\n{\"";
1.33 misha 183:
1.36 moko 184: ArrayString* row=r.next();
185: for(size_t index=0; index<row->count(); index++){
186: if(index)
187: result << "\",\"";
188: result.append(index < columns_count ? *columns->get(index) : String(format(index, 0)), String::L_JSON, true/*forced lang*/);
189: result << "\":\"";
190: result.append(*row->get(index), String::L_JSON, true/*forced lang*/);
1.33 misha 191: }
1.36 moko 192: r.has_next() ? result << "\"}," : result << "\"}\n" << indent;
193: }
194: return result;
195: }
196:
197: String& VTable::get_json_string_compact(String& result, const char *indent) {
198: // [
199: // "v11",
200: // ["v21", "v22", "v23" ...],
201: // ...
202: // ]
203: Table& ltable=table();
204:
205: for(Array_iterator<ArrayString*> r(ltable); r.has_next(); ) {
206: ArrayString& line=*r.next();
207: if (line.count()==1){
208: indent ? result << "\n\t" << indent << "\"" : result << "\n\"";
1.33 misha 209:
1.36 moko 210: result.append(*line[0], String::L_JSON, true/*forced lang*/);
211: r.has_next() ? result << "\"," : result << "\"\n" << indent;
212: } else {
213: indent ? result << "\n\t" << indent << "[\"" : result << "\n[\"";
1.33 misha 214:
1.36 moko 215: bool need_delim=false;
216: for(Array_iterator<const String*> c(line); c.has_next(); ) {
217: if(need_delim)
1.33 misha 218: result << "\",\"";
1.36 moko 219: result.append(*c.next(), String::L_JSON, true/*forced lang*/);
220: need_delim=true;
1.33 misha 221: }
1.36 moko 222: r.has_next() ? result << "\"]," : result << "\"]\n" << indent;
223: }
224: }
225: return result;
226: }
227:
1.38 moko 228: const String* VTable::get_json_string(Json_options& options) {
1.36 moko 229: String* result = new String("[", String::L_AS_IS);
1.33 misha 230:
1.38 moko 231: switch(options.table){
1.36 moko 232: case Json_options::T_ARRAY:
1.38 moko 233: result=&get_json_string_array(*result, options.indent);
1.36 moko 234: break;
235: case Json_options::T_OBJECT:
1.38 moko 236: result=&get_json_string_object(*result, options.indent);
1.36 moko 237: break;
238: case Json_options::T_COMPACT:
1.38 moko 239: result=&get_json_string_compact(*result, options.indent);
1.36 moko 240: break;
1.33 misha 241: }
242:
1.36 moko 243: *result << "]";
244: return result;
245: }
E-mail: