hugg-orm 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fcefba25435c17f1d48c113fb95cd455999188bd
4
+ data.tar.gz: 9fa82007c4e17a0565d2e38098ea312eebfceefa
5
+ SHA512:
6
+ metadata.gz: 98439bedf84eafe456465061514d3dd00d8e8d879cc82f81fceb8fb1236df73d4971ff409e8a8c16449d88301cf370a86ff9136e81fdef276aad3e7a2af3fa1d
7
+ data.tar.gz: 167741b1ed8bdd9970ab6cda82957a3b2e7f2466c4c1b5088e6126e9dfe22d801cf4beb4da1b403e35f6d80352462b3469dccc3626722b4831990309d7be4cd1
@@ -0,0 +1,9 @@
1
+ require 'active_support/all'
2
+
3
+ require "hugg_orm/version"
4
+ require "hugg_orm/connection"
5
+ require "hugg_orm/persistence"
6
+ require 'hugg_orm/query'
7
+
8
+ module HuggORM
9
+ end
@@ -0,0 +1,71 @@
1
+ require 'forwardable'
2
+ require 'pg'
3
+
4
+ module HuggORM
5
+ class Connection
6
+ extend Forwardable
7
+
8
+ RETRIES = 1
9
+
10
+ attr_reader :options
11
+
12
+ def self.db
13
+ @_db ||= self.new
14
+ end
15
+
16
+ def connection
17
+ return @connection unless @connection.nil?
18
+ connect(@options)
19
+ @connection
20
+ end
21
+
22
+ def options(opts = {})
23
+ @options = opts
24
+ end
25
+
26
+ def connect(opts = {})
27
+ @options = opts
28
+ @connection = PG.connect(opts)
29
+ self
30
+ end
31
+
32
+ def disconnect
33
+ connection.finish if @connection
34
+ @connection = nil
35
+ self
36
+ end
37
+
38
+ def reconnect
39
+ disconnect
40
+ connect(@options)
41
+ self
42
+ end
43
+
44
+ def method_missing(meth, *args, &block)
45
+ if connection.respond_to?(meth)
46
+ method_retry(meth, *args, &block)
47
+ else
48
+ super
49
+ end
50
+ end
51
+
52
+ def method_retry(method, *args, &block)
53
+ tries ||= RETRIES + 1
54
+ connection.send(method, *args, &block)
55
+ rescue PG::ConnectionBad, PG::AdminShutdown
56
+ if (tries -= 1) > 0
57
+ reconnect
58
+ retry
59
+ end
60
+ raise
61
+ end
62
+
63
+ def exec(*args)
64
+ method_retry(:exec, *args)
65
+ end
66
+
67
+ def exec_params(*args)
68
+ method_retry(:exec_params, *args)
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,204 @@
1
+ module HuggORM
2
+ module Persistence
3
+ include Comparable
4
+
5
+ def self.included(base)
6
+ base.send(:include, InstanceMethods)
7
+ base.extend(ClassMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ attr_accessor :_table_name, :_primary_key, :_key_field, :_exclude_fields, :_include_fields
12
+
13
+ def table_name(table_name = nil)
14
+ self._table_name = table_name unless table_name.nil?
15
+ self._table_name
16
+ end
17
+
18
+ def primary_key(primary_key = nil)
19
+ self._primary_key = primary_key unless primary_key.nil?
20
+ self._primary_key
21
+ end
22
+
23
+ def key_field(key_field = nil)
24
+ self._key_field = key_field.to_sym unless key_field.nil?
25
+ self._key_field ||= :id
26
+ end
27
+
28
+ def exclude_fields(*fields)
29
+ self._exclude_fields = fields unless fields.empty?
30
+ self._exclude_fields ||= []
31
+ end
32
+
33
+ def include_fields(*fields)
34
+ self._include_fields = fields unless fields.empty?
35
+ self._include_fields ||= []
36
+ end
37
+
38
+ def find(id)
39
+ where("#{primary_key} = ?", [id]).select.first
40
+ end
41
+
42
+ def all
43
+ results = new_query.select
44
+ new_collection(results)
45
+ end
46
+
47
+ def select(query = nil, where: nil, order: nil, limit: nil, offset: nil)
48
+ return new_collection(query.select) if query
49
+
50
+ query = new_query
51
+ query.where(where[:conditions], where[:values]) if where
52
+ query.order(order) if order
53
+ query.limit(limit) if limit
54
+ query.offset(offset) if offset
55
+
56
+ new_collection(query.select)
57
+ end
58
+
59
+ def create(data)
60
+ new(data) if new_query.insert(data) > 0
61
+ end
62
+
63
+ def update(id, data)
64
+ results = where("#{primary_key} = ?", [id]).update(data, true)
65
+ new(results.first) unless results.empty?
66
+ end
67
+
68
+ def destroy(id)
69
+ where("#{primary_key} = ?", [id]).delete > 0
70
+ end
71
+
72
+ def count
73
+ new_query.count
74
+ end
75
+
76
+ def where(conditions, values = [])
77
+ new_query.where(conditions, values)
78
+ end
79
+
80
+ def limit(limit, offset = nil)
81
+ new_query.limit(limit, offset)
82
+ end
83
+
84
+ def order(*args)
85
+ new_query.order(*args)
86
+ end
87
+
88
+ def new_query
89
+ Query.new(table_name)
90
+ end
91
+
92
+ def new_collection(data_ary)
93
+ data_ary.map { |data| new(data) }
94
+ end
95
+
96
+ def to_pgtimestamp(field)
97
+ "to_timestamp(#{field}, 'YYYY-MM-DD HH24:MI:SS')"
98
+ end
99
+
100
+ def string_to_pgtimestamp(string)
101
+ to_pgtimestamp("'#{string}'")
102
+ end
103
+
104
+ def escape_like(str = '')
105
+ pat = Regexp.union("\\", "%", "_")
106
+ str.gsub(pat) { |mat| ["\\", mat].join }
107
+ end
108
+
109
+ end
110
+
111
+ module InstanceMethods
112
+ attr_accessor :uuid, :data
113
+
114
+ def initialize(data = {})
115
+ @data = {}
116
+ update_attributes(data) unless data.empty?
117
+ end
118
+
119
+ def key
120
+ @data[self.class.key_field]
121
+ end
122
+
123
+ def set_id
124
+ # Set id based on key field, but only if id isn't already set and
125
+ # the key method has been overridden and returns data.
126
+ @data[self.class.key_field] = key if @data[self.class.key_field].nil? && key
127
+ end
128
+
129
+ def update_attributes(update_data)
130
+ # Remove fields not set to be included
131
+ unless self.class.include_fields.empty?
132
+ update_data = self.class.include_fields.each_with_object({}) do |key, hash|
133
+ hash[key] = update_data[key] if update_data.has_key? key
134
+ end
135
+ end
136
+
137
+ # Update all fields unless they have been excluded
138
+ update_data.each do |field, value|
139
+ @data[field] = value unless self.class.exclude_fields.include?(field)
140
+ end
141
+
142
+ # Set id based on key method.
143
+ set_id
144
+
145
+ self
146
+ end
147
+
148
+ def destroy
149
+ if self.class.destroy(key)
150
+ @data = {}
151
+ @state = :destroyed
152
+ end
153
+
154
+ self
155
+ end
156
+
157
+ def save
158
+ updated_data = self.class.where("#{self.class.primary_key} = ?", [key]).update(@data, true)
159
+
160
+ if updated_data != 0
161
+ @data = updated_data
162
+ @state = :updated
163
+ else
164
+ self.class.new_query.insert(@data)
165
+ @state = :created
166
+ end
167
+
168
+ self
169
+ end
170
+
171
+ def destroyed?
172
+ @state == :destroyed
173
+ end
174
+
175
+ def updated?
176
+ @state == :updated
177
+ end
178
+
179
+ def created?
180
+ @state == :created
181
+ end
182
+
183
+ def dump
184
+ str = "#{self.class.name}:\n"
185
+ @data.sort.each do |field, value|
186
+ str << " #{field}: #{value}\n"
187
+ end
188
+ str
189
+ end
190
+
191
+ def fetch(*args)
192
+ @data.send(:fetch, *args)
193
+ end
194
+
195
+ def has_field?(field)
196
+ @data.has_key?(field)
197
+ end
198
+
199
+ def <=>(o)
200
+ o.kind_of?(self.class) && @data == o.data ? 0 : nil
201
+ end
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,98 @@
1
+ module HuggORM
2
+ class Query
3
+ attr_reader :table, :column_name, :values,
4
+ :_command, :_where, :_order, :_limit, :_offset, :_returning
5
+
6
+ def initialize(table, column_name = 'data')
7
+ @table = table
8
+ @column_name = column_name
9
+ @values = []
10
+ end
11
+
12
+ def run
13
+ HuggORM::Connection.db.exec_params(to_sql, @values)
14
+ end
15
+
16
+ def to_sql
17
+ sql = "#{@_command} #{@_where} #{@_order} #{@_limit} #{@_offset} #{@_returning}".strip
18
+ sql.gsub!(/\s{2,}/, ' ')
19
+ sql
20
+ end
21
+
22
+ def insert(data)
23
+ @_command = "INSERT INTO #{@table} (#{@column_name}) VALUES (#{next_placeholder})"
24
+ @values << data.to_json
25
+ pg_result = run
26
+ pg_result.cmd_tuples
27
+ end
28
+
29
+ def update(data, return_data = false)
30
+ @_command = "UPDATE #{@table} SET #{@column_name} = #{@column_name} || #{next_placeholder}::jsonb"
31
+ @values << data.to_json
32
+
33
+ if return_data
34
+ @_returning = "RETURNING #{@column_name}"
35
+ return run.map { |tuple| deserialize(tuple["#{@column_name}"]) }
36
+ end
37
+
38
+ run.cmd_tuples
39
+ end
40
+
41
+ def select
42
+ @_command = "SELECT #{@column_name} FROM #{@table}"
43
+ pg_result = run
44
+ pg_result.map { |tuple| deserialize(tuple["#{@column_name}"]) }
45
+ end
46
+
47
+ def delete
48
+ @_command = "DELETE FROM #{@table}"
49
+ run.cmd_tuples
50
+ end
51
+
52
+ def count
53
+ @_command = "SELECT COUNT(*) FROM #{@table}"
54
+ run.getvalue(0, 0).to_i
55
+ end
56
+
57
+ def where(conditions, values = [])
58
+ values.size.times { |i| conditions.sub!(/\?/, next_placeholder(i + 1)) }
59
+ @_where = "WHERE #{conditions}"
60
+ @values += values
61
+ self
62
+ end
63
+
64
+ def limit(limit, offset = nil)
65
+ @_limit = "LIMIT #{next_placeholder}"
66
+ @values << limit
67
+ self.offset(offset) if offset
68
+ self
69
+ end
70
+
71
+ def offset(offset)
72
+ @_offset = "OFFSET #{next_placeholder}"
73
+ @values << offset
74
+ self
75
+ end
76
+
77
+ def order(*args)
78
+ fields = []
79
+ args.first.each_pair { |field, order| fields << "#{wrap_json(field)} #{order}" }
80
+ @_order = "ORDER BY #{fields.join(', ')}"
81
+ self
82
+ end
83
+
84
+ private
85
+
86
+ def deserialize(data)
87
+ JSON.parse(data, symbolize_names: true)
88
+ end
89
+
90
+ def next_placeholder(offset = 1)
91
+ "$#{@values.size + offset}"
92
+ end
93
+
94
+ def wrap_json(field)
95
+ "#{@column_name}->>'#{field}'"
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,3 @@
1
+ module HuggORM
2
+ VERSION = "1.0.0"
3
+ end
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hugg-orm
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Olle Johansson
8
+ - Lúcio Rosa
9
+ - Avidity
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2016-10-31 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: pg
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - "~>"
20
+ - !ruby/object:Gem::Version
21
+ version: '0.8'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - "~>"
27
+ - !ruby/object:Gem::Version
28
+ version: '0.8'
29
+ - !ruby/object:Gem::Dependency
30
+ name: activesupport
31
+ requirement: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - "~>"
34
+ - !ruby/object:Gem::Version
35
+ version: '4.2'
36
+ type: :runtime
37
+ prerelease: false
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - "~>"
41
+ - !ruby/object:Gem::Version
42
+ version: '4.2'
43
+ - !ruby/object:Gem::Dependency
44
+ name: bundler
45
+ requirement: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '1.11'
50
+ type: :development
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - "~>"
55
+ - !ruby/object:Gem::Version
56
+ version: '1.11'
57
+ - !ruby/object:Gem::Dependency
58
+ name: rake
59
+ requirement: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - "~>"
62
+ - !ruby/object:Gem::Version
63
+ version: '10.0'
64
+ type: :development
65
+ prerelease: false
66
+ version_requirements: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - "~>"
69
+ - !ruby/object:Gem::Version
70
+ version: '10.0'
71
+ - !ruby/object:Gem::Dependency
72
+ name: rspec
73
+ requirement: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - "~>"
76
+ - !ruby/object:Gem::Version
77
+ version: '3.0'
78
+ type: :development
79
+ prerelease: false
80
+ version_requirements: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - "~>"
83
+ - !ruby/object:Gem::Version
84
+ version: '3.0'
85
+ description: Ruby Object Relational Mapper for JSON-based models with PostgreSQL
86
+ email:
87
+ - code@avidity.se
88
+ executables: []
89
+ extensions: []
90
+ extra_rdoc_files: []
91
+ files:
92
+ - lib/hugg_orm.rb
93
+ - lib/hugg_orm/connection.rb
94
+ - lib/hugg_orm/persistence.rb
95
+ - lib/hugg_orm/query.rb
96
+ - lib/hugg_orm/version.rb
97
+ homepage: https://github.com/avidity/hugg-orm
98
+ licenses:
99
+ - MIT
100
+ metadata: {}
101
+ post_install_message:
102
+ rdoc_options: []
103
+ require_paths:
104
+ - lib
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ requirements: []
116
+ rubyforge_project:
117
+ rubygems_version: 2.5.1
118
+ signing_key:
119
+ specification_version: 4
120
+ summary: Ruby ORM for Postgresql
121
+ test_files: []