Can a structure be defined dynamically by csv headers

Just starting out? Need help? Post your questions and find answers here.
craig7
User
User
Posts: 35
Joined: Thu Sep 23, 2021 2:49 pm

Can a structure be defined dynamically by csv headers

Post by craig7 »

Can a structure, such as the example below from the PureBasic book be defined by the column headers in a CSV imported into PureBasic... or in any way by the user of the software. I guess what I am asking is, can the code itself be made to alter in response to what the user does.

Structure FISH
Kind.s
Weight.s
Color.s

EndStructure

//I would then like to add each row from the csv - a more automated version of the following from the book?

Dim FishInTank.FISH(2)
FishInTank(0)\Kind = "Clown Fish"
FishInTank(0)\Weight = "4 oz."
FishInTank(0)\Color = "Red, White and Black"
FishInTank(1)\Kind = "Box Fish"
FishInTank(1)\Weight = "1 oz."
FishInTank(1)\Color = "Yellow"
FishInTank(2)\Kind = "Sea Horse"
FishInTank(2)\Weight = "2 oz."
FishInTank(2)\Color = "Green"
DarkDragon
Addict
Addict
Posts: 2345
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Re: Can a structure be defined dynamically by csv headers

Post by DarkDragon »

Structures have to be defined at compile time. For that use case hashmaps are typically used.
bye,
Daniel
User avatar
skywalk
Addict
Addict
Posts: 4218
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Can a structure be defined dynamically by csv headers

Post by skywalk »

You can use in memory database tables created dynamically.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
the.weavster
Addict
Addict
Posts: 1577
Joined: Thu Jul 03, 2003 6:53 pm
Location: England

Re: Can a structure be defined dynamically by csv headers

Post by the.weavster »

I think the JSON commands give you the closest thing to dynamically changing structures.
User avatar
mk-soft
Always Here
Always Here
Posts: 6248
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Can a structure be defined dynamically by csv headers

Post by mk-soft »

You can use LinkedList ...

Found an old example but it work ;)
https://www.purebasic.fr/german/viewtop ... 82#p310782
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
craig7
User
User
Posts: 35
Joined: Thu Sep 23, 2021 2:49 pm

Re: Can a structure be defined dynamically by csv headers

Post by craig7 »

mk-soft wrote: Mon Mar 04, 2024 7:20 pm You can use LinkedList ...

Found an old example but it work ;)
https://www.purebasic.fr/german/viewtop ... 82#p310782
Thanks !
craig7
User
User
Posts: 35
Joined: Thu Sep 23, 2021 2:49 pm

Re: Can a structure be defined dynamically by csv headers

Post by craig7 »

DarkDragon wrote: Mon Mar 04, 2024 4:50 pm Structures have to be defined at compile time. For that use case hashmaps are typically used.
Do you mean hashtable / map?
craig7
User
User
Posts: 35
Joined: Thu Sep 23, 2021 2:49 pm

Re: Can a structure be defined dynamically by csv headers

Post by craig7 »

skywalk wrote: Mon Mar 04, 2024 6:10 pm You can use in memory database tables created dynamically.
I was thinking about using the DB library... but does that not then creates an external dependency on SQLite or whatever DB is being used? Would prefer to use something built into PureBasic for reliability.
User avatar
skywalk
Addict
Addict
Posts: 4218
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Can a structure be defined dynamically by csv headers

Post by skywalk »

sqlite3.lib is statically loaded with your app.exe. No dependency, unless you need a feature not in the current lib. Then you would dynamically load sqlite3.dll of your compilation.
Fred said we can even statically load our own VS2022 versions of sqlite3.lib, but I have not succeeded yet.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
craig7
User
User
Posts: 35
Joined: Thu Sep 23, 2021 2:49 pm

Re: Can a structure be defined dynamically by csv headers

Post by craig7 »

skywalk wrote: Tue Mar 05, 2024 1:12 am sqlite3.lib is statically loaded with your app.exe. No dependency, unless you need a feature not in the current lib. Then you would dynamically load sqlite3.dll of your compilation.
Fred said we can even statically load our own VS2022 versions of sqlite3.lib, but I have not succeeded yet.
Ok great that is another option then thanks.
infratec
Always Here
Always Here
Posts: 7619
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Can a structure be defined dynamically by csv headers

Post by infratec »

infratec
Always Here
Always Here
Posts: 7619
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Can a structure be defined dynamically by csv headers

Post by infratec »

A quick implementation with an user function:

Code: Select all

EnableExplicit

Structure IndexArray
  *Index[0]
