This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
newcat's profile picture

Database API v1.01 - Can be operated with MySQL queries!

Started by newcat, 29 March 2014 - 11:30 AM
newcat #1
Posted 29 March 2014 - 12:30 PM
Hello,

I just wrote a simple Database API I needed for a project.
It can store any sort of Data and can be used in a simple way. Every function is documented and I compare the Syntax with the MySQL Syntax, so you know how to use them.
But the best thing is, that you can use basic MySQL / SQL queries to operate the API. (link to the documentation / limitations site)

Planned features:
  • Improve the MySQL interpreter to support more complex queries
Also, if you have suggestions, tell them and I will try to implement them!

Pastebin: http://pastebin.com/dBHuAvka

CCMyAdmin


CCMyAdmin is a tool similar to PHPmyAdmin. It allows you to easily manage your databases and edit data.
[attachment=1835:ccdb.png]
Download: http://newcat.bplaced.net/CCDB.zip

How to use:

Click the "Open Database" button, then select the "Databases" folder in your minecraft/saves/computer/{computerID}. In the following dialog select a database or create a new one.
After that you can select the table with the tabs on the top, select the ID/row with the listbox in the left and then edit the data with the three buttons above the table view.

—————————————————————————————————————————————



Functions of the API:
SpoilerThis is just a list of currently implemented functions. A detailed documentation can be found here: http://computercraftdb.wikispaces.com/
  • dbExists
  • tableExists
  • createDatabase
  • deleteDatabase
  • createTable
  • renameTable
  • deleteTable
  • getTotalEntries
  • set
  • get
  • delete
  • getIdsByValue
  • getNextFreeID
  • splitString
  • query
  • sqlSELECT
  • sqlUPDATE
  • sqlINSERT
  • sqlDELETE
  • sqlCREATE
  • sqlRENAME
  • sqlDROP

Beginner's Guide / Example Program
Spoiler

--Load the API if not done yet
os.unloadAPI("db")
os.loadAPI("db")

--First of all we need a database in which we want to write, so we check if there is already
--a database called "warehouse" and if not, we create a new one
if (not db.dbExists("warehouse")) then
db.createDatabase("warehouse")
end

--Then we create a table called "items". We also check if it is already existing,
--because we will get an error else
--Currently you have to specify the database you want to modify in almost all
--methods, this will be removed in a later version and replaced through
--db.selectDatabase(), like in PHP/MySQL
if (not db.tableExists("warehouse", "items")) then
db.createTable("warehouse", "items")
end

--Next we want to feed our table with some data.
--The syntax of this very long set commmand is quite simple:
--1st parameter: The database you want to modify (in our case "warehouse")
--2nd parameter: The table you want to modify (in our case "items")
--3rd parameter: The row ID, which will in our case be the Minecraft-ID of the item
--4th parameter: The key (column) which should be modified, in our case for every item the count column and the name column
--5th parameter: The (new) value of the key, in our case for every item the count and the name

--Our first item will be stone
db.set("warehouse", "items", 1, "name", "Stone")
db.set("warehouse", "items", 1, "count", "64")

--The second item will be sand
db.set("warehouse", "items", 12, "name", "Sand")
db.set("warehouse", "items", 12, "count", "12")

--And our last item is going to be diamonds *-*
db.set("warehouse", "items", 264, "name", "Diamond")
db.set("warehouse", "items", 264, "count", "1")

--Also we want to create an index so we know which item ID's we
--currently have stored.
--Since there is no item in minecraft with the ID "0" (except air,
--but in my opionion this is no item), we store the index there
--As index I use an serialized lua-table
index = {1, 12, 264}
db.set("warehouse", "items", 0, "index", textutils.serialize(index))

--All of our data is now written into the database.
--Now it is time to read it and present it to the user
--Let's start. First of all we need to read our index file
--Reading is done by using db.get()
--The syntax is the same as db.set(), except the last parameter
--So for the index file we use this:
index = textutils.unserialize(db.get("warehouse", "items", 0, "index"))

--Now we can read all the other items by using a for-loop, since we have the
--index table.
for i = 1, #index do
print(db.get("warehouse", "items", index[i], "name") .. ": " .. db.get("warehouse", "items", index[i], "count"))
end

--The program will output:
--Stone: 64
--Sand: 12
--Diamond: 1
--Using the index makes the program very flexible and expandable,
--but it is also possible to hardcode the ID's.


Changelog
Spoilerv0.9
+ Initial Release

v1.0
+ Added all MySQL related functions:
  • query()
  • sqlSELECT()
  • sqlUPDATE()
  • sqlINSERT()
  • sqlDELETE()
  • sqlCREATE()
  • sqlRENAME()
  • sqlDROP()
  • splitString()
+ Added a detailed documentation

