so://phie

glue

A zero-boilerplate, ORM for PostgreSQL
git clone git://soophie.de/glue

blob: 8bfcd9cf66e4a6ba76ca1589308923ec1e42fa3d (5269 bytes)[doc][blame][raw]

1#ifndef _SO_GLUE_H

2#define _SO_GLUE_H

3

4#include <stddef.h>

5#include <stdbool.h>

6

7typedef void (*glue_fetch_fn)(char *, char *, void *);

8

9void glue_fetch(const char *query, size_t params_len, const char *params[params_len], glue_fetch_fn fn, void **data, size_t *len, size_t size);

10void glue_execute(const char *query, size_t params_len, const char *params[params_len]);

11void glue_get_string(char *src, char **dest);

12void glue_get_int(char *src, int *dest);

13void glue_get_double(char *src, double *dest);

14void glue_get_float(char *src, float *dest);

15void glue_get_bool(char *src, bool *dest);

16

17

18#define GLUE_TABLEDEF($name, $cols) \

19 typedef struct { \

20 $cols(_GLUE_X_COLDEF) \

21 } $name##_t; \

22 \

23 static inline void _##$name##_fetch_fn(char *column, char *value, void *data) { \

24 $name##_t *self = ($name##_t *) data; \

25 $cols(_GLUE_X_ASSIGN) \

26 } \

27 static inline void $name##_fetch(const char *query, size_t params_len, const char *params[params_len], $name##_t **data, size_t *len) { \

28 glue_fetch(query, params_len, params, _##$name##_fetch_fn, (void *) data, len, sizeof($name##_t)); \

29 } \

30 static inline void $name##_free($name##_t *self) { \

31 $cols(_GLUE_X_FREE) \

32 } \

33 \

34 static inline void $name##_list_free($name##_t *list, size_t len) { \

35 if (!list) return; \

36 for (size_t i = 0; i < len; i++) { \

37 $name##_free(&list[i]); \

38 } \

39 free(list); \

40 } \

41 \

42 static inline void $name##_dbg($name##_t *self) { \

43 fprintf(stdout, "(%s_t) {\n", #$name); \

44 $cols(_GLUE_X_DEBUG) \

45 fprintf(stdout, "}\n"); \

46 }

47

48#define _GLUE_X_COLDEF($type, $name, $getter, $freeable, $format) \

49 $type $name;

50

51#define _GLUE_X_FREE($type, $name, $getter, $freeable, $format) \

52 if ($freeable) { \

53 if (self->$name) { \

54 void **name = (void **) &self->$name; \

55 free(*name); \

56 *name = NULL; \

57 } \

58 }

59

60#define _GLUE_X_ASSIGN($type, $name, $getter, $freeable, $format) \

61 if (strcmp(column, #$name) == 0) { \

62 $getter(value, &self->$name); \

63 }

64

65#define _GLUE_X_DEBUG($type, $name, $getter, $freeable, $format) \

66 fprintf(stdout, " .%s = ", #$name); \

67 $format($name) \

68 fprintf(stdout, "\n");

69

70#define GLUE_FORMAT_INT($name) \

71 fprintf(stdout, "%d,", (int) self->$name);

72

73#define GLUE_FORMAT_TEXT($name) \

74 fprintf(stdout, "%s,", (const char *) self->$name);

75

76#define GLUE_COLDEF(X, $type, $name, $getter, $freeable, $format) \

77 X($type, $name, $getter, $freeable, $format)

78

79#define GLUE_COLDEF_INT(X, $name) \

80 X(int, $name, glue_get_int, 0, GLUE_FORMAT_INT)

81

82#define GLUE_COLDEF_TEXT(X, $name) \

83 X(char *, $name, glue_get_string, 1, GLUE_FORMAT_TEXT)

84

85#ifdef SO_GLUE_IMPL

86

87#include <stdio.h>

88#include <stdlib.h>

89#include <string.h>

90#include <inttypes.h>

91#include <libpq-fe.h>

92

93void glue_execute(const char *query, size_t params_len, const char *params[params_len]) {

94 PGconn *conn = PQconnectdb(GLUE_DB_INFO);

95 if (PQstatus(conn) != CONNECTION_OK) {

96 fprintf(stderr, "%s\n", PQerrorMessage(conn));

97 PQfinish(conn);

98 return;

99 }

100 PGresult *result = PQexecParams(conn, query, params_len, NULL, params, NULL, NULL, 0);

101 ExecStatusType status = PQresultStatus(result);

102 if (status != PGRES_COMMAND_OK) {

103 fprintf(stderr, "%s\n", PQerrorMessage(conn));

104 PQclear(result);

105 return;

106 }

107 PQclear(result);

108 PQfinish(conn);

109}

110

111void glue_fetch(const char *query, size_t params_len, const char *params[params_len], glue_fetch_fn fn, void **data, size_t *len, size_t size) {

112 PGconn *conn = PQconnectdb(GLUE_DB_INFO);

113 if (PQstatus(conn) != CONNECTION_OK) {

114 fprintf(stderr, "%s\n", PQerrorMessage(conn));

115 PQfinish(conn);

116 return;

117 }

118 PGresult *result = PQexecParams(conn, query, params_len, NULL, params, NULL, NULL, 0);

119 ExecStatusType status = PQresultStatus(result);

120 if (status != PGRES_TUPLES_OK) {

121 fprintf(stderr, "%s\n", PQerrorMessage(conn));

122 PQclear(result);

123 PQfinish(conn);

124 return;

125 }

126 size_t rows = PQntuples(result);

127 size_t cols = PQnfields(result);

128 if (rows > 0) {

129 for (size_t i = 0; i < rows; i++) {

130 void *ptr = realloc(*data, size * (*len + 1));

131 if (ptr == NULL) {

132 // TODO error message

133 PQclear(result);

134 PQfinish(conn);

135 return;

136 }

137 *data = ptr;

138 void *item = (char *) *data + size * (*len);

139 memset(item, 0, size);

140 (*len)++;

141 for (size_t j = 0; j < cols; j++) {

142 if (PQgetisnull(result, i, j)) {

143 continue;

144 }

145 char *column = PQfname(result, j);

146 char *value = PQgetvalue(result, i, j);

147 fn(column, value, item);

148 }

149 }

150 }

151 PQclear(result);

152 PQfinish(conn);

153}

154

155void glue_get_string(char *src, char **dest) {

156 size_t value_len = strlen(src);

157 if (value_len == 0) {

158 *dest = NULL;

159 return;

160 }

161 *dest = malloc(sizeof(char) * (value_len + 1));

162 memcpy(*dest, src, value_len);

163 (*dest)[value_len] = '\0';

164}

165

166void glue_get_int(char *src, int *dest) {

167 *dest = strtoimax(src, NULL, 10);

168}

169

170void glue_get_double(char *src, double *dest) {

171 *dest = strtod(src, NULL);

172}

173

174void glue_get_float(char *src, float *dest) {

175 *dest = strtof(src, NULL);

176}

177

178void glue_get_bool(char *src, bool *dest) {

179 *dest = strcmp("t", src) == 0;

180}

181

182#endif /* SO_GLUE_IMPL */

183#endif /* _SO_GLUE_H */