OOP, templates and macros in mql5, subtleties and uses - page 28

 
Maxim Kuznetsov:

I remember that in SQLite, field types are optional and you don't have to worry about specifying and casting types. It is "Lite" for a reason.

you can split a long query into 3-4-5 ones :-)

BEGIN TRANSACTION

INSERT INTO myTable VALUES (...); --- тут можно получить PrimaryKey

UPDATE myTable .... ; --- обновить по Primary

UPDATE myTable ...  ; --- ещё...

COMMIT ; --- это если все запросы удачны.. иначе ROLLBACK

it's from the old memory, so you should check in the help

i would like to have a reproducible query code, it will take a long time to google, i've worked with a database occasionally - i have a problem, i googled it, i solved it - but i would like to see a failed database query

 
Vladimir Simakov:

Your particular problem should be solved like this:

string MakeRequest(string md5txt){
   static ENUM_STATISTICS intIndex[]={STAT_CONPROFITMAX_TRADES,
                                      STAT_MAX_CONPROFIT_TRADES,
                                      STAT_CONLOSSMAX_TRADES,
                                      STAT_MAX_CONLOSS_TRADES,
                                      STAT_DEALS,
                                      STAT_TRADES,
                                      STAT_PROFIT_TRADES,
                                      STAT_LOSS_TRADES,
                                      STAT_SHORT_TRADES,
                                      STAT_LONG_TRADES,
                                      STAT_PROFIT_SHORTTRADES,
                                      STAT_PROFIT_LONGTRADES,
                                      STAT_PROFITTRADES_AVGCON,
                                      STAT_LOSSTRADES_AVGCON};
   string ret="INSERT INTO \"TesterStatistics\" + StringFormat(" set md5= %d ,md5txt),
   for (int i=0,ii=0;i<=STAT_LOSSTRADES_AVGCON;++i){
      ret+=",";
      if (i==intIndex[ii]){
         ret+=StringFormat("%s = %d,",EnumToString((ENUM_STATISTICS)i),(int)TesterStatistics((ENUM_STATISTICS)i) ));
         ++ii;}
      else ret+=StringFormat("%s =%G",EnumToString((ENUM_STATISTICS),i),TesterStatistics((ENUM_STATISTICS)i));}
   return ret;}
   
DatabaseExecute(handleDB, MakeRequest("md5txt"));

a small fix, with more brackets to fix :-)
the main idea is not to use UPDATE x VALUES (), but UPDATE x SET name1=value1,name2=value2. To make the query work correctly when the database structure is changed and not depend on the order of the fields listed

 

there is approximately the following code (I read text fields from database and want to convert into enum)

class MyClass
{
public:
   enum A            {Aq, Aw, Ae, Ar, At, Ay};
   enum B            {Bq, Bw, Be};
   enum C            {Cq, Cw, Ce, Cr};

   static bool       txtToEnumA(const string txt, A &result);
   static bool       txtToEnumB(const string txt, B &result);
   static bool       txtToEnumC(const string txt, C &result);
};
//+------------------------------------------------------------------+
static bool MyClass::txtToEnumA(const string txt, A &result)
{
   for(int i = 0; i <= (int)A::Ay; i++)
   {
      if(StringCompare(EnumToString((A)i), txt) == 0)
      {
         result = (MyClass::A)i;
         return(true);
      }
   }
   return(false);
}
//+------------------------------------------------------------------+
static bool MyClass::txtToEnumB(const string txt, B &result)
{
   for(int i = 0; i <= (int)B::Be; i++)
   {
      if(StringCompare(EnumToString((B)i), txt) == 0)
      {
         result = (MyClass::B)i;
         return(true);
      }
   }
   return(false);
}
//+------------------------------------------------------------------+
static bool MyClass::txtToEnumC(const string txt, C &result)
{
   for(int i = 0; i <= (int)C::Cr; i++)
   {
      if(StringCompare(EnumToString((A)i), txt) == 0)
      {
         result = (MyClass::C)i;
         return(true);
      }
   }
   return(false);
}
//+------------------------------------------------------------------+
void OnStart()
{
   MyClass::A a;
   MyClass::B b;
   MyClass::C c;
   string txt[] = {"Aq", "Bw", "No"};

   if(MyClass::txtToEnumA(txt[0], a)) Print(txt[0], " in A = ", EnumToString(a));
   else Print("Error, ", txt[0], " not in A");

   if(MyClass::txtToEnumB(txt[1], b)) Print(txt[1], " in B = ", EnumToString(b));
   else Print("Error, ", txt[1], " not in B");

   if(MyClass::txtToEnumC(txt[2], c)) Print(txt[2], " in C = ", EnumToString(c));
   else Print("Error, ", txt[2], " not in C");
}
//+------------------------------------------------------------------+