v1.01
* Bugfix
Edited on 04 August 2014 - 09:34 PM
Remi #2
Posted 29 March 2014 - 01:07 PM
This looks neat. Especially if you add a basic SQL interpreter. I looked in the Pastebin and was expecting more code, after reading what the API can do! ;)/>
LayZee #3
Posted 13 April 2014 - 11:49 PM
Access restricted to http://computercraftdb.wikispaces.com
Edited on 13 April 2014 - 09:49 PM
newcat #4
Posted 02 June 2014 - 11:24 AM
Yep, thanks for mentioning it, I just made it public. I'm sorry that it took so long, I didn't look in the forums here for quite some time, but now the documentation should be available!
RoD #5
Posted 02 June 2014 - 06:49 PM
You are missing a end here:

function deleteDatabase(dbName)
if (dbExists(dbName)) then
  fs.delete("Databases\\" .. dbName)
else
end

Needs to be:

function deleteDatabase(dbName)
if (dbExists(dbName)) then
  fs.delete("Databases\\" .. dbName)
else
		end
end

Edit: Quick question: can we add various values to one key?
Something like:

db.set("DatabaseName", "exampleTable", db.getNextFreeID(), "foo", "bar", "var2", "username", "password")
Edited on 02 June 2014 - 04:54 PM
newcat #6
Posted 02 June 2014 - 09:49 PM
You are missing a end here:

function deleteDatabase(dbName)
if (dbExists(dbName)) then
  fs.delete("Databases\\" .. dbName)
else
end

Needs to be:

function deleteDatabase(dbName)
if (dbExists(dbName)) then
  fs.delete("Databases\\" .. dbName)
else
		end
end

Edit: Quick question: can we add various values to one key?
Something like:

db.set("DatabaseName", "exampleTable", db.getNextFreeID(), "foo", "bar", "var2", "username", "password")
Thank you for mentioning it, I fixed that.

You can't set multiple values for one key yet (though I maybe implement that in the future), but if you combine the multiple strings into one string, you can set this combined string as value.
If you use blanks as separators you can then use the db.splitString() function to split the string back into the single values. But it isn't a good idea to use blanks as separators ;)/>
RoD #7
Posted 02 June 2014 - 09:55 PM
You are missing a end here:

function deleteDatabase(dbName)
if (dbExists(dbName)) then
  fs.delete("Databases\\" .. dbName)
else
end

Needs to be:

function deleteDatabase(dbName)
if (dbExists(dbName)) then
  fs.delete("Databases\\" .. dbName)
else
		end
end

Edit: Quick question: can we add various values to one key?
Something like:

db.set("DatabaseName", "exampleTable", db.getNextFreeID(), "foo", "bar", "var2", "username", "password")
Thank you for mentioning it, I fixed that.

You can't set multiple values for one key yet (though I maybe implement that in the future), but if you combine the multiple strings into one string, you can set this combined string as value.
If you use blanks as separators you can then use the db.splitString() function to split the string back into the single values. But it isn't a good idea to use blanks as separators ;)/>
You're welcome

Ok, i hope you implement this as it will add the really important part of the database.
Thanks
newcat #8
Posted 03 June 2014 - 08:42 PM
You are missing a end here:
 function deleteDatabase(dbName) if (dbExists(dbName)) then fs.delete("Databases\\" .. dbName) else end 
Needs to be:
 function deleteDatabase(dbName) if (dbExists(dbName)) then fs.delete("Databases\\" .. dbName) else end end 
Edit: Quick question: can we add various values to one key? Something like:
 db.set("DatabaseName", "exampleTable", db.getNextFreeID(), "foo", "bar", "var2", "username", "password") 
Thank you for mentioning it, I fixed that. You can't set multiple values for one key yet (though I maybe implement that in the future), but if you combine the multiple strings into one string, you can set this combined string as value. If you use blanks as separators you can then use the db.splitString() function to split the string back into the single values. But it isn't a good idea to use blanks as separators ;)/>/>
You're welcome Ok, i hope you implement this as it will add the really important part of the database. Thanks
AFAIK it isn't possible to set multiple values for one key in MySQL… You can, of course, combine the data and split it afterwards; that also works in MySQL. But this isn't a function MySQL features, this has to be done by the user. But I'm planning to improve the splitString() function so it allows to split Strings based on variable chars which are given as a parameter. So e. g. if you have var1 and var2 and combine them like this "var1!var2!var3!…" and use the splitString() function with the parameter "!" it will return the single variables again. But you can tell me a database language with supports multiple values for one key maybe I can improve my database structure with that ;)/>
RoD #9
Posted 03 June 2014 - 10:00 PM
i think that you can use … as a argument wich will add infinite param. to the function:
http://www.lua.org/pil/5.2.html
http://stackoverflow.com/questions/7573588/variable-number-of-function-arguments-lua-5-1
http://stackoverflow.com/questions/6086901/call-a-function-with-variable-length-of-arguments
newcat #10
Posted 03 June 2014 - 10:46 PM
i think that you can use … as a argument wich will add infinite param. to the function:
http://www.lua.org/pil/5.2.html
http://stackoverflow...guments-lua-5-1
http://stackoverflow...th-of-arguments
The problem isn't that I don't know how to implement this in Lua. But i want this database to be similar like a MySQL Database, in which it isn't possible to assign multiple values to one key. Of course it is implementable, but is it that useful?
I think I will add more functions, which will allow you to convert tables into one value and a value back into a table. This would be like:

