B4J Question Updating KeyValueStore to allow for multiple tables.

LWGShane

Well-Known Member
Licensed User
Longtime User
I'm in the process of updating KVS to allow the usage of multiple tables. However, I'm encountering the "table doesn't exist" error when running my code.

B4X:
'KeyValueStore: v3.00
Sub Class_Globals
    Private sql1 As SQL
    Private ser As B4XSerializator
End Sub

'Initializes the store and sets the store file.
Public Sub Initialize (Dir As String, FileName As String)
    If sql1.IsInitialized Then sql1.Close
#if B4J
    sql1.InitializeSQLite(Dir, FileName, True)
#else
    sql1.Initialize(Dir, FileName, True)
#end if
End Sub

'creates the main table (if it does not exist)
Public Sub CreateTable (Table As String)
    sql1.ExecNonQuery("CREATE TABLE IF NOT EXISTS " & Table & "(key TEXT PRIMARY KEY, value NONE)")
End Sub

Public Sub Put(Key As String, Value As Object, Table As String)
    sql1.ExecNonQuery2("INSERT OR REPLACE INTO " & Table & " VALUES(?, ?)", Array As Object(Key, ser.ConvertObjectToBytes(Value)))
End Sub

Public Sub Get(Key As String, Table As String) As Object
    Dim rs As ResultSet = sql1.ExecQuery2("SELECT value FROM " & Table & " WHERE key = ?", Array As String(Key))
    Dim result As Object = Null
    If rs.NextRow Then
        result = ser.ConvertBytesToObject(rs.GetBlob2(0))
    End If
    rs.Close
    Return result
End Sub

Public Sub GetDefault(Key As String, DefaultValue As Object, Table As String) As Object
    Dim res As Object = Get(Key, Table)
    If res = Null Then Return DefaultValue
    Return res
End Sub

Public Sub PutEncrypted (Key As String, Value As Object, Password As String, Table As String)
#if B4I
    Dim cipher As Cipher
#else
    Dim cipher As B4XCipher
#end if
    Put(Key, cipher.Encrypt(ser.ConvertObjectToBytes(Value), Password), Table)
End Sub


Public Sub GetEncrypted (Key As String, Password As String, Table As String) As Object
#if B4I
    Dim cipher As Cipher
#else
    Dim cipher As B4XCipher
#end if
    Dim b() As Byte = Get(Key, Table)
    If b = Null Then Return Null
    Return ser.ConvertBytesToObject(cipher.Decrypt(b, Password))
End Sub

#if not(B4J)
Public Sub PutBitmap(Key As String, Value As Bitmap)
    Dim out As OutputStream
    out.InitializeToBytesArray(0)
    Value.WriteToStream(out, 100, "PNG")
    Put(Key, out.ToBytesArray)
    out.Close
End Sub

Public Sub GetBitmap(Key As String) As Bitmap
    Dim b() As Byte = Get(Key)
    If b = Null Then Return Null
    Dim in As InputStream
    in.InitializeFromBytesArray(b, 0, b.Length)
    Dim bmp As Bitmap
    bmp.Initialize2(in)
    in.Close
    Return bmp
End Sub
#End If

'Removes the key and value mapped to this key.
Public Sub Remove(Key As String, Table As String)
    sql1.ExecNonQuery2("DELETE FROM " & Table & " WHERE key = ?", Array As Object(Key))
End Sub

'Returns a list with all the keys.
Public Sub ListKeys (Table As String) As List
    Dim c As ResultSet = sql1.ExecQuery("SELECT key FROM " & Table)
    Dim res As List
    res.Initialize
    Do While c.NextRow
        res.Add(c.GetString2(0))
    Loop
    c.Close
    Return res
End Sub

'Tests whether a key is available in the store.
Public Sub ContainsKey(Key As String, Table As String) As Boolean
    Return sql1.ExecQuerySingleResult2("SELECT count(key) FROM " & Table & " WHERE key = ?", _
        Array As String(Key)) > 0
End Sub

'Deletes all data from the store.
Public Sub DeleteAll (Table As String)
    sql1.ExecNonQuery("DROP TABLE " & Table & "")
    CreateTable (Table)
End Sub

'Closes the store.
Public Sub Close
    sql1.Close
End Sub
 

LWGShane

Well-Known Member
Licensed User
Longtime User
Here's the project.....
 

Attachments

  • KVS3.zip
    2.2 KB · Views: 178
Upvote 0

OliverA

Expert
Licensed User
Longtime User
I have not run the code, but I found a typo on line 41 of your "KVS 3.b4j" file:

B4X:
Dim Keys As List = TestDB.ListKeys("Frist_Array")

You have "Frist_Array" instead of "First_Array".
 
Upvote 0

LWGShane

Well-Known Member
Licensed User
Longtime User
@OliverA - Thanks, It works! I'm excited for the new possibilities a multi-tabled KVS brings to B4X. (For one, no more needing multiple DBs.)
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
This may not be the route your going, but I modified the code to use a key field as table name (instead of creating actual tables). This allows for SQL to escape the table name (using parameters) instead of having to write some sort of validation rule (I'm lazy and I would say others are better than I at writing the proper rules). This may brake whatever you had in mind and may be totally ignored.

PS: Could not download the B4XCommunityLib from your site.

Update: Was able to download B4XCommunityLib (see next post) and used the SpecialFolder method (after modifying it for the new version of the B4XCommunityLib). The posted file now reflects these changes.
 

Attachments

  • KVS3_FakeTable.zip
    2.4 KB · Views: 182
Last edited:
Upvote 0

LWGShane

Well-Known Member
Licensed User
Longtime User
@OliverA

KVS: I'll take a look into your code.
B4XCommunityLib: Major oops. I forgot to re-upload the ZIP. I have also uploaded the documentation as I'm planning on integrating it via WP pages. I have also renamed it to "NebulaLib". The name change will be official in Version 2.0
 
Last edited:
Upvote 0

OliverA

Expert
Licensed User
Longtime User
@OliverA

KVS: I'll take a look into your code.

If you look at CloudKVS, the "user" portion can be seen as "another table". By using a field within the DB to designate a "table", it would be real easy to go from non-distributed to distributed KVS via CloudKVS. Another way to put it, if KVS3 is closely aligned to CloudKVS, one could easily go from local only to distributed KVS with ease. Hope I'm making sense.
 
Upvote 0
Top