jsondb 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f12ca944e1c7a4a054b787da398a96998aa78f37
4
+ data.tar.gz: 29b3f64e40cfd3cf4355b3fe3e9ce255105c7b86
5
+ SHA512:
6
+ metadata.gz: e01e62d7f226e0c81cd006294f54b5b628ba830d2fed14c1870eff0fd9484497817900e11ee4087bca5449131b9a613eeab385d5c75b73d83c3380774888cd15
7
+ data.tar.gz: 6a7324ba2fffb7c7cc5e9232dbe247b5e5e8bf30c4fba2daf81212161a7295ddb843e443fe89c0cafbe2b5223bb4a94bedd2696645523dcdb7c38b89b4c025d6
data/lib/jsondb.rb ADDED
@@ -0,0 +1,11 @@
1
+ #it depends on json_pure
2
+ require 'json/pure'
3
+
4
+ this_dir = File.dirname(__FILE__)
5
+ require File.join(this_dir, 'jsondb/file_ops')
6
+ require File.join(this_dir, 'jsondb/db')
7
+ require File.join(this_dir, 'jsondb/validation')
8
+ require File.join(this_dir, 'jsondb/table')
9
+ require File.join(this_dir, 'jsondb/field')
10
+ require File.join(this_dir, 'jsondb/record')
11
+ require File.join(this_dir, 'jsondb/resultset')
data/lib/jsondb/db.rb ADDED
@@ -0,0 +1,56 @@
1
+ #db.rb
2
+ class Db
3
+
4
+ attr_reader :root, :tables, :writeable
5
+
6
+ def initialize(root, writeable = true)
7
+ @root = root
8
+ @writeable = writeable
9
+ @file = FileOps.new(@root, '_db.json', 'db', @writeable)
10
+ load_tables
11
+ end
12
+
13
+ def table(name)
14
+ @tables[name] ||= Table.new(name, @root, Time.now.to_i, @writeable)
15
+ end
16
+
17
+ def table_add(name)
18
+ if @tables.keys.include?(name)
19
+ raise "Table '#{name}' already defined."
20
+ else
21
+ @tables[name] = Table.new(name, @root, Time.now.to_i, @writeable)
22
+ end
23
+ end
24
+
25
+ def table_drop(name)
26
+ @tables[name].drop
27
+ @tables.delete(name)
28
+ end
29
+
30
+ def table_names
31
+ @tables.keys
32
+ end
33
+
34
+ def persist
35
+ @file.contents['tables'] = {}
36
+ @tables.each do |name, table|
37
+ if table.persisted == false
38
+ table.updated_at = Time.now.to_i
39
+ table.persist
40
+ end
41
+ @file.contents['tables'][name] = { "name" => name, "updated_at" => table.updated_at }
42
+ end
43
+ return @file.save
44
+ end
45
+
46
+ private
47
+
48
+ def load_tables
49
+ @tables_in_file = @file.contents['tables'] || Hash.new({})
50
+ @tables = Hash.new
51
+ @tables_in_file.each do |name, values|
52
+ @tables[name] = Table.new(name, @root, values['updated_at'], @writeable)
53
+ end
54
+ end
55
+
56
+ end
@@ -0,0 +1,47 @@
1
+ class Field
2
+
3
+ include Validation
4
+
5
+ attr_reader :name, :type, :nullable, :default
6
+
7
+ def initialize(name)
8
+ allowed_name?(name)
9
+
10
+ @name = name
11
+ @nullable = true
12
+ @default = nil
13
+ @type = "String"
14
+ end
15
+
16
+ def type=(_class)
17
+ @type = allowed?(_class)
18
+ end
19
+
20
+ def type
21
+ @type
22
+ end
23
+
24
+ def nullable=(value)
25
+ @nullable = validate_type("Bool", value)
26
+ end
27
+
28
+ def nullable
29
+ @nullable
30
+ end
31
+
32
+ def default=(value)
33
+ @default = validate_type(@type, value)
34
+ end
35
+
36
+ def default
37
+ @default
38
+ end
39
+
40
+ def to_hash
41
+ data = Hash.new
42
+ data['type'] = @type
43
+ data['nullable'] = @nullable
44
+ data['default'] = @default
45
+ data
46
+ end
47
+ end
@@ -0,0 +1,71 @@
1
+ class FileOps
2
+
3
+ attr_reader :writeable, :filename, :folder, :raw, :new_file
4
+
5
+ def initialize(folder, filename, filetype, writeable = true)
6
+ @folder = folder
7
+ @writeable = writeable
8
+ @filename = File.join(@folder, filename)
9
+ @filetype = filetype
10
+ if exists?(@folder)
11
+ load
12
+ else
13
+ raise "Folder '#{@folder}' does not exists."
14
+ end
15
+ end
16
+
17
+ def contents=(contents)
18
+ @contents = contents
19
+ end
20
+
21
+ def contents
22
+ @contents
23
+ end
24
+
25
+ def save
26
+ return false if @writeable == false
27
+ @file = File.open(@filename, 'w')
28
+ @raw = JSON.pretty_generate(@contents)
29
+ @file.write(@raw)
30
+ @file.close
31
+ @new_file = false
32
+ return true
33
+ end
34
+
35
+ def destroy
36
+ File.delete(@filename) if exists?(@filename)
37
+ end
38
+
39
+ def close
40
+ @file.close if @file
41
+ end
42
+
43
+ private
44
+
45
+ def exists?(file)
46
+ File.exists?(File.expand_path(file))
47
+ end
48
+
49
+ def load
50
+ @new_file = !exists?(@filename)
51
+ if exists?(@filename)
52
+ @file = File.open(@filename, 'r')
53
+ @raw = @file.read
54
+ else
55
+ @raw = default_content
56
+ end
57
+ @contents = JSON.parse(@raw)
58
+ @file.close if @file
59
+ end
60
+
61
+ def default_content
62
+ case @filetype
63
+ when 'db'
64
+ '{ "tables": {} }'
65
+ when 'table_structure'
66
+ '{ "last_id" : 0, "fields": {} }'
67
+ when 'table_records'
68
+ '{ }'
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,90 @@
1
+ class Record
2
+
3
+ include Validation
4
+
5
+ def initialize(fields, data = nil)
6
+ @fields = fields
7
+ if data.nil?
8
+ @record = Hash.new
9
+ @new = true
10
+ self.id = 0
11
+ else
12
+ @record = data
13
+ @new = false
14
+ end
15
+ @persisted = false
16
+ set_defaults # we need to apply again the defaults
17
+ end
18
+
19
+ def method_missing(name, *args)
20
+ attribute = name.to_s
21
+
22
+ if @fields.to_hash.keys.include?(attribute.sub('=', ''))
23
+ if attribute =~ /=$/
24
+ if @record[attribute] != args[0]
25
+ @record[attribute.sub('=', '')] = args[0]
26
+ @persisted = true
27
+ end
28
+ else
29
+ @record[attribute]
30
+ end
31
+ else
32
+ raise "Column '#{attribute.sub('=', '')}' do not exists"
33
+ end
34
+ end
35
+
36
+ def save_with_id(id)
37
+ self.created_at = Time.now.to_i
38
+ self.updated_at = Time.now.to_i
39
+ self.id = id
40
+ @new = false
41
+ @persisted = false
42
+ end
43
+
44
+ def update
45
+ self.updated_at = Time.now.to_i
46
+ @new = false
47
+ @persisted = false
48
+ end
49
+
50
+ def to_hash
51
+ @record
52
+ end
53
+
54
+ def new?
55
+ @new
56
+ end
57
+
58
+ def persisted?
59
+ @persisted
60
+ end
61
+
62
+ def created_at
63
+ Time.at(@record['created_at'])
64
+ end
65
+
66
+ def persisted_at
67
+ Time.at(@record['updated_at'])
68
+ end
69
+
70
+ private
71
+
72
+ def set_defaults
73
+ @fields.each do |name, values|
74
+ if values.default and @record[name].nil?
75
+ @record[name] = values.default
76
+ end
77
+ end
78
+ end
79
+
80
+ # # TODO : Add Validation
81
+
82
+ # def save!
83
+ # raiseif(save, false, "Error saving the record.")
84
+ # end
85
+
86
+ # def save
87
+ # return @table_class.save
88
+ # end
89
+
90
+ end
@@ -0,0 +1,107 @@
1
+ class ResultSet
2
+
3
+ include Validation
4
+
5
+ def initialize(table_class, array_fields = nil)
6
+ @fields = array_fields || table_class.fields.to_hash.keys
7
+ # actually it deletes the record!
8
+ @result = Hash.new()
9
+ table_class.records.each do |k, v|
10
+ @result[k] = v.dup
11
+ end
12
+
13
+ @equal = Hash.new
14
+ @min = Hash.new
15
+ @max = Hash.new
16
+ @like = Hash.new
17
+ end
18
+
19
+ def equal(field, value)
20
+ @equal[field] = value
21
+ return self
22
+ end
23
+
24
+ def min(field, value)
25
+ @min[field] = value
26
+ return self
27
+ end
28
+
29
+ def max(field, value)
30
+ @max[field] = value
31
+ return self
32
+ end
33
+
34
+ def like(field, value)
35
+ @like[field] = value
36
+ return self
37
+ end
38
+
39
+ def result
40
+ result_equal if @equal.keys.count != 0
41
+ result_min if @min.keys.count != 0
42
+ result_max if @max.keys.count != 0
43
+ result_like if @like.keys.count != 0
44
+ return @result
45
+ end
46
+
47
+ private
48
+
49
+ def result_equal
50
+ @equal.each do |col_name, col_value|
51
+ this_result = Array.new
52
+ @result.each do |id, record|
53
+ r = record.send col_name.to_sym
54
+ if r == col_value
55
+ this_result << id
56
+ end
57
+ end
58
+ remove_if_key_not_in(this_result)
59
+ end
60
+ end
61
+
62
+ def result_min
63
+ @min.each do |col_name, col_value|
64
+ this_result = Array.new
65
+ @result.each do |id, record|
66
+ r = record.send col_name.to_sym
67
+ if r >= col_value
68
+ this_result << id
69
+ end
70
+ end
71
+ remove_if_key_not_in(this_result)
72
+ end
73
+ end
74
+
75
+ def result_max
76
+ @max.each do |col_name, col_value|
77
+ this_result = Array.new
78
+ @result.each do |id, record|
79
+ r = record.send col_name.to_sym
80
+ if r <= col_value
81
+ this_result << id
82
+ end
83
+ end
84
+ remove_if_key_not_in(this_result)
85
+ end
86
+ end
87
+
88
+ def result_like
89
+ @like.each do |col_name, col_value|
90
+ this_result = Array.new
91
+ @result.each do |id, record|
92
+ r = record.send col_name.to_sym
93
+ if r =~ Regexp.new(col_value)
94
+ this_result << id
95
+ end
96
+ end
97
+ remove_if_key_not_in(this_result)
98
+ end
99
+ end
100
+
101
+ def remove_if_key_not_in(arr)
102
+ @result.keys.each do |key|
103
+ @result.delete(key) if arr.include?(key) == false
104
+ end
105
+ end
106
+
107
+ end
@@ -0,0 +1,143 @@
1
+ class Table
2
+
3
+ attr_accessor :updated_at
4
+ attr_reader :fields, :records, :last_id, :persisted
5
+
6
+ include Validation
7
+
8
+ def initialize(name, folder, updated_at, writeable)
9
+ allowed_name?(name)
10
+
11
+ @name = name
12
+ @folder = folder
13
+ @writeable = writeable
14
+
15
+ @structure_file = FileOps.new(@folder, "#{@name}_structure.json", 'table_structure', @writeable)
16
+ @records_file = FileOps.new(@folder, "#{@name}_records.json", 'table_records', @writeable)
17
+
18
+ # last_id
19
+ @last_id = @structure_file.contents["last_id"]
20
+
21
+ # Fields
22
+ @fields = Hash.new
23
+
24
+ if @structure_file.contents["fields"].keys.count
25
+ @structure_file.contents["fields"].each do |name, field|
26
+ @fields[name] ||= Field.new(name)
27
+ end
28
+ end
29
+ # add id and timestamps fields if not exists...
30
+ add_main_fields
31
+
32
+ # Fills records hash
33
+ @records_contents = @records_file.contents || {}
34
+ @records = Hash.new
35
+ @records_contents.each do |id, record|
36
+ @records[id] = Record.new(@fields, record)
37
+ end
38
+
39
+ @updated_at = Time.now.to_i if @structure_file.new_file
40
+ @persisted = !@structure_file.new_file
41
+
42
+ end
43
+
44
+ def field(name)
45
+ return @fields[name] ||= Field.new(@name)
46
+ end
47
+
48
+ def records
49
+ return @records
50
+ end
51
+
52
+ def new_record
53
+ @persisted = false
54
+ @updated_at = Time.now.to_i
55
+ return Record.new(@fields)
56
+ end
57
+
58
+ def query(array_fields = nil)
59
+ return select(array_fields)
60
+ end
61
+
62
+ def select(array_fields = nil)
63
+ return ResultSet.new(self, array_fields)
64
+ end
65
+
66
+ def insert(record)
67
+ if record.id != 0
68
+ raise "Record already exists."
69
+ else
70
+ id = new_id
71
+ record.save_with_id(id)
72
+ @records[id] = record
73
+ @persisted = false
74
+ return id
75
+ end
76
+ end
77
+
78
+ def update(record)
79
+ @persisted = false
80
+ @records[record.id] = record.update
81
+ end
82
+
83
+ def delete(record)
84
+ @persisted = false
85
+ @records.delete(record.id)
86
+ end
87
+
88
+ def drop
89
+ @structure_file.destroy
90
+ @records_file.destroy
91
+ end
92
+
93
+ def persist
94
+ @structure_file.contents['last_id'] = @last_id
95
+ @structure_file.contents['fields'] = @fields.to_hash
96
+ @structure_file.save
97
+
98
+ @records_file.contents = {}
99
+ @records.each do |id, record|
100
+ @records_file.contents[id] = record.to_hash
101
+ end
102
+ @records_file.save
103
+ @updated_at = Time.now.to_i
104
+ @persisted = true
105
+ end
106
+
107
+ def to_hash
108
+ return { "name" => @name, "updated_at" => @updated_at }
109
+ end
110
+
111
+ def updated_at_time
112
+ Time.at(@updated_at)
113
+ end
114
+
115
+ private
116
+
117
+ def new_id
118
+ @last_id = @last_id + 1
119
+ return @last_id
120
+ end
121
+
122
+ def add_main_fields
123
+ if @fields["id"].nil?
124
+ id_field = self.field('id')
125
+ id_field.type = "Fixnum"
126
+ id_field.nullable = false
127
+ id_field.default = 0
128
+ end
129
+ if @fields["created_at"].nil?
130
+ created_field = self.field('created_at')
131
+ created_field.type = "Fixnum"
132
+ created_field.nullable = false
133
+ created_field.default = 0
134
+ end
135
+ if @fields["updated_at"].nil?
136
+ updated_field = self.field('updated_at')
137
+ updated_field.type = "Fixnum"
138
+ updated_field.nullable = false
139
+ updated_field.default = 0
140
+ end
141
+ end
142
+
143
+ end
@@ -0,0 +1,86 @@
1
+ module Validation
2
+
3
+ def allowed_types
4
+ ["String", "Fixnum", "Integer", "Float", "Time", "Bool"]
5
+ end
6
+
7
+ def allowed_name?(name)
8
+ if (name =~ /^[a-zA-Z0-9_]+$/).nil?
9
+ raise "Name not allowed. /^[a-zA-Z0-9_]+$/"
10
+ else
11
+ return true
12
+ end
13
+ end
14
+
15
+ def allowed?(type)
16
+ if allowed_types.include?(type.to_s)
17
+ return type.to_s
18
+ else
19
+ raise "Validation: Type '#{type.to_s}' not allowed"
20
+ end
21
+ end
22
+
23
+ def validate_type(_class, _value)
24
+ case _class
25
+ when "Bool"
26
+ bool?(_class, _value)
27
+ when "String"
28
+ string?(_class, _value)
29
+ when "Fixnum", "Integer", "Float"
30
+ numeric?(_class, _value)
31
+ when "Time"
32
+ time?(_class, _value)
33
+ else
34
+ raise "Validation: '#{_class}' type not allowed"
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def bool?(_class, _value)
41
+ case _value
42
+ when true, false
43
+ return _value
44
+ else
45
+ raise "Validation: Bool: Not a Bool type"
46
+ end
47
+ end
48
+
49
+ def string?(_class, _value)
50
+ if _class == _value.class.to_s
51
+ return _value
52
+ else
53
+ raise "Validation: #{_class}: Value '#{_value}' not allowed for '#{_class}' type"
54
+ end
55
+ end
56
+
57
+ def numeric?(_class, _value)
58
+ case _class
59
+ when "Fixnum", "Integer"
60
+ if _value.class.to_s == "Fixnum"
61
+ return _value
62
+ else
63
+ raise "Validation: '#{_value}' is not Integer"
64
+ end
65
+ when "Float"
66
+ case eval(_value).class.to_s
67
+ when "Float"
68
+ return _value
69
+ when "Fixnum"
70
+ return _value.to_f
71
+ else
72
+ raise "Validation: '#{_value} is not a Float type"
73
+ end
74
+ else
75
+ raise "Validation: '#{_value} is not a Numeric type"
76
+ end
77
+ end
78
+
79
+ def time?(_class, _value)
80
+ if eval(_value).class.to_s != "Time"
81
+ raise "Validation: '#{_value} is not a Time type"
82
+ end
83
+ end
84
+
85
+ end
86
+
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jsondb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Antonio Fernandez
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: json_pure
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.8.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.8.1
27
+ description: Local Database using JSON files
28
+ email: antoniofernandezvara@gmail.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - lib/jsondb.rb
34
+ - lib/jsondb/db.rb
35
+ - lib/jsondb/field.rb
36
+ - lib/jsondb/file_ops.rb
37
+ - lib/jsondb/record.rb
38
+ - lib/jsondb/resultset.rb
39
+ - lib/jsondb/table.rb
40
+ - lib/jsondb/validation.rb
41
+ homepage: http://fernandezvara.github.io/jsondb/
42
+ licenses:
43
+ - MIT
44
+ metadata: {}
45
+ post_install_message:
46
+ rdoc_options: []
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubyforge_project:
61
+ rubygems_version: 2.2.2
62
+ signing_key:
63
+ specification_version: 4
64
+ summary: lib to manage tiny databases in plain JSON files
65
+ test_files: []