tbl = {"bar", "var2", "username", "password"}
db.set("DatabaseName", "exampleTable", db.getNextFreeID(), "foo", db.convertTableToString(tbl))

And then backwards:

tbl = db.convertStringToTable(db.get("DatabaseName", "exampleTable", 1, "foo"))

This will now also allow the use of MySQL syntax:

tbl = {"bar", "var2", "username", "password"}
qry = "UPDATE `exampleTable` SET `foo` = '" .. db.convertTableToString(tbl) .. "' WHERE `id` = '" .. db.getNextFreeID() .. "'"
db.query("DatabaseName", qry)
KingofGamesYami #11
Posted 04 June 2014 - 02:07 PM
-snip-
So, you are adding textutils.serialize and textutils.unserialize?
newcat #12
Posted 04 June 2014 - 07:20 PM
-snip-
So, you are adding textutils.serialize and textutils.unserialize?

Thanks for mentioning it :D/> I didn't even know there was already a function for that but thats great. So I'd say: Problem solved ;)/>
TheGreatSynan #13
Posted 02 July 2014 - 10:16 PM
Wow. Once you get the external tool going, you can be certain that I will be using this. Good luck!
newcat #14
Posted 02 August 2014 - 10:49 PM
Wow. Once you get the external tool going, you can be certain that I will be using this. Good luck!

Thank you, I just released the tool, DL link is in the OP.
Rokin05 #15
Posted 01 January 2015 - 03:07 PM
Hi, i'm beginner in CC (and don't speak very good english :P/>)
First, thank you, your BD API is very cool ! :)/>



for the index command :

Also we want to create an index so we know which item ID's we
–currently have stored.
–Since there is no item in minecraft with the ID "0" (except air,
–but in my opionion this is no item), we store the index there
–As index I use an serialized lua-table
index = {1, 12, 264}
db.set("warehouse", "items", 0, "index", textutils.serialize(index))



Why not fully integre it directly in the api after basic command ( ex : db.set)


Our first item will be stone
db
.set("warehouse", "items", 1, "name", "Stone")
db.set("warehouse", "items", 1, "count", "64")

and at the end the db.set api function pull another function like


- read all subdirs in warehouse/items
- get them name in a array : temp = {1, 12, 264…..}
- and run db.set("warehouse", "items", 0, "temp", textutils.serialize(index))


this remove one cmd for the user and get up to date the index after each update.
it's not "better" ?
Rokin05 #16
Posted 03 January 2015 - 06:48 PM
in complément of my previous thread :

With this new function :

--This function update / create index of a table:
function index(db, tableName)
		if (dbExists(db)) then
				if (tableExists(db, tableName)) then
						index = {}
						totalEntries = 0  
						path = "Databases\\" .. db .. "\\" .. tableName
						ls = fs.list(path)
						
						for _, table in pairs(ls) do		
						  table = textutils.unserialize(table)						
						  if table ~= 0 then
							totalEntries = totalEntries + 1
							index[totalEntries] = table
						  end					  
						end

						set(db, tableName, 0, "index", textutils.serialize(index))
						return nil
				else
						print("Invalid Table!")
						return nil
				end
		else
				print("Invalid Database!")
				return nil
		end
end


--As index I use an serialized lua-table
index = {1, 12, 264}
db.set("warehouse", "items", 0, "index", textutils.serialize(index))

can now be written :

--As index I use an serialized lua-table
db.index("warehouse", "items")

and i think, if you add :

db.index(db, tableName)

at the end of db.set, db.delete etc… function, user not need to write it now (not try)
Edited on 03 January 2015 - 05:53 PM
newcat #17
Posted 03 January 2015 - 10:03 PM
—snip—

That actually is a pretty good idea. I will implement this in a future version but since i am not currently working at this it will not be released soon :(/>
Rokin05 #18
Posted 04 January 2015 - 12:09 AM
np np, it's just a little idea/review but it is already good atm :lol:/>
R_B98 #19
Posted 23 January 2016 - 06:24 PM
I know this is a really old topic however, a friend and I are using this API right now and I was wondering how to pull the information for this out of a Lua table or if that is at all possible.