Recent

Author Topic: Use an Ordinal in constant  (Read 3796 times)

Hansvb

  • Sr. Member
  • ****
  • Posts: 397
Use an Ordinal in constant
« on: July 20, 2021, 07:20:03 pm »
Hi,

How can I use an ordinal type in a constant? I have this:


Code: Pascal  [Select][+][-]
  1.       type
  2.         TTableNames = (SETTINGS_META);  //Ordinal (Enumerated types)
  3.  
  4.       var
  5.       TableName :     TTableNames;
  6.  
  7.       const creMetaTbl = 'CREATE TABLE IF NOT EXISTS '+ TableName.SETTINGS_META + '(' +
  8.                                 'KEY                VARCHAR(50)  UNIQUE  ,' +
  9.                                 'VALUE              VARCHAR(255))';
  10.  

This gives the error: illegal expression.

OS Windows 10 - Lazarus 2.0.12

madref

  • Hero Member
  • *****
  • Posts: 861
  • ..... A day not Laughed is a day wasted !!
    • Nursing With Humour
Re: Use an Ordinal in constant
« Reply #1 on: July 20, 2021, 07:23:21 pm »
shouldn't there be a space between ten '(' else the tablename will be something like '10(Key......'
' (' ....
Code: Pascal  [Select][+][-]
  1. const creMetaTbl = 'CREATE TABLE IF NOT EXISTS '+ TableName.SETTINGS_META + ' (' +  
  2.                               'KEY                VARCHAR(50)  UNIQUE  ,' +
  3.                               'VALUE              VARCHAR(255))';
  4.  


If you have an illegal expression make the expression visible on your screen with
Code: Pascal  [Select][+][-]
  1. ShowMessage (string);
then you can see what you have done
« Last Edit: July 20, 2021, 07:26:32 pm by madref »
You treat a disease, you win, you lose.
You treat a person and I guarantee you, you win, no matter the outcome.

Lazarus Trunc.git [2.3.0 Rev. 65550] / FPC Trunc.git [3.3.1]
Mac OS X Big Sur

Hansvb

  • Sr. Member
  • ****
  • Posts: 397
Re: Use an Ordinal in constant
« Reply #2 on: July 20, 2021, 07:38:17 pm »
How does that work in a constant?
The constant gives the illegal expression error.
OS Windows 10 - Lazarus 2.0.12

y.ivanov

  • Full Member
  • ***
  • Posts: 232
Re: Use an Ordinal in constant
« Reply #3 on: July 20, 2021, 08:05:42 pm »
Hi,

How can I use an ordinal type in a constant? I have this:


Code: Pascal  [Select][+][-]
  1.       type
  2.         TTableNames = (SETTINGS_META);  //Ordinal (Enumerated types)
  3.  
  4.       var
  5.       TableName :     TTableNames;
  6.  
  7.       const creMetaTbl = 'CREATE TABLE IF NOT EXISTS '+ TableName.SETTINGS_META + '(' +
  8.                                 'KEY                VARCHAR(50)  UNIQUE  ,' +
  9.                                 'VALUE              VARCHAR(255))';
  10.  

This gives the error: illegal expression.

You can't. It is illegal to concatenate string with other than string or character.

Kays

  • Sr. Member
  • ****
  • Posts: 357
  • Whasup!?
    • KaiBurghardt.de
Re: Use an Ordinal in constant
« Reply #4 on: July 20, 2021, 08:39:57 pm »
How can I use an ordinal type in a constant?
Just like that.
Code: Pascal  [Select][+][-]
  1. program ordinalValueDemo(input, output, stdErr);
  2. type
  3.         resolution = (HD, HDDeluxe, HDPremium);
  4. const
  5.         standardResolution = HD;
  6. begin
  7. end.

I have this:
Uhm, what do you want to achieve by this design? If you want to ensure there are no duplicate table names, this is rather a task of your DBMS, not your Pascal program.
The FPC’s standard RTL can convert the names of ordinal value members at run‑time using write/writeLn/writeStr, but there ain’t no function nor syntax that does the same at compile-time (i. e. in constant definitions). For example:
Code: Pascal  [Select][+][-]
  1. program enumerationConversionDemo(input, output, stdErr);
  2. type
  3.         table = (settingsMeta);
  4. const
  5.         createTable = 'create table if not exists ';
  6. var
  7.         query: string;
  8. begin
  9.         writeStr(query, createTable, settingsMeta,
  10.                 ' (key varchar(50) unique, value varchar(255));');
  11.         query := upcase(query);
  12.        
  13.         writeLn(query);
  14. end.
Yours Sincerely
Kai Burghardt

Hansvb

  • Sr. Member
  • ****
  • Posts: 397
Re: Use an Ordinal in constant
« Reply #5 on: July 20, 2021, 09:34:34 pm »
Quote
Uhm, what do you want to achieve by this design?

What i would like is that i have all my table names in one place in one list. So if i later want to change a table name i have to change it in one place and not in a lot of places. I thought that ordinals where the way to go.
If that is not possible then i just have to type them where i need them.
OS Windows 10 - Lazarus 2.0.12

y.ivanov

  • Full Member
  • ***
  • Posts: 232
Re: Use an Ordinal in constant
« Reply #6 on: July 20, 2021, 10:19:14 pm »
Quote
Uhm, what do you want to achieve by this design?

What i would like is that i have all my table names in one place in one list. So if i later want to change a table name i have to change it in one place and not in a lot of places. I thought that ordinals where the way to go.
If that is not possible then i just have to type them where i need them.

Code: Pascal  [Select][+][-]
  1. type
  2.   TTableOrd = (toTable1, toTable2, toTable3);
  3.  
  4. const
  5.   TableNames: array[TTableOrd] of String = (
  6.     {toTable1} 'Table1',
  7.     {toTable2} 'Table2',
  8.     {toTable3} 'Table3'
  9.   );
  10.  
  11.   function GetCreateSQL(ATable: TTableOrd): String;
  12.   begin
  13.     Result := 'CREATE TABLE IF NOT EXISTS ' + TableNames[ATable] + ' (' +
  14.                                 'KEY                VARCHAR(50)  UNIQUE  ,' +
  15.                                 'VALUE              VARCHAR(255))';
  16.   end;
  17.  
  18.   //....
  19.   GetCreateSQL(toTable1);

That is: a mapping table from ordinal to string.
Is that suitable for the purpose?

At the other hand, probably you'll want a different columns for each table, so you'll need yet another dim for the  + '(key varchar(50) unique, value varchar(255))' thing. Something like:
Code: Pascal  [Select][+][-]
  1. const
  2.   TableNames: array[TTableOrd, 1..2] of String = (
  3.     {toTable1} ('Table1', '(key varchar(50) unique, value varchar(255))'),
  4.     {toTable2} ('Table2', '(key varchar(50) unique, ...)'),
  5.     {toTable3} ('Table3', '(key varchar(50) unique, ...)')
  6.   );
  7.  
  8.   function GetCreateSQL(ATable: TTableOrd): String;
  9.   begin
  10.     Result := 'CREATE TABLE IF NOT EXISTS ' + TableNames[ATable, 1] + ' ' + TableNames[ATable, 2];
  11.   end;
  12.  

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 988
    • Lebeau Software
Re: Use an Ordinal in constant
« Reply #7 on: July 21, 2021, 01:52:07 am »
What i would like is that i have all my table names in one place in one list. So if i later want to change a table name i have to change it in one place and not in a lot of places.

An admirable goal.

I thought that ordinals where the way to go.

Only if the actual names are stored in a separate array, and the ordinals are used as indexes into that array, like how y.ivanov showed.

The alternative is to use string constants instead.  You could store them as individual constants in a separate unit, eg:

Code: Pascal  [Select][+][-]
  1. unit TableNames;
  2.  
  3. interface
  4.  
  5. const
  6.   SETTINGS_META = 'SETTINGS_META';
  7.   ...
  8.  
  9. implementation
  10.  
  11. end.

Code: Pascal  [Select][+][-]
  1. uses
  2.   ..., TableNames;
  3.  
  4. const creMetaTbl = 'CREATE TABLE IF NOT EXISTS ' + TableNames.SETTINGS_META + '(' +
  5.                                 'KEY                VARCHAR(50)  UNIQUE  ,' +
  6.                                 'VALUE              VARCHAR(255))';

Or, as constant members of a class, eg:

Code: Pascal  [Select][+][-]
  1. type
  2.   TTableNames = class
  3.   public
  4.     const SETTINGS_META = 'SETTINGS_META';
  5.     ...
  6.   end;
  7.  
  8. ...
  9.  
  10. const creMetaTbl = 'CREATE TABLE IF NOT EXISTS ' + TTableNames.SETTINGS_META + '(' +
  11.                                 'KEY                VARCHAR(50)  UNIQUE  ,' +
  12.                                 'VALUE              VARCHAR(255))';
« Last Edit: July 21, 2021, 01:54:58 am by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

Kays

  • Sr. Member
  • ****
  • Posts: 357
  • Whasup!?
    • KaiBurghardt.de
Re: Use an Ordinal in constant
« Reply #8 on: July 21, 2021, 02:21:03 pm »
[…] You could store them as individual constants in a separate unit, eg: […]
I’m not a fan of duplicating data. Per se, I like to create enumeration data types as often as possible, because they create incompatibilites, i. e. I can use them as formal parameters and thus easily restrict the range of acceptable values.

I’d really rather write a conversion function, or even a simple type helper:
Code: Pascal  [Select][+][-]
  1. {$modeSwitch typeHelpers+}
  2. type
  3.         table = (settingsMeta);
  4.         tableHelper = type helper for table
  5.                         function asString(): string;
  6.                 end;
  7.  
  8. function tableHelper.asString(): string;
  9. begin
  10.         writeStr(asString, self);
  11.         asString := upCase(asString);
  12. end;
It’s just a few lines of code. Then you can write settingsMeta.asString. This will work fine for all table names that are shorter than 127 characters (FPC’s limit for significant characters in identifiers). This kind of implementation will “nicely” crash if you are attempting to convert the name of a “non‑existent” table (e. g. table(42).asString).
Yours Sincerely
Kai Burghardt

 

TinyPortal © 2005-2018