-
Notifications
You must be signed in to change notification settings - Fork 2
/
EbakusDB.sol
160 lines (144 loc) · 5.44 KB
/
EbakusDB.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
pragma solidity ^0.5.0;
/**
* @title EbakusDB
* @author Ebakus
* @notice Library for giving access to EbakusDB
*/
library EbakusDB {
/**
* @notice Create a table at EbakusDB
* @dev This has to be called once per table. Usually it makes sense to occur in contract's constructor,
* as it will run once and will be removed from the deployed code.
* Important, "Id" field has to exist in every table/struct.
* @param tableName Table name
* @param indexes List of indexed fields (comma separated)
* @param tablesAbi ABI represantation of the solidity struct defining the table
*
* Example solidity struct:
*
* struct User {
* uint64 Id;
* string Name;
* }
*
* Example table ABI:
*
* [{
* "type": "table",
* "name": "Users",
* "inputs": [
* {"name": "Id", "type": "uint64"},
* {"name": "Name", "type": "string"},
* ]
* }]
*/
function createTable(string memory tableName, string memory indexes, string memory tablesAbi) internal {
bytes memory input = abi.encodeWithSignature("createTable(string,string,string)", tableName, indexes, tablesAbi);
assembly {
let size := mload(input)
let x := add(input, 0x20)
if iszero(call(not(0), 0x102, 0, x, size, x, 0x00)) {
revert(0, 0)
}
}
}
/**
* @notice Get a single entry from EbakusDB
* @dev Transaction will fail if nothing is mathed in EbakusDB
* @param tableName Table name
* @param whereClause WhereClause for finding an entry
* Supported conditions are "<", ">", "=", "==", "<=", ">=", "!=", "LIKE"
* Example use case: Phone = "555-1111"
* Id >= 3
* @param orderClause OrderClause for sorting the results using "ASC" or "DESC"
* Example use case: Phone DESC
* @return ABI encoded object, read using abi.decode(...)
*/
function get(string memory tableName, string memory whereClause, string memory orderClause) internal view returns (bytes memory o) {
bytes memory input = abi.encodeWithSignature("get(string,string,string)", tableName, whereClause, orderClause);
return getBytes(input);
}
/**
* @notice Select entries from EbakusDB
* @param tableName Table name
* @param whereClause WhereClause for finding an entry
* Supported conditions are "<", ">", "=", "==", "<=", ">=", "!=", "LIKE"
* Example use case: Phone = "555-1111"
* Id >= 3
* @param orderClause OrderClause for sorting the results using "ASC" or "DESC"
* Example use case: Phone DESC
* @return Select iterator that has to be passed in EbakusDB.next(...)
*/
function select(string memory tableName, string memory whereClause, string memory orderClause) internal view returns (bytes32 o) {
bytes memory input = abi.encodeWithSignature("select(string,string,string)", tableName, whereClause, orderClause);
assembly {
let size := mload(input)
let x := add(input, 0x20)
if iszero(staticcall(not(0), 0x102, x, size, o, 0x20)) {
revert(0, 0)
}
o := mload(o)
}
}
/**
* @notice Insert/Update an entry in EbakusDB
* @param tableName Table name
* @param data ABI encoded object, encode using abi.encode(...)
* @return true if entry has been inserted/updated
*/
function insertObj(string memory tableName, bytes memory data) internal returns (bool o) {
bytes memory input = abi.encodeWithSignature("insertObj(string,bytes)", tableName, data);
return getBool(input);
}
/**
* @notice Delete an entry in EbakusDB
* @param tableName Table name
* @param data ABI encoded object's "Id" value, encode using abi.encode(...)
* @return true if entry has been deleted
*/
function deleteObj(string memory tableName, bytes memory data) internal returns (bool o) {
bytes memory input = abi.encodeWithSignature("deleteObj(string,bytes)", tableName, data);
return getBool(input);
}
/**
* @notice Get next entry for a select query made at EbakusDB
* @param iter Select's iterator retrieved by EbakusDB.select(...)
* @return ABI encoded object, read using abi.decode(...)
*/
function next(bytes32 iter) internal view returns (bytes memory o, bool found) {
bytes memory input = abi.encodeWithSignature("next(bytes32)", iter);
o = getBytes(input);
return (o, o.length > 0);
}
/**
* @notice Call EbakusDB system contract and fetch back some bytes
* @param input ABI encoded EbakusDB system contract command
* @return ABI encoded object, read using abi.decode(...)
*/
function getBytes(bytes memory input) private view returns (bytes memory o) {
assembly {
let size := mload(input)
let x := add(input, 0x20)
if iszero(staticcall(not(0), 0x102, x, size, o, 0xffff)) {
revert(0, 0)
}
let osize := mload(o)
mstore(0x40, add(mload(0x40), add(osize, 0x20)))
}
}
/**
* @notice Call EbakusDB system contract and fetch back a boolean value
* @param input ABI encoded EbakusDB system contract command
* @return boolean
*/
function getBool(bytes memory input) private returns (bool o) {
assembly {
let size := mload(input)
let x := add(input, 0x20)
if iszero(call(not(0), 0x102, 0, x, size, o, 0x20)) {
revert(0, 0)
}
o := mload(o)
}
}
}