├── .cproject
├── .gitignore
├── build_linux.sh
├── build_osx.sh
├── readme.md
├── src
├── .gitignore
└── as_lua.c
└── test
└── main.lua
/.cproject:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /as_lua.so
2 |
--------------------------------------------------------------------------------
/build_linux.sh:
--------------------------------------------------------------------------------
1 | gcc -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/as_lua.d" -MT"src/as_lua.d" -o "./src/as_lua.o" "src/as_lua.c" -std=gnu99 -g -rdynamic -Wall -fno-common -fno-strict-aliasing -fPIC -DMARCH_x86_64 -D_FILE_OFFSET_BITS=64 -D_REENTRANT -D_GNU_SOURCE
2 | gcc -shared -o "as_lua.so" ./src/as_lua.o -laerospike -lssl -lcrypto -lpthread -lrt -lm
3 |
--------------------------------------------------------------------------------
/build_osx.sh:
--------------------------------------------------------------------------------
1 | clang -std=gnu99 -g -Wall -fPIC -fno-common -fno-strict-aliasing -march=nocona -DMARCH_i386 -D_FILE_OFFSET_BITS=64 -D_REENTRANT -D_GNU_SOURCE -D_DARWIN_UNLIMITED_SELECT -I/usr/local/include -o src/as_lua.o -c src/as_lua.c
2 | clang -dynamiclib -o as_lua.so src/as_lua.o /usr/local/lib/libaerospike.a -lssl -lcrypto -lpthread -L/usr/local/lib -lm -lz
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Calling Aerospike from Lua
2 | ## Problem
3 | You are using [Lua](http://www.lua.org/) and would like to make calls to an Aerospike database. But Aerospike does not provide a Lua Client API.
4 |
5 | You may be using Lua within application servers like Nginx, BarracudaDrive, Mako, OpenResty, Kepler, etc - similar to how Javascript is used inside Node.
6 | ## Solution
7 | The solution is conceptually simple: Call the Aerospike C API from Lua. There is extensive Lua documentation and many books and blogs that describe calling C from Lua. This example demonstrates how to wrap the Aerospike C client API so it can be called from Lua.
8 |
9 | The source code for this solution is available on GitHub at
10 | http://github.com/aerospike/client-lua.
11 |
12 | The project also requires the Aerospike C client, which is available at http://github.com/aerospike/aerospike-client-c or from http://aerospike.com . You will need to build the client and have the Aerospike headers and libraries available in the search path.
13 |
14 |
15 | You’ll need the Lua development environment, and the ```lua.h``` in the include path. You can include the Lua 5.0 or 5.1 environment from the source, or install a Lua development package with your package manager.
16 | ### Build Instructions
17 |
18 | In this example, we will wrap 5 basic Aerospike key-value operations:
19 | 1. **Connect** - connect to an Aerospike cluster
20 | 2. **Get** - read a record from the Aerospike cluster
21 | 3. **Put** - write a record to the Aerospike cluster
22 | 4. **Increment** - increment a Bin value in a record
23 | 5. **Disconnect** - disconnect from the Aerospike cluster
24 |
25 | You can use this example to wrap other Aerospike operations in the C library. This C library must be installed on the Lua library path for Lua to find it.
26 |
27 | There is a lot of information at the [Lua users wiki](http://lua-users.org/wiki/) that describes calling C from Lua. Chapter 24 of “[Programming in Lua](http://www.lua.org/pil/)” describes in detail how this is done.
28 |
29 |
30 | Run the build script located in the root directory of the repository to build the library "as_lua.so"
31 |
32 | For Linux
33 | ```
34 | ./build_linux.sh
35 | ```
36 | For OS X
37 | ```
38 | ./build_osx.sh
39 | ```
40 | The shared library “as_lua.so” has dependencies on the Aerospike C Client API. Refer to the [Aerospike C Client](https://docs.aerospike.com/pages/viewpage.action?pageId=3807998) documentation for instructions on insallation and dependencies.
41 |
42 |
43 | **IMPORTANT:** The shared library as_lua.so should be placed in the Lua library path:
44 | ```
45 | ./as_lua.so
46 | /usr/local/lib/lua/5.1/as_lua.so
47 | /usr/lib/lua/5.1/as_lua.so
48 | ```
49 | ### Lua application to calling Aerospike
50 |
51 | This example includes a simple Lua program that exercises each function implemented in the library. You will find code in the file ```main.lua``` in the “test” subdirectory.
52 |
53 | Something to remember:
54 | This is a C library that calls the Aerospike 3 C Client API.
55 | This project has all the same dependencies as the Aerospike C Client API. It will only run on the same platforms supported by the C Client.
56 |
57 |
58 | ## Discussion
59 | The functions that will be exposed to Lua are defined in the following code:
60 | ```c
61 | static const struct luaL_Reg as_client [] = {
62 | {"connect", connect},
63 | {"disconnect", disconnect},
64 | {"get", get},
65 | {"put", put},
66 | {"increment", increment},
67 | {NULL, NULL}
68 | };
69 |
70 | extern int luaopen_as_lua(lua_State *L){
71 | luaL_register(L, "as_lua", as_client);
72 | return 0;
73 | }
74 | ```
75 | This function is called by the require statement in Lua. When require is called, Lua will look for a library named ```as_lua.so``` on its library path. Be sure to put ```as_lua.so``` in one of the following directories, depending on your Lua installation:
76 | ```
77 | ./as_lua.so
78 | /usr/local/lib/lua/5.1/as_lua.so
79 | /usr/lib/lua/5.1/as_lua.so
80 | ```
81 | The C function ```lua_open_aerospike``` is called by the Lua function require ```as_lua```. At the start of your Lua application, you should have code like this:
82 | ```lua
83 | local as = require "as_lua"
84 | ```
85 | ### Connect
86 | To connect to an Aerospike cluster you need to supply one or more “seed nodes” and ports. When a client application connects to a cluster, one name or IP address and port is sufficient. The Aerospike intelligent client will discover all the nodes in the cluster and become a 1st class observer of them. Additional nodes can be supplied at connection time in case the node you have specified is actually down.
87 |
88 | Our Lua function will take one seed node address and port, and return a handle to a cluster.
89 | ```lua
90 | err, message, cluster = as.connect("localhost", 3000)
91 | print("connected", err, message)
92 | ```
93 | Connect must be called before you call any other Aerospike function.
94 | Connect will return 3 values, in the above example, the variables ```err``` and ```message``` will contain the error code and error message, and the variable cluster will be a handle to the Aerospike cluster. You will use the cluster handle in subsequent Aerospike function calls.
95 |
96 | The C code to implement this function:
97 | ```c
98 | static int connect(lua_State *L){
99 | const char *hostName = luaL_checkstring(L, 1);
100 | int port = lua_tointeger(L, 2);
101 | as_error err;
102 |
103 | // Configuration for the client.
104 | as_config config;
105 | as_config_init(&config);
106 |
107 | // Add a seed host for cluster discovery.
108 | as_config_add_host(&config, hostName, port);
109 |
110 | // The Aerospike client instance, initialized with the configuration.
111 | aerospike_init(&as, &config);
112 |
113 | // Connect to the cluster.
114 | aerospike_connect(&as, &err);
115 |
116 | /* Push the return */
117 | lua_pushnumber(L, err.code);
118 | lua_pushstring(L, err.message);
119 | lua_pushlightuserdata(L, &as);
120 | return 3;
121 | }
122 | ```
123 | Lua uses its own stack mechanism to pass parameters between Lua and C. You will note at the start of this function, parameters are taken from the stack
124 | ```c
125 | const char *hostName = luaL_checkstring(L, 1);
126 | int port = lua_tointeger(L, 2);
127 | ```
128 | and at the end of the function, the return values are pushed onto the stack
129 | ```c
130 | lua_pushnumber(L, err.code);
131 | lua_pushstring(L, err.message);
132 | lua_pushlightuserdata(L, &as);
133 | return 3;
134 | ```
135 | Note that there are 3 return values:
136 | - error number
137 | - error message
138 | - cluster pointer
139 |
140 | ### Disconnect
141 | When your Lua application has completed using Aerospike, usually at the end of the Lua code, it should disconnect from the Aerospike cluster. This frees resources in the process, things like socket connections, file descriptors, etc.
142 |
143 | Our Lua function to disconnect from the cluster will take one parameter that is the cluster handle.
144 | ```lua
145 | err, message = as.disconnect(cluster)
146 | print("disconnected", err, message)
147 | ```
148 | The C code to implement this function:
149 | ```c
150 | static int disconnect(lua_State *L){
151 | aerospike* as = lua_touserdata(L, 1);
152 | as_error err;
153 | aerospike_close(as, &err);
154 | lua_pushnumber(L, err.code);
155 | lua_pushstring(L, err.message);
156 | return 2;
157 | }
158 | ```
159 | You should be seeing a pattern emerging in the way the parameters are passed to the function and how values are returned. The actual code that interacts with Aerospike is trivial. Most of the work in this function is to obtain the pointer to the cluster and return 2 values to Lua
160 | ### Get
161 | To read a record from Aerospike you use the ```get``` function. The cluster handle, obtained from the ```connect``` function, is the first argument and is the reference the ```get``` function uses to interact with the cluster.
162 |
163 | The next 3 parameters are ```namespace```, ```set``` and ```key```, in that order. These values uniquely identify the record.
164 | ```lua
165 | err, message, record = as.get(cluster, "test", "test", "peter001")
166 | print("read record", err, message, record.uid, record.name, record.dob)
167 | ```
168 | The ```get``` function returns 3 values. The 1st is the error code, the second is the error message if one exists, the 3rd is a table containing the record values.
169 |
170 | You will note that this function reads all the Bins in the record and is the easiest to implement. A better implementation would offer the capability to read a subset of Bins. We will leave that activity up to the reader.
171 |
172 | ### Put
173 | To write data to Aerospike you use the ```put``` function. The cluster handle, obtained from the ```connect``` function, is the first argument and is the reference the ```put``` function uses to interact with the cluster.
174 |
175 | The next 3 parameters are ```namespace```, ```set``` and ```key```, in that order. These values uniquely identify the record.
176 |
177 | The 5th parameter is a table containing the Bin names and values. This is the actual data you want to store in Aerospike.
178 | ```lua
179 | local bins = {}
180 | bins["uid"] = "peter001"
181 | bins["name"] = "Peter"
182 | bins["dob"] = 19800101
183 |
184 | err, message = as.put(cluster, "test", "test", "peter001", 3, bins)
185 | print("saved record", err, message)
186 | ```
187 | The put function returns 2 values. The 1st is the error code, the second is the error message if one exists.
188 |
189 | This function illustrates the complexity of passing parameters and return values between Lua and C. The complexity is in obtaining the values in the table parameter. The function ```add_bins_to_rec``` takes the passed-in table containing the Bin names and values and creates Bin values and populates a ```as_record``` structure. This structure is returned to the caller.
190 |
191 | The tricky part is obtaining the individual elements from the table. This function manipulates the Lua stack to iterate through the elements in the table and creates Bin values.
192 | ```c
193 | static as_record add_bins_to_rec(lua_State *L, int index, int numBins)
194 | {
195 | as_record rec;
196 | as_record_init(&rec, numBins);
197 |
198 | // Push another reference to the table on top of the stack (so we know
199 | // where it is, and this function can work for negative, positive and
200 | // pseudo indices
201 | lua_pushvalue(L, index);
202 | // stack now contains: -1 => table
203 | lua_pushnil(L);
204 | // stack now contains: -1 => nil; -2 => table
205 | while (lua_next(L, -2))
206 | {
207 | // stack now contains: -1 => value; -2 => key; -3 => table
208 | // copy the key so that lua_tostring does not modify the original
209 | lua_pushvalue(L, -2);
210 | // stack now contains: -1 => key; -2 => value; -3 => key; -4 => table
211 | const char *key = lua_tostring(L, -1);
212 |
213 | // add to record
214 | if (lua_isnumber(L, -2)){
215 | int intValue = lua_tointeger(L, -2);
216 | as_record_set_int64(&rec, key, intValue);
217 |
218 | } else if (lua_isstring(L, -2)){
219 | const char *value = lua_tostring(L, -2);
220 | as_record_set_str(&rec, key, value);
221 | }
222 | // pop value + copy of key, leaving original key
223 | lua_pop(L, 2);
224 | // stack now contains: -1 => key; -2 => table
225 | }
226 |
227 | // stack now contains: -1 => table (when lua_next returns 0 it pops the key
228 | // but does not push anything.)
229 | // Pop table
230 | lua_pop(L, 1);
231 | // Stack is now the same as it was on entry to this function
232 | return rec;
233 | }
234 | ```
235 | ### Increment
236 | The increment function is quite similar to the put function in that it changes the value of one or more Bins in a record. It is useful when your application uses counters, and it also removes the need to read the value, increment the value in your application and rewrite it.
237 | ```lua
238 | bins = {}
239 | bins["counter"] = 1
240 | err, message = as.increment(cluster, "test", "test", "peter003", 1, bins)
241 | print("incremented record", err, message)
242 | ```
243 |
244 |
--------------------------------------------------------------------------------
/src/.gitignore:
--------------------------------------------------------------------------------
1 | /as_lua.d
2 | /as_lua.o
3 |
--------------------------------------------------------------------------------
/src/as_lua.c:
--------------------------------------------------------------------------------
1 |
2 | #include /* Always include this */
3 | #include /* Always include this */
4 | #include /* Always include this */
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 |
25 | // Allow only one global aerospike instance.
26 | aerospike as;
27 |
28 | static as_record add_bins_to_rec(lua_State *L, int index, int numBins)
29 | {
30 | as_record rec;
31 | as_record_init(&rec, numBins);
32 |
33 | // Push another reference to the table on top of the stack (so we know
34 | // where it is, and this function can work for negative, positive and
35 | // pseudo indices
36 | lua_pushvalue(L, index);
37 | // stack now contains: -1 => table
38 | lua_pushnil(L);
39 | // stack now contains: -1 => nil; -2 => table
40 | while (lua_next(L, -2))
41 | {
42 | // stack now contains: -1 => value; -2 => key; -3 => table
43 | // copy the key so that lua_tostring does not modify the original
44 | lua_pushvalue(L, -2);
45 | // stack now contains: -1 => key; -2 => value; -3 => key; -4 => table
46 | const char *binName = lua_tostring(L, -1);
47 |
48 | // add to record
49 | if (lua_isnumber(L, -2)){
50 | int intValue = lua_tointeger(L, -2);
51 | as_record_set_int64(&rec, binName, intValue);
52 |
53 | } else if (lua_isstring(L, -2)){
54 | const char *value = lua_tostring(L, -2);
55 | as_record_set_str(&rec, binName, value);
56 | } else if (lua_istable(L, -2)){
57 | // make a as_list and populate it
58 | as_arraylist *list = as_arraylist_new(3, 3);
59 |
60 | lua_pushvalue(L, -2);
61 | lua_pushnil(L);
62 | // This is needed for it to even get the first value
63 | while (lua_next(L, -2))
64 | {
65 | lua_pushvalue(L, -2);
66 | //const char *key = lua_tostring(L, -1);
67 | const char *value = lua_tostring(L, -2);
68 | // populate the as_list
69 | as_arraylist_append_str(list, value);
70 | //printf("%s => %s\n", key, value);
71 | lua_pop(L, 2);
72 | }
73 | lua_pop(L, 1);
74 |
75 | // put the list in a bin
76 | as_record_set_list(&rec, binName, (as_list*)as_val_reserve(list));
77 | }
78 | // pop value + copy of key, leaving original key
79 | lua_pop(L, 2);
80 | // stack now contains: -1 => key; -2 => table
81 | }
82 |
83 | // stack now contains: -1 => table (when lua_next returns 0 it pops the key
84 | // but does not push anything.)
85 | // Pop table
86 | lua_pop(L, 1);
87 | // Stack is now the same as it was on entry to this function
88 | return rec;
89 | }
90 |
91 |
92 |
93 | static as_operations add_bins_to_increment(lua_State *L, int index, int numBins)
94 | {
95 | as_operations ops;
96 | as_operations_init(&ops, numBins);
97 |
98 | // Push another reference to the table on top of the stack (so we know
99 | // where it is, and this function can work for negative, positive and
100 | // pseudo indices
101 | lua_pushvalue(L, index);
102 | // stack now contains: -1 => table
103 | lua_pushnil(L);
104 | // stack now contains: -1 => nil; -2 => table
105 | while (lua_next(L, -2))
106 | {
107 | // stack now contains: -1 => value; -2 => key; -3 => table
108 | // copy the key so that lua_tostring does not modify the original
109 | lua_pushvalue(L, -2);
110 | // stack now contains: -1 => key; -2 => value; -3 => key; -4 => table
111 | const char *binName = lua_tostring(L, -1);
112 | int intValue = lua_tointeger(L, -2);
113 |
114 | //printf("Bin:%s, value:%d\n", binName, intValue);
115 |
116 | //add an operation for each bin
117 | as_operations_add_incr(&ops, binName, intValue);
118 | // pop value + copy of key, leaving original key
119 | lua_pop(L, 2);
120 | // stack now contains: -1 => key; -2 => table
121 | }
122 |
123 | // stack now contains: -1 => table (when lua_next returns 0 it pops the key
124 | // but does not push anything.)
125 | // Pop table
126 | lua_pop(L, 1);
127 | // Stack is now the same as it was on entry to this function
128 | return ops;
129 | }
130 |
131 |
132 | static int connect(lua_State *L){
133 | const char *hostName = luaL_checkstring(L, 1);
134 | int port = lua_tointeger(L, 2);
135 | as_error err;
136 |
137 | // Configuration for the client.
138 | as_config config;
139 | as_config_init(&config);
140 |
141 | // Add a seed host for cluster discovery.
142 | //config.hosts[0].addr = hostName;
143 | //config.hosts[0].port = port;
144 | as_config_add_host(&config, hostName, port);
145 |
146 | // The Aerospike client instance, initialized with the configuration.
147 | aerospike_init(&as, &config);
148 |
149 | // Connect to the cluster.
150 | aerospike_connect(&as, &err);
151 |
152 | /* Push the return */
153 | lua_pushnumber(L, err.code);
154 | lua_pushstring(L, err.message);
155 | lua_pushlightuserdata(L, &as);
156 | return 3;
157 | }
158 |
159 | static int disconnect(lua_State *L){
160 | aerospike* as = lua_touserdata(L, 1);
161 | as_error err;
162 | aerospike_close(as, &err);
163 | lua_pushnumber(L, err.code);
164 | lua_pushstring(L, err.message);
165 | return 2;
166 | }
167 | static int get(lua_State *L){
168 | //printf("-get-\n");
169 | aerospike* as = lua_touserdata(L, 1);
170 | const char* nameSpace = luaL_checkstring(L, 2);
171 | const char* set = luaL_checkstring(L, 3);
172 | const char* keyString = luaL_checkstring(L, 4);
173 | //printf("key-:%s\n", keyString);
174 | as_record* rec = NULL;
175 | as_key key;
176 | as_error err;
177 | as_key_init(&key, nameSpace, set, keyString);
178 |
179 | // Read the test record from the database.
180 | aerospike_key_get(as, &err, NULL, &key, &rec);
181 |
182 | // Push the error code
183 | lua_pushnumber(L, err.code);
184 |
185 | // Push the error message
186 | lua_pushstring(L, err.message);
187 |
188 | // Create an new table and push it
189 | if ( err.code == AEROSPIKE_OK){
190 |
191 | lua_newtable(L); /* create table to hold Bins read */
192 | /*
193 | * iterate through bin and add the bin name
194 | * and value to the table
195 | */
196 | as_record_iterator it;
197 | as_record_iterator_init(&it, rec);
198 |
199 | while (as_record_iterator_has_next(&it)) {
200 | as_bin *bin = as_record_iterator_next(&it);
201 | as_val *value = (as_val*)as_bin_get_value(bin);
202 | char * binName = as_bin_get_name(bin);
203 |
204 | int bin_type = as_val_type(value); //Bin Type
205 |
206 | switch (bin_type){
207 | case AS_INTEGER:
208 |
209 | //printf("--integer-%s-\n", binName);
210 | lua_pushstring(L, binName); //Bin name
211 | lua_pushnumber(L, as_integer_get(as_integer_fromval(value)));
212 | //printf("--integer-end-\n");
213 | break;
214 | case AS_DOUBLE:
215 |
216 | //printf("--double-%s-\n", binName);
217 | lua_pushstring(L, binName); //Bin name
218 | lua_pushnumber(L, as_double_get(as_double_fromval(value)));
219 | //printf("--double-end-\n");
220 | break;
221 | case AS_STRING:
222 | //printf("--string-%s-\n", binName);
223 | lua_pushstring(L, binName); //Bin name
224 | lua_pushstring(L, as_val_tostring(value));
225 | //printf("--string-end-\n");
226 | break;
227 | case AS_LIST:
228 | //printf("--list-%s-\n", binName);
229 | lua_pushstring(L, binName); //Bin name
230 | // Iterate through arraylist populating table
231 | as_list* p_list = as_list_fromval(value);
232 | as_arraylist_iterator it;
233 | as_arraylist_iterator_init(&it, (const as_arraylist*)p_list);
234 |
235 | // create a Lua inner table table for the "List"
236 | lua_newtable(L);
237 |
238 | int count = 0;
239 | // See if the elements match what we expect.
240 | while (as_arraylist_iterator_has_next(&it)) {
241 | const as_val* p_val = as_arraylist_iterator_next(&it);
242 | //Assume string
243 | char* p_str = as_val_tostring(p_val);
244 | lua_pushnumber(L, count); // table[i]
245 | lua_pushstring(L, p_str); //Value
246 | //printf("%d => %s\n", count, p_str);
247 | count++;
248 | lua_settable(L, -3);
249 | }
250 | //printf("--list-end-\n");
251 | break;
252 | }
253 | //printf("--settable-\n");
254 | lua_settable(L, -3);
255 | //printf("--settable-end-\n");
256 | }
257 | }
258 | as_record_destroy(rec);
259 | as_key_destroy(&key);
260 | //printf("-get-end-\n");
261 | return 3;
262 | }
263 |
264 |
265 |
266 | static int put(lua_State *L){
267 |
268 | //Cluster
269 | aerospike* as = lua_touserdata(L, 1);
270 |
271 | //Namespace
272 | const char* nameSpace = luaL_checkstring(L, 2);
273 |
274 | //Set
275 | const char* set = luaL_checkstring(L, 3);
276 |
277 | //Key as string
278 | const char* keyString = luaL_checkstring(L, 4);
279 |
280 | // Number of bins.
281 | const int numBins = lua_tointeger(L, 5);
282 |
283 | //Bins
284 | as_record rec = add_bins_to_rec(L, 6, numBins);
285 |
286 | //const as_record * test = &rec;
287 | //if (as_val_type(as_record_get(test, "animals")) == AS_LIST)
288 | // printf("correct list\n");
289 | //else
290 | // printf("not a list\n");
291 |
292 | // Create key
293 | as_key key;
294 | as_error err;
295 | as_key_init(&key, nameSpace, set, keyString);
296 |
297 | // Write record
298 | aerospike_key_put(as, &err, NULL, &key, &rec);
299 | as_key_destroy(&key);
300 | as_record_destroy(&rec);
301 | // Return status
302 | lua_pushnumber(L, err.code);
303 | lua_pushstring(L, err.message);
304 | return 2;
305 |
306 | }
307 |
308 |
309 | static int increment(lua_State *L){
310 | as_error err;
311 | aerospike* as = lua_touserdata(L, 1);
312 | const char* nameSpace = luaL_checkstring(L, 2);
313 | const char* set = luaL_checkstring(L, 3);
314 | const char* keyString = luaL_checkstring(L, 4);
315 | const int numBins = lua_tointeger(L, 5);
316 |
317 | as_operations ops = add_bins_to_increment(L, 6, numBins);
318 |
319 | as_key key;
320 | as_key_init(&key, nameSpace, set, keyString);
321 | // Apply the operations. Since the record does not exist, it will be created
322 | // and the bins initialized with the ops' integer values.
323 | aerospike_key_operate(as, &err, NULL, &key, &ops, NULL);
324 |
325 | as_operations_destroy(&ops);
326 | as_key_destroy(&key);
327 |
328 | lua_pushnumber(L, err.code);
329 | lua_pushstring(L, err.message);
330 | return 2;
331 | }
332 |
333 | static const struct luaL_Reg as_client [] = {
334 | {"connect", connect},
335 | {"disconnect", disconnect},
336 | {"get", get},
337 | {"put", put},
338 | {"increment", increment},
339 | {NULL, NULL}
340 | };
341 |
342 | extern int luaopen_as_lua(lua_State *L){
343 | luaL_register(L, "as_lua", as_client);
344 | return 0;
345 | }
346 |
347 |
--------------------------------------------------------------------------------
/test/main.lua:
--------------------------------------------------------------------------------
1 |
2 | local as = require "as_lua"
3 |
4 | function tprint (tbl, indent)
5 | if not indent then indent = 0 end
6 | for k, v in pairs(tbl) do
7 | formatting = string.rep(" ", indent) .. k .. ": "
8 | if type(v) == "table" then
9 | print(formatting)
10 | tprint(v, indent+1)
11 | else
12 | print(formatting .. v)
13 | end
14 | end
15 | end
16 |
17 |
18 | local function main()
19 | local record
20 | local err
21 | local message
22 | local cluster
23 |
24 | err, message, cluster = as.connect("127.0.0.1", 3000)
25 |
26 | if err ~= 0 then
27 | print(err, message)
28 | return
29 | end
30 |
31 | print("## connected ##")
32 |
33 | local bins = {}
34 | bins["uid"] = "peter001"
35 | bins["name"] = "Peter"
36 | bins["dob"] = 19800101
37 |
38 | err, message = as.put(cluster, "test", "test", "peter001", 3, bins)
39 | print("saved record peter001", err, message)
40 |
41 | err, message, record = as.get(cluster, "test", "test", "peter001")
42 | print("read record peter001", err, message)
43 | tprint(record, 1)
44 |
45 | bins = {}
46 | bins["uid"] = "peter002"
47 | bins["name"] = "Peter2"
48 | bins["dob"] = 19800102
49 |
50 | err, message = as.put(cluster, "test", "test", "peter002", 3, bins)
51 | print("saved record peter002", err, message)
52 |
53 | bins = {}
54 | bins["uid"] = "peter004"
55 | bins["name"] = "Peter4"
56 | bins["dob"] = 19800102
57 | bins["animals"] = {"cats","mice","dogs","elephants","snakes"}
58 |
59 | err, message = as.put(cluster, "test", "test", "peter004", 4, bins)
60 | print("saved record peter004", err, message)
61 |
62 | bins = {}
63 | bins["counter"] = 1
64 | err, message = as.increment(cluster, "test", "test", "peter003", 1, bins)
65 | print("incremented record", err, message)
66 |
67 | err, message, record = as.get(cluster, "test", "test", "peter003")
68 | print("read record", err, message)
69 | tprint(record, 1)
70 |
71 | err, message, record = as.get(cluster, "test", "test", "peter004")
72 | print("read record", err, message)
73 | tprint(record, 1)
74 |
75 | bins = {}
76 | bins["uid"] = "peter005"
77 | bins["name"] = "Peter5"
78 | bins["dob"] = 19800102
79 | bins["animals"] = {"cats","mice","dogs","elephants","snakes"}
80 | bins["weight"] = 72.5
81 |
82 | err, message = as.put(cluster, "test", "test", "peter005", 5, bins)
83 | print("saved record peter005", err, message)
84 |
85 | err, message, record = as.get(cluster, "test", "test", "peter005")
86 | print("read record", err, message)
87 | tprint(record, 1)
88 |
89 | err, message = as.disconnect(cluster)
90 | print("disconnected", err, message)
91 |
92 | end
93 | main()
94 |
--------------------------------------------------------------------------------