2020.09.01 18:59:02.593 tst (EURUSD,M5) Aq in A = Aq

2020.09.01 18:59:02.593 tst (EURUSD,M5) Bw in B = Bw

2020.09.01 18:59:02.593 tst (EURUSD,M5) Error, No not in C

Everything works, but the question is again about the optimal code:

if any way to write instead of txtToEnumA() , txtToEnumB(), txtToEnumC()

template method ( template )

the problem is different number of elements in the enum

 

What if there is an enum:

enum A            {Aq=10, Aw=9, Ae=8, Ar=7, At=6, Ay=5};

?

 
Dmitry Fedoseev:

What if there is an enum:

?

numbering the enum elements is not a problem, it's not clear what this would do

I have only 4 enumerations, not numbered

the problem is that I may want to add new elements to enumeration - in my code, I will add new elements to NOT the outermost ones - the code will work - I do not like the cumbersomeness of this code


but we are not talking about some universal code for all occasions, we need the current tasks in a template


SZY: i can't do without enumeration - it's convenient, i can equally read data both in source and in database, and in database maybe i want to correct some fields manually.... in general, everything suits me

 
Igor Makanu:

numbering the elements of the enumeration is not a problem, it is not clear what this will do

I have only 4 enumerations, not numbered

the problem is that I may want to add new items to lists - in my code, I will add new items to NOT the outermost ones - the code will work - I do not like the unwieldiness of the code


but we are not talking about some universal code for all occasions, we need the current tasks in a template


SZY: i can't do without enumeration - it's convenient, i can equally read data both in source and in database, and in database maybe i want to correct some fields manually.... everything suits me fine

make a global array and fill it with pairs { EnumToString(x) , x }

struct StringID {

   string str;

   int id;

};

StringID IDS[];

and templates will be unnecessary.
 
Maxim Kuznetsov:

make a global array and fill it with pairs { EnumToString(x) , x }

struct StringID {

   string str;

   int id;

};

StringID IDS[];

and you won't need templates.

Your way of doing it is not much different from mine - it's cumbersome too, and if there will be any changes in the code, you'll have to edit the arrays too.

 

solved my wish this way:

class MyClass
{
public:
   enum A            {Aq, Aw, Ae, Ar, At, Ay};
   enum B            {Bq, Bw, Be};
   enum C            {Cq, Cw, Ce, Cr};
   template<typename T>
   static bool       txtToEnum(const T LastElement, const string txt, T &result);
};
//+------------------------------------------------------------------+
template<typename T>
static bool MyClass::txtToEnum(const T LastElement, const string txt, T &result)
{
   for(int i = 0; i <= (int)LastElement; i++)
   {
      if(StringCompare(EnumToString((T)i), txt) == 0)
      {
         result = (T)i;
         return(true);
      }
   }
   return(false);
}
//+------------------------------------------------------------------+
void OnStart()
{
   MyClass::A a;
   MyClass::B b;
   MyClass::C c;
   string txt[] = {"Aq", "Bw", "No"};

   if(MyClass::txtToEnum(MyClass::Ay, txt[0], a)) Print(txt[0], " in A = ", EnumToString(a));
   else Print("Error, ", txt[0], " not in A");

   if(MyClass::txtToEnum(MyClass::Be, txt[1], b)) Print(txt[1], " in B = ", EnumToString(b));
   else Print("Error, ", txt[1], " not in B");

   if(MyClass::txtToEnum(MyClass::Cr, txt[2], c)) Print(txt[2], " in C = ", EnumToString(c));
   else Print("Error, ", txt[2], " not in C");

}
//+------------------------------------------------------------------+

2020.09.01 22:08:47.417 tst (EURUSD,M5) Aq in A = Aq

2020.09.01 22:08:47.417 tst (EURUSD,M5) Bw in B = Bw

2020.09.01 22:08:47.417 tst (EURUSD,M5) Error, No not in C



I need more defines not to enter LastElement, but on the whole this code is more compact

 
How much it takes to write all sorts of things
Reason: