actn-db 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,136 @@
1
+ class Builder
2
+
3
+ constructor: (@schema_name, @table_name, @search_path, @query) ->
4
+ @query.select ?= "*"
5
+ @params = []
6
+ @i = 0
7
+
8
+ qm: -> "$#{@i += 1}"
9
+
10
+ make_select: ->
11
+ if @query?.select?.indexOf('COUNT') > -1
12
+ @query.select
13
+ else
14
+ if @query.select is "*"
15
+ "data"
16
+ else
17
+ @params.push _.flatten([@query.select]).join(".")
18
+ "__select(data, #{@qm()}) as data" #::text
19
+
20
+
21
+ make_where: (q, join_by = 'AND') ->
22
+ sql = []
23
+ for k, subquery of q
24
+ switch k
25
+ when 'and', 'AND', '&', '&&'
26
+ sql.push "(#{make_where(subquery, 'AND')})"
27
+ when 'or', 'OR', '|', '||'
28
+ sql.push "(#{make_where(subquery, 'OR')})"
29
+ when 'not', 'NOT', '!'
30
+ sql.push "NOT (#{make_where(subquery, 'AND')})"
31
+ else
32
+ if _.isArray(subquery)
33
+ @params.push k
34
+ @params.push subquery[1]
35
+ sql.push "#{@plv8_key(subquery[1])} #{subquery[0]} #{@plv8_qm(subquery[1])}"
36
+ else if _.isObject(subquery)
37
+ comparisons = []
38
+ for symbol, value in subquery
39
+ comparisons.push "#{symbol} #{@plv8_qm(value)}"
40
+ @params.push k
41
+ @params.push value
42
+ sql.push _.map(comparisons, (comparison) -> "#{@plv8_key(value)} #{comparison}").join(" AND ")
43
+ else
44
+ @params.push k
45
+ @params.push subquery
46
+ sql.push "#{@plv8_key(subquery)} = #{@plv8_qm(subquery)}"
47
+
48
+ sql.join "\n#{join_by} "
49
+
50
+
51
+ make_order_by: () ->
52
+ ord = @query.order_by
53
+ str = []
54
+ if _.isArray(ord)
55
+ @params.push ord[0]
56
+ str.push "#{@plv8_key(ord[1])} #{ord[1].toUpperCase()}"
57
+ else if _.isObject(ord)
58
+ for k,v in ord
59
+ @params.push v
60
+ str.push "#{@plv8_key(k)} #{k.toUpperCase()}"
61
+ else
62
+ @params.push ord
63
+ str.push @qm()
64
+ str.join(",")
65
+
66
+
67
+ make_limit: ->
68
+ @params.push @query.limit
69
+ @qm()
70
+
71
+
72
+ make_offset: ->
73
+ @params.push @query.offset
74
+ @qm()
75
+
76
+
77
+ build_select: ->
78
+ sql = []
79
+ sql.push "SET search_path TO #{@search_path};"
80
+ sql.push "SELECT #{@make_select()} FROM #{@schema_name}.#{@table_name}"
81
+ sql.push "WHERE #{@make_where(@query.where)}" unless _.isEmpty(@query.where)
82
+ sql.push "ORDER BY #{@make_order()}" if @query.order_by?
83
+ sql.push "LIMIT #{@make_limit()}" if @query.limit?
84
+ sql.push "OFFSET #{@make_offset()}" if @query.offset?
85
+ [sql.join("\n"), @params]
86
+
87
+ build_delete: ->
88
+ sql = []
89
+ sql.push "SET search_path TO #{@search_path};"
90
+ sql.push "DELETE FROM #{@schema_name}.#{@table_name}"
91
+ sql.push "WHERE #{@make_where(@query.where)}" unless _.isEmpty(@query.where)
92
+ sql.push "RETURNING data::json;"
93
+ [sql.join("\n"), @params]
94
+
95
+ build_update: (data, merge = true) ->
96
+
97
+ @params.push data
98
+ @params.push merge
99
+ sql = []
100
+ sql.push "SET search_path TO #{@search_path};"
101
+ sql.push "UPDATE #{@schema_name}.#{@table_name} SET data = __patch(data,#{@qm()},#{@qm()})"
102
+ sql.push "WHERE #{@make_where(@query.where)}" unless _.isEmpty(@query.where)
103
+ sql.push "RETURNING data::json;"
104
+ [sql.join("\n"), @params]
105
+
106
+ build_insert: (data, merge = true) ->
107
+ @params.push data
108
+ @params.push merge
109
+ sql = []
110
+ sql.push "SET search_path TO #{@search_path};"
111
+ sql.push "INSERT INTO #{@schema_name}.#{@table_name} (data) VALUES (__patch(__defaults(),#{@qm()},#{@qm()}))"
112
+ sql.push "RETURNING data::json;"
113
+ [sql.join("\n"), @params]
114
+
115
+ plv8_key: (value) -> "#{@typecast(value,true)}(data, #{@qm()}::text)" #::text
116
+
117
+ plv8_qm: (value) -> "#{@qm()}::#{@typecast(value)}"
118
+
119
+ typecast: (value, is_func = false) ->
120
+ type = if is_func then "__" else ""
121
+ if _.isBoolean(value)
122
+ type += "bool"
123
+ else if _.isDate(value)
124
+ type += "timestamp"
125
+ else if _.isNumber(value)
126
+ type += "integer"
127
+ else if _.isObject(value)
128
+ type += (if is_func then "text" else "json")
129
+ else if _.isArray(value)
130
+ type += (if is_func then "text" else "array")
131
+ else
132
+ type += (if is_func then "string" else "text")
133
+ type
134
+
135
+
136
+ global.actn.Builder = Builder
@@ -0,0 +1,218 @@
1
+ // Generated by CoffeeScript 1.6.3
2
+ (function() {
3
+ var Builder;
4
+
5
+ Builder = (function() {
6
+ function Builder(schema_name, table_name, search_path, query) {
7
+ var _base;
8
+ this.schema_name = schema_name;
9
+ this.table_name = table_name;
10
+ this.search_path = search_path;
11
+ this.query = query;
12
+ if ((_base = this.query).select == null) {
13
+ _base.select = "*";
14
+ }
15
+ this.params = [];
16
+ this.i = 0;
17
+ }
18
+
19
+ Builder.prototype.qm = function() {
20
+ return "$" + (this.i += 1);
21
+ };
22
+
23
+ Builder.prototype.make_select = function() {
24
+ var _ref, _ref1;
25
+ if (((_ref = this.query) != null ? (_ref1 = _ref.select) != null ? _ref1.indexOf('COUNT') : void 0 : void 0) > -1) {
26
+ return this.query.select;
27
+ } else {
28
+ if (this.query.select === "*") {
29
+ return "data";
30
+ } else {
31
+ this.params.push(_.flatten([this.query.select]).join("."));
32
+ return "__select(data, " + (this.qm()) + ") as data";
33
+ }
34
+ }
35
+ };
36
+
37
+ Builder.prototype.make_where = function(q, join_by) {
38
+ var comparisons, k, sql, subquery, symbol, value, _i, _len;
39
+ if (join_by == null) {
40
+ join_by = 'AND';
41
+ }
42
+ sql = [];
43
+ for (k in q) {
44
+ subquery = q[k];
45
+ switch (k) {
46
+ case 'and':
47
+ case 'AND':
48
+ case '&':
49
+ case '&&':
50
+ sql.push("(" + (make_where(subquery, 'AND')) + ")");
51
+ break;
52
+ case 'or':
53
+ case 'OR':
54
+ case '|':
55
+ case '||':
56
+ sql.push("(" + (make_where(subquery, 'OR')) + ")");
57
+ break;
58
+ case 'not':
59
+ case 'NOT':
60
+ case '!':
61
+ sql.push("NOT (" + (make_where(subquery, 'AND')) + ")");
62
+ break;
63
+ default:
64
+ if (_.isArray(subquery)) {
65
+ this.params.push(k);
66
+ this.params.push(subquery[1]);
67
+ sql.push("" + (this.plv8_key(subquery[1])) + " " + subquery[0] + " " + (this.plv8_qm(subquery[1])));
68
+ } else if (_.isObject(subquery)) {
69
+ comparisons = [];
70
+ for (value = _i = 0, _len = subquery.length; _i < _len; value = ++_i) {
71
+ symbol = subquery[value];
72
+ comparisons.push("" + symbol + " " + (this.plv8_qm(value)));
73
+ this.params.push(k);
74
+ this.params.push(value);
75
+ }
76
+ sql.push(_.map(comparisons, function(comparison) {
77
+ return "" + (this.plv8_key(value)) + " " + comparison;
78
+ }).join(" AND "));
79
+ } else {
80
+ this.params.push(k);
81
+ this.params.push(subquery);
82
+ sql.push("" + (this.plv8_key(subquery)) + " = " + (this.plv8_qm(subquery)));
83
+ }
84
+ }
85
+ }
86
+ return sql.join("\n" + join_by + " ");
87
+ };
88
+
89
+ Builder.prototype.make_order_by = function() {
90
+ var k, ord, str, v, _i, _len;
91
+ ord = this.query.order_by;
92
+ str = [];
93
+ if (_.isArray(ord)) {
94
+ this.params.push(ord[0]);
95
+ str.push("" + (this.plv8_key(ord[1])) + " " + (ord[1].toUpperCase()));
96
+ } else if (_.isObject(ord)) {
97
+ for (v = _i = 0, _len = ord.length; _i < _len; v = ++_i) {
98
+ k = ord[v];
99
+ this.params.push(v);
100
+ str.push("" + (this.plv8_key(k)) + " " + (k.toUpperCase()));
101
+ }
102
+ } else {
103
+ this.params.push(ord);
104
+ str.push(this.qm());
105
+ }
106
+ return str.join(",");
107
+ };
108
+
109
+ Builder.prototype.make_limit = function() {
110
+ this.params.push(this.query.limit);
111
+ return this.qm();
112
+ };
113
+
114
+ Builder.prototype.make_offset = function() {
115
+ this.params.push(this.query.offset);
116
+ return this.qm();
117
+ };
118
+
119
+ Builder.prototype.build_select = function() {
120
+ var sql;
121
+ sql = [];
122
+ sql.push("SET search_path TO " + this.search_path + ";");
123
+ sql.push("SELECT " + (this.make_select()) + " FROM " + this.schema_name + "." + this.table_name);
124
+ if (!_.isEmpty(this.query.where)) {
125
+ sql.push("WHERE " + (this.make_where(this.query.where)));
126
+ }
127
+ if (this.query.order_by != null) {
128
+ sql.push("ORDER BY " + (this.make_order()));
129
+ }
130
+ if (this.query.limit != null) {
131
+ sql.push("LIMIT " + (this.make_limit()));
132
+ }
133
+ if (this.query.offset != null) {
134
+ sql.push("OFFSET " + (this.make_offset()));
135
+ }
136
+ return [sql.join("\n"), this.params];
137
+ };
138
+
139
+ Builder.prototype.build_delete = function() {
140
+ var sql;
141
+ sql = [];
142
+ sql.push("SET search_path TO " + this.search_path + ";");
143
+ sql.push("DELETE FROM " + this.schema_name + "." + this.table_name);
144
+ if (!_.isEmpty(this.query.where)) {
145
+ sql.push("WHERE " + (this.make_where(this.query.where)));
146
+ }
147
+ sql.push("RETURNING data::json;");
148
+ return [sql.join("\n"), this.params];
149
+ };
150
+
151
+ Builder.prototype.build_update = function(data, merge) {
152
+ var sql;
153
+ if (merge == null) {
154
+ merge = true;
155
+ }
156
+ this.params.push(data);
157
+ this.params.push(merge);
158
+ sql = [];
159
+ sql.push("SET search_path TO " + this.search_path + ";");
160
+ sql.push("UPDATE " + this.schema_name + "." + this.table_name + " SET data = __patch(data," + (this.qm()) + "," + (this.qm()) + ")");
161
+ if (!_.isEmpty(this.query.where)) {
162
+ sql.push("WHERE " + (this.make_where(this.query.where)));
163
+ }
164
+ sql.push("RETURNING data::json;");
165
+ return [sql.join("\n"), this.params];
166
+ };
167
+
168
+ Builder.prototype.build_insert = function(data, merge) {
169
+ var sql;
170
+ if (merge == null) {
171
+ merge = true;
172
+ }
173
+ this.params.push(data);
174
+ this.params.push(merge);
175
+ sql = [];
176
+ sql.push("SET search_path TO " + this.search_path + ";");
177
+ sql.push("INSERT INTO " + this.schema_name + "." + this.table_name + " (data) VALUES (__patch(__defaults()," + (this.qm()) + "," + (this.qm()) + "))");
178
+ sql.push("RETURNING data::json;");
179
+ return [sql.join("\n"), this.params];
180
+ };
181
+
182
+ Builder.prototype.plv8_key = function(value) {
183
+ return "" + (this.typecast(value, true)) + "(data, " + (this.qm()) + "::text)";
184
+ };
185
+
186
+ Builder.prototype.plv8_qm = function(value) {
187
+ return "" + (this.qm()) + "::" + (this.typecast(value));
188
+ };
189
+
190
+ Builder.prototype.typecast = function(value, is_func) {
191
+ var type;
192
+ if (is_func == null) {
193
+ is_func = false;
194
+ }
195
+ type = is_func ? "__" : "";
196
+ if (_.isBoolean(value)) {
197
+ type += "bool";
198
+ } else if (_.isDate(value)) {
199
+ type += "timestamp";
200
+ } else if (_.isNumber(value)) {
201
+ type += "integer";
202
+ } else if (_.isObject(value)) {
203
+ type += (is_func ? "text" : "json");
204
+ } else if (_.isArray(value)) {
205
+ type += (is_func ? "text" : "array");
206
+ } else {
207
+ type += (is_func ? "string" : "text");
208
+ }
209
+ return type;
210
+ };
211
+
212
+ return Builder;
213
+
214
+ })();
215
+
216
+ global.actn.Builder = Builder;
217
+
218
+ }).call(this);
@@ -0,0 +1,76 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-04/schema",
3
+ "type": "object",
4
+ "properties": {
5
+ "uuid": {
6
+ "id": "#uuid",
7
+ "description": "Universal accessible name of the model, cannot be change after created"
8
+ },
9
+ "name": {
10
+ "id": "#name",
11
+ "description": "Universal accessible name of the model, cannot be change after created",
12
+ "type": "string"
13
+ },
14
+ "schema": {
15
+ "id": "#schema"
16
+ },
17
+ "indexes" : {
18
+ "id": "#indexes",
19
+ "description": "Database index definitions",
20
+ "type": "array",
21
+ "items": {
22
+ "type": "object",
23
+ "properties": {
24
+ "cols": {
25
+ "type": "object",
26
+ "patternProperties": {
27
+ ".{1,}": {
28
+ "type": "string"
29
+ }
30
+ }
31
+ },
32
+ "unique": { "type": "boolean" },
33
+ "concurrently": { "type": "boolean" }
34
+ },
35
+ "required": ["cols"]
36
+ },
37
+ "minItems": 1,
38
+ "maxItems": 10
39
+ },
40
+ "hooks": {
41
+ "type": "object",
42
+ "properties": {
43
+ "$ref": "#/definitions/hook"
44
+ }
45
+ }
46
+ },
47
+ "required": ["name"],
48
+ "readonly_attributes": ["name"],
49
+ "unique_attributes": ["name"],
50
+ "definitions": {
51
+ "hook":{
52
+ "id": "#hook",
53
+ "description": "Async jobs for after callbacks",
54
+ "type": "object",
55
+ "patternProperties": {
56
+ "after_[create|update|destroy]" : {
57
+ "type": "array",
58
+ "items": {
59
+ "type" : "object",
60
+ "properties": {
61
+ "name": { "type": "string" },
62
+ "run_at": { "type": "date" },
63
+ "conditions": {
64
+ "type": "array",
65
+ "items": { "type": "string" }
66
+ }
67
+ },
68
+ "required": ["name"]
69
+ },
70
+ "minItems": 1,
71
+ "maxItems": 20
72
+ }
73
+ }
74
+ }
75
+ }
76
+ }
@@ -0,0 +1,10 @@
1
+ require 'oj'
2
+
3
+ class ::Hash
4
+ def to_json
5
+ Oj.dump(self)
6
+ end
7
+ def as_json
8
+ self
9
+ end
10
+ end
@@ -0,0 +1,8 @@
1
+ module ::Kernel
2
+
3
+ def called_from(level=1)
4
+ arrs = caller((level||1)+1) or return
5
+ arrs[0] =~ /:(\d+)(?::in `(.*)')?/ ? [$`, $1.to_i, $2] : nil
6
+ end
7
+
8
+ end