EndStructure


PrototypeC.l Prototype_CallBack(*pCtx, argc.l, *argv.IndexArray, *colnames.IndexArray)

ImportC "sqlite3.lib" 
  sqlite3_create_function.l(DatabaseID, zFunctionName.p-utf8, nArg.l, eTextRep.l, *pApp, *xFunc, *xStep, *xFinal)
  sqlite3_value_text16(*sqlite3_value)
  sqlite3_context_db_handle.i(*context)
  sqlite3_exec(*db, sql.p-utf8, callback.Prototype_CallBack, *firstArg, *errmsg)
EndImport

#SQLITE_UTF16 = 4




ProcedureC createTableFromCSV(*context, argc.i, *argv.IndexArray)
  
  Protected Filename$, File.i, Line$, FieldCount.i, Table$, SQL$, Field$, *DB, i.i
  
  
  Filename$ = PeekS(sqlite3_value_text16(*argv\Index[0]))
  File = ReadFile(#PB_Any, Filename$)
  If File
    Table$ = GetFilePart(Filename$, #PB_FileSystem_NoExtension)
    
    Line$ = ReadString(File)
    ;Debug Line$
    
    SQL$ = "CREATE TABLE " + Table$ + "("
    
    FieldCount = 1
    Repeat
      Field$ = StringField(Line$, FieldCount, ",")
      If Field$ <> ""
        SQL$ + Trim(Field$) + " TEXT,"
      EndIf
      FieldCount + 1
    Until Field$ = ""
    SQL$ = RTrim(SQL$, ",") + ")"
    ;Debug SQL$
    
    *DB = sqlite3_context_db_handle(*context)
    
    sqlite3_exec(*DB, SQL$, #Null, #Null, #Null)
    
    While Not Eof(File)
      Line$ = ReadString(File)
      SQL$ = "INSERT INTO " + Table$ + " VALUES ("
      
      For i = 1 To FieldCount
        Field$ = StringField(Line$, i, ",")
        SQL$ + Trim(Field$) + ","
      Next i
      SQL$ = RTrim(SQL$, ",") + ")"
      ;Debug SQL$
      
      sqlite3_exec(*DB, SQL$, #Null, #Null, #Null)
    Wend
    
    CloseFile(File)
  EndIf
  
EndProcedure




Define Filename$


UseSQLiteDatabase()

Filename$ = OpenFileRequester("Choose a CSV file", GetPathPart(ProgramFilename()), "CSV|*.csv", 0)
If Filename$

If OpenDatabase(0, ":memory:", "", "")
  
  sqlite3_create_function(DatabaseID(0), "createTableFromCSV",  1, #SQLITE_UTF16, #Null, @createTableFromCSV(), #Null, #Null)
  
  DatabaseUpdate(0, "SELECT createTableFromCSV('" + Filename$ + "')")
  
  If DatabaseQuery(0, "SELECT * FROM Test")
    While NextDatabaseRow(0)
      Debug GetDatabaseString(0, 0) + " " + GetDatabaseString(0, 1) + " " + GetDatabaseString(0, 2)
    Wend
    FinishDatabaseQuery(0)
  Else
    Debug DatabaseError()
  EndIf
  
  
  Debug ""
  Debug "Return as JSON Array:"
  Debug ""
  
  
  If DatabaseQuery(0, "SELECT json_group_array(json_object('ArtistId', ArtistId, 'ArtistName', ArtistName, 'Bio', Bio)) FROM Test")
    While NextDatabaseRow(0)
      Debug GetDatabaseString(0, 0)
    Wend
    FinishDatabaseQuery(0)
  Else
    Debug DatabaseError()
  EndIf
  
  CloseDatabase(0)
Else
  Debug DatabaseError()
EndIf

EndIf
Sample CSV:

Code: Select all

ArtistId,ArtistName,Bio
1,"Joe Satriani",""
2,"Steve Vai",""
3,"The Tea Party",""
4,"Noiseworks",""
5,"Wayne Jury",""
6,"Mr Percival",""
7,"Iron Maiden",""
8,"Atmasphere","Australian jazz band centred around polyrhythms."
9,"Ian Moss",""
10,"Magnum",""
13,"Primus",""
14,"Pat Metheny",""
15,"Frank Gambale",""
16,"Mothers of Invention",""
Can be extended.
Detection of field types
...
Last edited by infratec on Thu Mar 07, 2024 8:27 am, edited 1 time in total.
craig7
User
User
Posts: 35
Joined: Thu Sep 23, 2021 2:49 pm

Re: Can a structure be defined dynamically by csv headers

Post by craig7 »

infratec wrote: Wed Mar 06, 2024 9:50 pm A quick implementation with an user function:

Code: Select all

EnableExplicit

Structure IndexArray
  *Index[0]
EndStructure


PrototypeC.l Prototype_CallBack(*pCtx, argc.l, *argv.IndexArray, *colnames.IndexArray)

ImportC "sqlite3.lib" 
  sqlite3_create_function.l(DatabaseID, zFunctionName.p-utf8, nArg.l, eTextRep.l, *pApp, *xFunc, *xStep, *xFinal)
  sqlite3_value_text16(*sqlite3_value)
  sqlite3_context_db_handle.i(*context)
  sqlite3_exec(*db, sql.p-utf8, callback.Prototype_CallBack, *firstArg, *errmsg)
EndImport

#SQLITE_UTF16 = 4




ProcedureC createTableFromCSV(*context, argc.i, *argv.IndexArray)
  
  Protected Filename$, File.i, Line$, FieldCount.i, Table$, SQL$, Field$, *DB, i.i
  
  
  Filename$ = PeekS(sqlite3_value_text16(*argv\Index[0]))
  File = ReadFile(#PB_Any, Filename$)
  If File
    Table$ = GetFilePart(Filename$, #PB_FileSystem_NoExtension)
    
    Line$ = ReadString(File)
    ;Debug Line$
    
    SQL$ = "CREATE TABLE " + Table$ + "("
    
    FieldCount = 1
    Repeat
      Field$ = StringField(Line$, FieldCount, ",")
      If Field$ <> ""
        SQL$ + Trim(Field$) + " TEXT,"
      EndIf
      FieldCount + 1
    Until Field$ = ""
    SQL$ = RTrim(SQL$, ",") + ")"
    ;Debug SQL$
    
    *DB = sqlite3_context_db_handle(*context)
    
    sqlite3_exec(*DB, SQL$, #Null, #Null, #Null)
    
    While Not Eof(File)
      Line$ = ReadString(File)
      SQL$ = "INSERT INTO " + Table$ + " VALUES ("
      
      For i = 1 To FieldCount
        Field$ = StringField(Line$, i, ",")
        SQL$ + Trim(Field$) + ","
      Next i
      SQL$ = RTrim(SQL$, ",") + ")"
      ;Debug SQL$
      
      sqlite3_exec(*DB, SQL$, #Null, #Null, #Null)
    Wend
    
    CloseFile(File)
  EndIf
  
EndProcedure


UseSQLiteDatabase()



If OpenDatabase(0, ":memory:", "", "")
  
  sqlite3_create_function(DatabaseID(0), "createTableFromCSV",  1, #SQLITE_UTF16, #Null, @createTableFromCSV(), #Null, #Null)
  
  DatabaseUpdate(0, "SELECT createTableFromCSV('c:\tmp\PureBasic\csvtest\Test.csv')")
  Debug DatabaseError()
  
  If DatabaseQuery(0, "SELECT * FROM Test")
    While NextDatabaseRow(0)
      Debug GetDatabaseString(0, 0) + " " + GetDatabaseString(0, 1) + " " + GetDatabaseString(0, 2)
    Wend
    FinishDatabaseQuery(0)
  Else
    Debug DatabaseError()
  EndIf
  
  CloseDatabase(0)
Else
  Debug DatabaseError()
EndIf
Sample CSV:

Code: Select all

ArtistId,ArtistName,Bio
1,"Joe Satriani",""
2,"Steve Vai",""
3,"The Tea Party",""
4,"Noiseworks",""
5,"Wayne Jury",""
6,"Mr Percival",""
7,"Iron Maiden",""
8,"Atmasphere","Australian jazz band centred around polyrhythms."
9,"Ian Moss",""
10,"Magnum",""
13,"Primus",""
14,"Pat Metheny",""
15,"Frank Gambale",""
16,"Mothers of Invention",""
Can be extended.
Detection of field types
...
Oh thanks for the example, that will be very useful.
User avatar
skywalk
Addict
Addict
Posts: 4218
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Can a structure be defined dynamically by csv headers

Post by skywalk »

Wow, another great example from infratec. 8)
I wondered how to return an array from SQLite in a userfunction.
This could help solve a complicated 2D query.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
infratec
Always Here
Always Here
Posts: 7619
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Can a structure be defined dynamically by csv headers

Post by infratec »

I extended the listing above.

It returns now also the content of the table as JSON array.
Post Reply