jrec 0.0.1

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: 9c8f3d76853a1ff9b072d76cc96a438b08349825
4
+ data.tar.gz: 43049379238ff7c5e50e938fe21e6d8295a95c67
5
+ SHA512:
6
+ metadata.gz: d511999e4c94ce5e031f77a208f62905720763c45355cb9d620b8ef0a21e5108eda8cd9131111b5476089d85fbcf6e8e5bd826ede65afb2bba0fc6fe12ce0814
7
+ data.tar.gz: f71e640198adc68926cf7652ff665f9d645c87c6a300f64f6999aaca2e471cf5b10094263a7326b5424c700767a2af4b41144272340432f30e9c1aa66a3be24b
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in jrec.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Onur Uyar
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,31 @@
1
+ # Jrec
2
+
3
+ Simple object modelling for Postgresql JSON
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'jrec'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install jrec
20
+
21
+ ## Usage
22
+
23
+ run `jrec --help` for cli usage
24
+
25
+ ## Contributing
26
+
27
+ 1. Fork it ( https://github.com/[my-github-username]/jrec/fork )
28
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
29
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
30
+ 4. Push to the branch (`git push origin my-new-feature`)
31
+ 5. Create a new Pull Request
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ end
7
+
8
+ task :default => :test
9
+
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'jrec'
4
+ require 'commander/import'
5
+ require 'active_support/inflector'
6
+
7
+ def db_config
8
+ @db_config ||= Jrec.config.dup.tap{|s| s.delete(:size) }
9
+ end
10
+
11
+ def pg_config
12
+ @pg_config ||= db_config.dup.merge({'dbname' => 'postgres'})
13
+ end
14
+
15
+ def run_sql sql, root = false
16
+ pg = PG::EM::Client.new(root ? pg_config : db_config)
17
+ puts "----SQL\n#{sql}\n----SQL END"
18
+ pg.exec(sql)
19
+ end
20
+
21
+ # :name is optional, otherwise uses the basename of this executable
22
+ program :name, 'Jrec'
23
+ program :version, '1.0.0'
24
+ program :description, 'Simple PLV8 Json Models'
25
+
26
+ command :'collection:create' do |c|
27
+ c.syntax = 'create NAME'
28
+ c.description = 'Create collection with given name'
29
+ c.action do |args, options|
30
+ coll = args[0].tableize
31
+ Jrec.exec_func "create_table", "public", coll
32
+ Jrec.exec_func "create_trigger", "public", coll
33
+ end
34
+ end
35
+
36
+ command :'collection:destroy' do |c|
37
+ c.syntax = 'destroy NAME'
38
+ c.description = 'Destroy collection with given name'
39
+ c.action do |args, options|
40
+ coll = args[0].tableize
41
+ Jrec.exec_func "drop_table", "public", coll
42
+ end
43
+ end
44
+
45
+ command :'db:reset' do |c|
46
+ c.syntax = 'reset'
47
+ c.description = 'Reset Database'
48
+ c.action do |args, options|
49
+ drop_schema rescue nil
50
+ create_schema
51
+ migrate
52
+ end
53
+ end
54
+
55
+ def migrate
56
+ # run setup if exists
57
+
58
+ setup_sql = "#{Jrec.gem_root}/lib/jrec/sql/setup.sql"
59
+ puts setup_sql
60
+ if File.exists?(setup_sql)
61
+ puts "Running Setup SQL File: #{setup_sql}"
62
+ run_sql(File.read(setup_sql))
63
+ end
64
+
65
+ path = "#{Jrec.root}/db/migrate"
66
+
67
+ # where are we?
68
+ puts "Migration running on: #{path}"
69
+
70
+ if File.exists?("#{path}/db/migrate")
71
+ Dir.glob("#{path}/db/migrate/*.sql").sort.each do |sql|
72
+
73
+ puts "Running SQL File: #{sql}"
74
+ run_sql(File.read(sql))
75
+
76
+ end
77
+ end
78
+ end
79
+ command :'db:migrate' do |c|
80
+ c.syntax = 'migrate'
81
+ c.description = 'Migrate Database'
82
+ c.action do |args, options|
83
+
84
+ migrate
85
+
86
+ end
87
+ end
88
+
89
+ def drop_schema
90
+ sql = "drop schema public cascade;"
91
+ run_sql sql
92
+ end
93
+ command :'db:drop_schema' do |c|
94
+ c.syntax = 'drop_schema'
95
+ c.description = 'Drops all schemas'
96
+ c.action do |args, options|
97
+ drop_schema
98
+ end
99
+ end
100
+
101
+ def create_schema
102
+ sql = "create schema public;"
103
+ run_sql sql
104
+ end
105
+ command :'db:create_schema' do |c|
106
+ c.syntax = 'drop_schema'
107
+ c.description = 'Create database'
108
+ c.action do |args, options|
109
+ create_schema
110
+ end
111
+ end
112
+
113
+ command :'db:drop' do |c|
114
+ c.syntax = 'drop'
115
+ c.description = 'Drop database'
116
+ c.action do |args, options|
117
+ sql = "DROP DATABASE IF EXISTS \"%s\";" % [db_config[:dbname]]
118
+ run_sql sql, true
119
+ end
120
+ end
121
+
122
+ command :'db:create' do |c|
123
+ c.syntax = 'drop'
124
+ c.description = 'Create database'
125
+ c.action do |args, options|
126
+ puts "Db Creating... #{db_config[:dbname]}"
127
+ sql = "CREATE DATABASE \"%s\" ENCODING = 'utf8';" % [db_config[:dbname]]
128
+ run_sql sql, true
129
+ end
130
+ end
131
+
132
+
133
+
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'jrec/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "jrec"
8
+ spec.version = Jrec::VERSION
9
+ spec.authors = ["Onur Uyar"]
10
+ spec.email = ["me@onuruyar.com"]
11
+ spec.summary = %q{Simple object mapping for Postgresql JSON}
12
+ spec.homepage = ""
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.7"
21
+ spec.add_development_dependency "rake", "~> 10.0"
22
+ spec.add_development_dependency "minitest"
23
+
24
+ spec.add_dependency "em-pg-client"
25
+ spec.add_dependency "activemodel"
26
+ spec.add_dependency "oj"
27
+ spec.add_dependency "commander"
28
+ end
@@ -0,0 +1,13 @@
1
+ require "jrec/version"
2
+ require "jrec/paths"
3
+ require "jrec/pg"
4
+ require "jrec/collection"
5
+ require "jrec/model"
6
+
7
+ module Jrec
8
+ extend PG
9
+ include Paths
10
+ def self.gem_root
11
+ @@gem_root ||= File.expand_path('../../', __FILE__)
12
+ end
13
+ end
@@ -0,0 +1,68 @@
1
+ require 'jrec/pg'
2
+
3
+ module Jrec
4
+ class Collection
5
+
6
+ include PG
7
+
8
+ def self.tables
9
+ @@tables ||= {}
10
+ end
11
+
12
+ def self.[]table
13
+ self.tables[table] ||= new(:public,table)
14
+ end
15
+
16
+ attr_accessor :table, :schema
17
+
18
+ def initialize schema, table
19
+ self.table = table
20
+ self.schema = schema
21
+ end
22
+
23
+ # where(:not => { active: :true }, :or => { name: { :== => 'Igor'}, age: { :>= => 20 } })
24
+
25
+ [:query, :upsert, :update, :delete].each do |meth|
26
+ class_eval <<-CODE
27
+ def #{meth} *args
28
+ exec_func :#{meth}, schema, table, *args.map(&:to_json)
29
+ end
30
+ CODE
31
+ end
32
+
33
+ [:query].each do |meth|
34
+ class_eval <<-CODE
35
+ def inspect_#{meth} *args
36
+ inspect_func :#{meth}, schema, table, *args.map(&:to_json)
37
+ end
38
+ CODE
39
+ end
40
+
41
+ def count conds = {}
42
+ exec_func :query, schema, table, {select: 'COUNT(id)'}.merge(conds).to_json
43
+ end
44
+
45
+
46
+ def all
47
+ where({})
48
+ end
49
+
50
+ def where cond
51
+ query({where: cond})
52
+ end
53
+
54
+ def find_by cond
55
+ query({where: cond,limit: 1})[1..-2]
56
+ end
57
+
58
+ def find uuid
59
+ find_by(uuid: uuid)
60
+ end
61
+
62
+ def delete_all
63
+ delete({})
64
+ end
65
+
66
+
67
+ end
68
+ end
@@ -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
@@ -0,0 +1,11 @@
1
+ require 'oj'
2
+ require 'uri'
3
+
4
+ class ::String
5
+ def to_json
6
+ self
7
+ end
8
+ def as_json
9
+ Oj.load(self)
10
+ end
11
+ end
@@ -0,0 +1,167 @@
1
+ require 'jrec/pg'
2
+ require 'jrec/collection'
3
+ require "active_model"
4
+
5
+
6
+ module Jrec
7
+ class Model
8
+
9
+ include PG
10
+
11
+ include ActiveModel::Model
12
+ extend ActiveModel::Callbacks
13
+ include ActiveModel::Validations
14
+ include ActiveModel::Validations::Callbacks
15
+ include ActiveModel::Serializers::JSON
16
+
17
+ define_model_callbacks :create
18
+ define_model_callbacks :update
19
+ define_model_callbacks :destroy
20
+
21
+ class << self
22
+
23
+ attr_accessor :schema, :table, :collection
24
+
25
+ def collection
26
+ @collection ||= Collection.new(schema, table)
27
+ end
28
+
29
+ def data_attr_accessor *fields
30
+ fields.each do |field|
31
+ class_eval %Q{
32
+ def #{field}; self.attributes['#{field}'] end
33
+ def #{field}=val; self.attributes['#{field}']=val end
34
+ }
35
+ end
36
+ end
37
+
38
+ def create data = {}
39
+ record = new(data)
40
+ record.save
41
+ record
42
+ end
43
+
44
+ [:upsert, :update, :delete, :delete_all].each do |meth|
45
+ class_eval <<-RUBY
46
+ def #{meth} *args
47
+ collection.#{meth}(*args)
48
+ end
49
+ RUBY
50
+ end
51
+
52
+ [:find_by, :find].each do |meth|
53
+ class_eval <<-RUBY
54
+ def #{meth} conds
55
+ return nil if conds.empty?
56
+ new.from_json(collection.#{meth}(conds)) rescue nil
57
+ end
58
+ RUBY
59
+ end
60
+
61
+ [:all, :where].each do |meth|
62
+ class_eval <<-RUBY
63
+ def #{meth} *args
64
+ (Oj.load(collection.#{meth}(*args)) rescue {}).map{ |attrs| new(attrs) }
65
+ end
66
+ RUBY
67
+ end
68
+
69
+ def count conds = {}
70
+ collection.count(conds).match(/(\d+)/)[1].to_i
71
+ end
72
+
73
+ end
74
+
75
+ self.schema ||= "public"
76
+
77
+ attr_accessor :attributes
78
+ data_attr_accessor :uuid, :locale, :created_at, :updated_at
79
+
80
+
81
+ def initialize data = {}
82
+ data ||= {}
83
+ register_attr_accessors data
84
+ super(data)
85
+ end
86
+
87
+ def attributes
88
+ @attributes ||= {}
89
+ end
90
+
91
+ def persisted?
92
+ self.uuid.present?
93
+ end
94
+
95
+ def uuid
96
+ self.attributes['uuid']
97
+ end
98
+
99
+ ##
100
+ # persistency
101
+
102
+ def save
103
+ create_or_update if valid?
104
+ end
105
+
106
+ def update attrs
107
+ register_attr_accessors attrs
108
+ self.attributes.update(attrs)
109
+ save
110
+ end
111
+
112
+ def destroy
113
+ return unless self.persisted?
114
+ run_callbacks :destroy do
115
+ if result = self.class.delete(identity)
116
+ process_response result
117
+ end
118
+ end
119
+ end
120
+
121
+
122
+ private
123
+
124
+ def create_or_update
125
+ self.persisted? ? _update : _upsert
126
+ end
127
+
128
+ def _update
129
+ run_callbacks :update do
130
+ if result = self.class.update(self.attributes.merge(identity))
131
+ process_response result
132
+ end
133
+ end
134
+ end
135
+
136
+ def _upsert
137
+ run_callbacks :create do
138
+ if result = self.class.upsert(self.attributes)
139
+ process_response result
140
+ end
141
+ end
142
+ end
143
+
144
+ def identity
145
+ {'uuid' => self.uuid}
146
+ end
147
+
148
+ ##
149
+ # allows dynamic attributes!
150
+
151
+ def register_attr_accessors data
152
+ data.deep_stringify_keys!
153
+ # ignore attributes declared with attr_accessor method
154
+ self.class.data_attr_accessor *data.keys.keep_if{ |key|
155
+ public_methods.keep_if{ |n| n.to_s.start_with? key }.empty?
156
+ }
157
+ end
158
+
159
+ private
160
+
161
+ def process_response result
162
+ self.from_json(result)
163
+ self
164
+ end
165
+
166
+ end
167
+ end