3 function ends_with($str, $key) {
4 return strrpos($str, $key) == strlen($str) - strlen($key);
7 function ctype_alnum_underscore($str) {
8 return ctype_alnum(str_replace('_', '', $str));
11 function &array_ensure_item_has_array(&$array, $key) {
12 if (!array_key_exists($key, $array))
13 $array[$key] = array();
17 function array_get($array, $key, $default = NULL) {
18 if (!array_key_exists($key, $array))
23 function array_set_default(&$array, $key, $default) {
24 if (!array_key_exists($key, $array))
25 $array[$key] = $default;
30 function config($key) {
33 $_config = json_decode(file_get_contents(dirname(__FILE__) . '/../../config.json'), true);
34 return $_config[$key];
37 if (config('debug')) {
38 error_reporting(E_ALL | E_STRICT);
39 ini_set('display_errors', 'On');
41 error_reporting(E_ERROR);
43 date_default_timezone_set('UTC');
47 private $connection = false;
49 function __destruct() {
50 if ($this->connection)
51 pg_close($this->connection);
52 $this->connection = false;
55 function is_true($value) {
60 $databaseConfig = config('database');
61 $this->connection = pg_connect('host=' . $databaseConfig['host'] . ' port=' . $databaseConfig['port']
62 . ' dbname=' . $databaseConfig['name'] . ' user=' . $databaseConfig['username'] . ' password=' . $databaseConfig['password']);
63 return $this->connection ? true : false;
66 private function prefixed_column_names($columns, $prefix = NULL) {
68 return join(', ', $columns);
69 return $prefix . '_' . join(', ' . $prefix . '_', $columns);
72 private function prefixed_name($column, $prefix = NULL) {
73 return $prefix ? $prefix . '_' . $column : $column;
76 private function prepare_params($params, &$placeholders, &$values) {
77 $column_names = array_keys($params);
79 $i = count($values) + 1;
80 foreach ($column_names as $name) {
81 assert(ctype_alnum_underscore($name));
82 array_push($placeholders, '$' . $i);
83 array_push($values, $params[$name]);
90 function insert_row($table, $prefix, $params, $returning = 'id') {
91 $placeholders = array();
93 $column_names = $this->prepare_params($params, $placeholders, $values);
95 assert(!$prefix || ctype_alnum_underscore($prefix));
96 $column_names = $this->prefixed_column_names($column_names, $prefix);
97 $placeholders = join(', ', $placeholders);
100 $returning_column_name = $this->prefixed_name($returning, $prefix);
101 $rows = $this->query_and_fetch_all("INSERT INTO $table ($column_names) VALUES ($placeholders) RETURNING $returning_column_name", $values);
102 return $rows ? $rows[0][$returning_column_name] : NULL;
105 return $this->query_and_get_affected_rows("INSERT INTO $table ($column_names) VALUES ($placeholders)", $values) == 1;
108 function select_or_insert_row($table, $prefix, $select_params, $insert_params = NULL, $returning = 'id') {
109 return $this->_select_update_or_insert_row($table, $prefix, $select_params, $insert_params, $returning, FALSE);
112 function update_or_insert_row($table, $prefix, $select_params, $insert_params = NULL, $returning = 'id') {
113 return $this->_select_update_or_insert_row($table, $prefix, $select_params, $insert_params, $returning, TRUE);
116 private function _select_update_or_insert_row($table, $prefix, $select_params, $insert_params, $returning, $should_update) {
119 $select_placeholders = array();
120 $select_column_names = $this->prepare_params($select_params, $select_placeholders, $values);
121 $select_values = array_slice($values, 0);
123 if ($insert_params === NULL)
124 $insert_params = $select_params;
125 $insert_placeholders = array();
126 $insert_column_names = $this->prepare_params($insert_params, $insert_placeholders, $values);
128 assert(!!$returning);
129 assert(!$prefix || ctype_alnum_underscore($prefix));
130 $returning_column_name = $returning == '*' ? '*' : $this->prefixed_name($returning, $prefix);
131 $select_column_names = $this->prefixed_column_names($select_column_names, $prefix);
132 $select_placeholders = join(', ', $select_placeholders);
133 $query = "SELECT $returning_column_name FROM $table WHERE ($select_column_names) = ($select_placeholders)";
135 $insert_column_names = $this->prefixed_column_names($insert_column_names, $prefix);
136 $insert_placeholders = join(', ', $insert_placeholders);
138 // http://stackoverflow.com/questions/1109061/insert-on-duplicate-update-in-postgresql
140 if ($should_update) {
141 $rows = $this->query_and_fetch_all("UPDATE $table SET ($insert_column_names) = ($insert_placeholders)
142 WHERE ($select_column_names) = ($select_placeholders) RETURNING $returning_column_name", $values);
145 $rows = $this->query_and_fetch_all("INSERT INTO $table ($insert_column_names) SELECT $insert_placeholders
146 WHERE NOT EXISTS ($query) RETURNING $returning_column_name", $values);
148 if (!$should_update && !$rows)
149 $rows = $this->query_and_fetch_all($query, $select_values);
151 return $rows ? ($returning == '*' ? $rows[0] : $rows[0][$returning_column_name]) : NULL;
154 function select_first_row($table, $prefix, $params, $order_by = NULL) {
155 return $this->select_first_or_last_row($table, $prefix, $params, $order_by, FALSE);
158 function select_last_row($table, $prefix, $params, $order_by = NULL) {
159 return $this->select_first_or_last_row($table, $prefix, $params, $order_by, TRUE);
162 private function select_first_or_last_row($table, $prefix, $params, $order_by, $descending_order) {
163 $rows = $this->select_rows($table, $prefix, $params, $order_by, $descending_order, 0, 1);
164 return $rows ? $rows[0] : NULL;
167 function select_rows($table, $prefix, $params,
168 $order_by = NULL, $descending_order = FALSE, $offset = NULL, $limit = NULL) {
170 $placeholders = array();
172 $column_names = $this->prefixed_column_names($this->prepare_params($params, $placeholders, $values), $prefix);
173 $placeholders = join(', ', $placeholders);
174 $query = "SELECT * FROM $table WHERE ($column_names) = ($placeholders)";
176 assert(ctype_alnum_underscore($order_by));
177 $query .= ' ORDER BY ' . $this->prefixed_name($order_by, $prefix);
178 if ($descending_order)
181 if ($offset !== NULL)
182 $query .= ' OFFSET ' . intval($offset);
184 $query .= ' LIMIT ' . intval($limit);
186 return $this->query_and_fetch_all($query, $values);
189 function query_and_get_affected_rows($query, $params = array()) {
190 if (!$this->connection)
192 $result = pg_query_params($this->connection, $query, $params);
195 return pg_affected_rows($result);
198 function query_and_fetch_all($query, $params = array()) {
199 if (!$this->connection)
201 $result = pg_query_params($this->connection, $query, $params);
204 if (pg_num_rows($result) == 0)
206 return pg_fetch_all($result);
209 function query($query, $params = array()) {
210 if (!$this->connection)
212 return pg_query_params($this->connection, $query, $params);
215 function fetch_next_row($result) {
216 return pg_fetch_assoc($result);
219 function fetch_table($table_name, $column_to_be_ordered_by = null) {
220 if (!$this->connection || !ctype_alnum_underscore($table_name) || ($column_to_be_ordered_by && !ctype_alnum_underscore($column_to_be_ordered_by)))
223 if ($column_to_be_ordered_by)
224 $clauses .= 'ORDER BY ' . $column_to_be_ordered_by;
225 return $this->query_and_fetch_all("SELECT * FROM $table_name $clauses");
228 function begin_transaction() {
229 return $this->connection and pg_query($this->connection, "BEGIN");
232 function commit_transaction() {
233 return $this->connection and pg_query($this->connection, 'COMMIT');
236 function rollback_transaction() {
237 return $this->connection and pg_query($this->connection, 'ROLLBACK');