json-orm 0.1.0 → 0.2.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.
- checksums.yaml +4 -4
- data/.github/workflows/gem-push.yml +45 -0
- data/.github/workflows/test.yml +25 -0
- data/.rubocop.yml +2 -0
- data/README.md +108 -7
- data/Rakefile +23 -0
- data/json-orm.gemspec +18 -13
- data/lib/json-orm/base_model.rb +61 -0
- data/lib/json-orm/chainable-query.rb +3 -1
- data/lib/json-orm/db.rb +16 -17
- data/lib/json-orm/orm.rb +11 -12
- data/lib/json-orm/validations.rb +56 -0
- data/lib/json-orm/version.rb +3 -1
- data/lib/json-orm.rb +4 -2
- metadata +28 -9
- data/test_jsorm.rb +0 -109
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f67bc2b71e782a57b186e7c91bcb25c58e059c51b60e555dc7c44ea933e63f92
|
4
|
+
data.tar.gz: 605844dcf63751a0534fc78ca3d6a886f96b8e1f8d398592474eb5bdc36f4a82
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8d57af525617a2126d65130b7d31cb2bbb90ec95fd16026d8ba52337e450d0450bce534dce76a465917bd9d319b74770553822962b09c342ae4a8ffc9b1d963a
|
7
|
+
data.tar.gz: e8954174120777083c723afdad1987a8a70a07fb1b1476008893002a611232c66f0911afea9d9208dcd01e13d580e5232be7695ae85731caf148a0ac4ca2c8b3
|
@@ -0,0 +1,45 @@
|
|
1
|
+
name: Ruby Gem
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ "main" ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ "main" ]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
build:
|
11
|
+
name: Build + Publish
|
12
|
+
runs-on: ubuntu-latest
|
13
|
+
permissions:
|
14
|
+
contents: read
|
15
|
+
packages: write
|
16
|
+
|
17
|
+
steps:
|
18
|
+
- uses: actions/checkout@v4
|
19
|
+
- name: Set up Ruby 3.2.0
|
20
|
+
uses: ruby/setup-ruby@v1
|
21
|
+
with:
|
22
|
+
ruby-version: 3.2.0
|
23
|
+
|
24
|
+
- name: Publish to GPR
|
25
|
+
run: |
|
26
|
+
mkdir -p $HOME/.gem
|
27
|
+
touch $HOME/.gem/credentials
|
28
|
+
chmod 0600 $HOME/.gem/credentials
|
29
|
+
printf -- "---\n:github: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
30
|
+
gem build *.gemspec
|
31
|
+
gem push --KEY github --host https://rubygems.pkg.github.com/${OWNER} *.gem
|
32
|
+
env:
|
33
|
+
GEM_HOST_API_KEY: "Bearer ${{secrets.GITHUB_TOKEN}}"
|
34
|
+
OWNER: ${{ github.repository_owner }}
|
35
|
+
|
36
|
+
- name: Publish to RubyGems
|
37
|
+
run: |
|
38
|
+
mkdir -p $HOME/.gem
|
39
|
+
touch $HOME/.gem/credentials
|
40
|
+
chmod 0600 $HOME/.gem/credentials
|
41
|
+
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
42
|
+
gem build *.gemspec
|
43
|
+
gem push *.gem
|
44
|
+
env:
|
45
|
+
GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
|
@@ -0,0 +1,25 @@
|
|
1
|
+
name: Test Minitest
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
paths-ignore:
|
6
|
+
- README.md
|
7
|
+
- LICENSE
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
test:
|
11
|
+
name: Run tests
|
12
|
+
runs-on: ubuntu-latest
|
13
|
+
permissions:
|
14
|
+
contents: read
|
15
|
+
packages: write
|
16
|
+
|
17
|
+
steps:
|
18
|
+
- uses: actions/checkout@v4
|
19
|
+
- name: Set up Ruby 3.2.0
|
20
|
+
uses: ruby/setup-ruby@v1
|
21
|
+
with:
|
22
|
+
ruby-version: 3.2.0
|
23
|
+
|
24
|
+
- name: Minitest
|
25
|
+
run: rake test
|
data/.rubocop.yml
ADDED
data/README.md
CHANGED
@@ -18,10 +18,11 @@ While designed for simplicity and ease of use, `json-orm` hasn't been optimized
|
|
18
18
|
## Future Plans
|
19
19
|
|
20
20
|
- [ ] Refactor logging
|
21
|
-
- [
|
22
|
-
- [
|
23
|
-
- [
|
24
|
-
- [
|
21
|
+
- [x] Add tests to DB class
|
22
|
+
- [] Add RuboCop to GitHub Actions
|
23
|
+
- [] Clean up better after test
|
24
|
+
- [x] Improve test to validate reliability
|
25
|
+
- [x] Add Validations class
|
25
26
|
|
26
27
|
## Installation 🔧
|
27
28
|
|
@@ -53,14 +54,114 @@ orm.begin_transaction
|
|
53
54
|
orm.commit_transaction
|
54
55
|
```
|
55
56
|
|
56
|
-
###
|
57
|
+
### JSONORM::Validations
|
58
|
+
|
59
|
+
The `JSONORM::Validations` module provides a flexible way to add validations to your Ruby objects. Here's how to use the newly added validators:
|
60
|
+
|
61
|
+
#### Length Validator
|
62
|
+
Checks if the length of a value is within a specified range.
|
63
|
+
|
64
|
+
**Usage:**
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
validate :attribute_name, :length, minimum: 5, maximum: 10
|
68
|
+
```
|
69
|
+
|
70
|
+
**Example:**
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
class User
|
74
|
+
include JSONORM::Validations
|
75
|
+
|
76
|
+
attr_accessor :name
|
77
|
+
|
78
|
+
validate :name, :length, minimum: 3, maximum: 50
|
79
|
+
end
|
80
|
+
|
81
|
+
user = User.new
|
82
|
+
user.name = "Jo"
|
83
|
+
user.validate! # Raises "Validation failed: name is too short (minimum is 3 characters)"
|
84
|
+
```
|
85
|
+
|
86
|
+
#### Inclusion Validator
|
87
|
+
Ensures a value is included in a specified set.
|
88
|
+
|
89
|
+
**Usage:**
|
57
90
|
|
58
91
|
```ruby
|
59
|
-
|
60
|
-
|
92
|
+
validate :attribute_name, :inclusion, in: [set_of_values]
|
93
|
+
```
|
94
|
+
|
95
|
+
**Example:**
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
class Product
|
99
|
+
include JSONORM::Validations
|
100
|
+
|
101
|
+
attr_accessor :category
|
102
|
+
|
103
|
+
validate :category, :inclusion, in: ['book', 'electronics', 'clothing']
|
61
104
|
end
|
105
|
+
|
106
|
+
product = Product.new
|
107
|
+
product.category = "food"
|
108
|
+
product.validate! # Raises "Validation failed: category is not included in the list"
|
62
109
|
```
|
63
110
|
|
111
|
+
#### Exclusion Validator
|
112
|
+
Ensures a value is not included in a specified set.
|
113
|
+
|
114
|
+
**Usage:**
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
validate :attribute_name, :exclusion, in: [set_of_values]
|
118
|
+
```
|
119
|
+
|
120
|
+
**Example:**
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
class Account
|
124
|
+
include JSONORM::Validations
|
125
|
+
|
126
|
+
attr_accessor :username
|
127
|
+
|
128
|
+
validate :username, :exclusion, in: ['admin', 'root']
|
129
|
+
end
|
130
|
+
|
131
|
+
account = Account.new
|
132
|
+
account.username = "admin"
|
133
|
+
account.validate! # Raises "Validation failed: username is reserved"
|
134
|
+
```
|
135
|
+
|
136
|
+
#### Custom Validator
|
137
|
+
Allows for custom validation logic through a lambda or proc.
|
138
|
+
|
139
|
+
**Usage:**
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
validate :attribute_name, :custom, with: lambda { |value| some_custom_condition }
|
143
|
+
```
|
144
|
+
|
145
|
+
**Example:**
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
class Order
|
149
|
+
include JSONORM::Validations
|
150
|
+
|
151
|
+
attr_accessor :total_price
|
152
|
+
|
153
|
+
validate :total_price, :custom, with: ->(value) { value > 0 && value < 10000 }
|
154
|
+
end
|
155
|
+
|
156
|
+
order = Order.new
|
157
|
+
order.total_price = -5
|
158
|
+
order.validate! # Raises "Validation failed: total_price is not valid"
|
159
|
+
```
|
160
|
+
|
161
|
+
#### Integrating Validators
|
162
|
+
|
163
|
+
To integrate these validators into your `validate!` method, simply add the cases as shown in the initial response to handle each validation type. Ensure that your `validate!` method checks for each validator type and applies the corresponding validation logic.
|
164
|
+
|
64
165
|
### Query Chaining
|
65
166
|
|
66
167
|
```ruby
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rake/testtask'
|
5
|
+
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
7
|
+
t.libs << 'test'
|
8
|
+
t.test_files = FileList['test/**/test_*.rb']
|
9
|
+
t.verbose = true
|
10
|
+
t.warning = true
|
11
|
+
t.ruby_opts = ['-I"test"', '-r./test/helper']
|
12
|
+
end
|
13
|
+
|
14
|
+
# Set the default task to :test if you want `rake` to run tests by default
|
15
|
+
task default: :test
|
16
|
+
|
17
|
+
desc 'Tag the current version and push tags to remote'
|
18
|
+
task :tag do
|
19
|
+
version = File.read(File.join(File.dirname(__FILE__), 'lib', 'json-orm',
|
20
|
+
'version.rb')).match(/VERSION = ['"](.*)['"]/)[1]
|
21
|
+
`git tag -a v#{version} -m "Release version #{version}"`
|
22
|
+
`git push origin v#{version}`
|
23
|
+
end
|
data/json-orm.gemspec
CHANGED
@@ -1,20 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
Gem::Specification.new do |spec|
|
2
|
-
spec.name
|
3
|
-
|
4
|
-
spec.
|
5
|
-
|
4
|
+
spec.name = 'json-orm'
|
5
|
+
required_ruby_version = '>= 3.2.0'
|
6
|
+
spec.version = File.read(File.join(File.dirname(__FILE__), 'lib', 'json-orm',
|
7
|
+
'version.rb')).match(/VERSION = ['"](.*)['"]/)[1]
|
8
|
+
spec.authors = ['Damir Mukimov']
|
9
|
+
spec.email = ['mukimov.d@gmail.com']
|
6
10
|
|
7
|
-
spec.summary =
|
8
|
-
spec.description =
|
9
|
-
spec.homepage =
|
10
|
-
spec.license =
|
11
|
+
spec.summary = 'A lightweight, JSON-based ORM for Ruby'
|
12
|
+
spec.description = 'Provides basic ORM functionalities like CRUD operations, transaction support, and custom validations.'
|
13
|
+
spec.homepage = 'https://www.glowing-pixels.com/json-orm'
|
14
|
+
spec.license = 'MIT'
|
11
15
|
|
12
16
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
13
|
-
spec.bindir =
|
17
|
+
spec.bindir = 'exe'
|
14
18
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
15
|
-
spec.require_paths = [
|
19
|
+
spec.require_paths = ['lib']
|
16
20
|
|
17
|
-
spec.add_development_dependency
|
18
|
-
spec.add_development_dependency
|
19
|
-
spec.add_development_dependency
|
21
|
+
spec.add_development_dependency 'bundler', '~> 2.0'
|
22
|
+
spec.add_development_dependency 'minitest', '~> 5.0'
|
23
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
24
|
+
spec.add_development_dependency 'rubocop'
|
20
25
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
module JSONORM
|
6
|
+
class BaseModel
|
7
|
+
include Validations
|
8
|
+
class << self
|
9
|
+
attr_accessor :attributes_list, :orm_instance
|
10
|
+
|
11
|
+
def attributes(*names)
|
12
|
+
@attributes_list ||= []
|
13
|
+
names.each do |name|
|
14
|
+
attr_accessor name unless method_defined?(name)
|
15
|
+
@attributes_list << name unless @attributes_list.include?(name)
|
16
|
+
end
|
17
|
+
attr_accessor :id unless method_defined?(:id)
|
18
|
+
@attributes_list << :id unless @attributes_list.include?(:id)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.inherited(subclass)
|
23
|
+
subclass.attributes_list = []
|
24
|
+
subclass.orm_instance = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(attributes = {}, orm_instance:)
|
28
|
+
raise 'ORM instance is required' unless orm_instance
|
29
|
+
|
30
|
+
self.class.orm_instance = orm_instance
|
31
|
+
@orm_instance = orm_instance
|
32
|
+
attributes.each do |attr, value|
|
33
|
+
send("#{attr}=", value) if self.class.attributes_list.include?(attr.to_sym)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def save
|
38
|
+
validate!
|
39
|
+
data = self.class.attributes_list.each_with_object({}) do |attr, hash|
|
40
|
+
hash[attr] = send(attr)
|
41
|
+
end
|
42
|
+
|
43
|
+
result = if id.nil? || id.to_s.empty?
|
44
|
+
@orm_instance.create(data)
|
45
|
+
else
|
46
|
+
@orm_instance.update(id, data)
|
47
|
+
end
|
48
|
+
self.id = result[:id] if result.is_a?(Hash) && result.key?(:id)
|
49
|
+
true
|
50
|
+
rescue StandardError => e
|
51
|
+
logger.error("Failed to save record for #{self.class.name}, Error: #{e.message}")
|
52
|
+
raise "Failed to save record: #{e.message}"
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def logger
|
58
|
+
@logger ||= Logger.new($stdout)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/json-orm/db.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'json'
|
2
4
|
require 'fileutils'
|
3
5
|
require 'logger'
|
@@ -20,18 +22,17 @@ module JSONORM
|
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
25
|
+
def write(data)
|
26
|
+
with_lock do
|
27
|
+
create_backup
|
28
|
+
File.open(file_path, 'w') { |f| f.write(JSON.pretty_generate(data)) }
|
29
|
+
logger.info('Data written successfully')
|
30
|
+
rescue IOError => e
|
31
|
+
restore_backup
|
32
|
+
logger.error("Error writing to file: #{e.message}")
|
33
|
+
raise "Error writing to file: #{e.message}"
|
34
|
+
end
|
32
35
|
end
|
33
|
-
end
|
34
|
-
|
35
36
|
|
36
37
|
private
|
37
38
|
|
@@ -40,22 +41,21 @@ module JSONORM
|
|
40
41
|
end
|
41
42
|
|
42
43
|
def create_backup
|
43
|
-
logger.info(
|
44
|
+
logger.info('Creating backup')
|
44
45
|
FileUtils.cp(file_path, backup_path)
|
45
|
-
rescue => e
|
46
|
+
rescue StandardError => e
|
46
47
|
logger.error("Failed to create backup: #{e.message}")
|
47
48
|
raise "Failed to create backup: #{e.message}"
|
48
49
|
end
|
49
50
|
|
50
51
|
def restore_backup
|
51
|
-
logger.info(
|
52
|
+
logger.info('Restoring from backup')
|
52
53
|
FileUtils.cp(backup_path, file_path)
|
53
|
-
rescue => e
|
54
|
+
rescue StandardError => e
|
54
55
|
logger.error("Failed to restore backup: #{e.message}")
|
55
56
|
raise "Failed to restore backup: #{e.message}"
|
56
57
|
end
|
57
58
|
|
58
|
-
|
59
59
|
def with_lock
|
60
60
|
File.open("#{file_path}.lock", 'w') do |f|
|
61
61
|
f.flock(File::LOCK_EX)
|
@@ -66,4 +66,3 @@ module JSONORM
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
end
|
69
|
-
|
data/lib/json-orm/orm.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module JSONORM
|
2
4
|
class ORM
|
3
5
|
attr_reader :database, :transaction_data, :logger
|
@@ -41,7 +43,7 @@ module JSONORM
|
|
41
43
|
end
|
42
44
|
|
43
45
|
def create(attributes)
|
44
|
-
attributes[:id] = next_id unless attributes.key?(:id)
|
46
|
+
attributes[:id] = next_id unless attributes.key?(:id) && attributes[:id]
|
45
47
|
validate_attributes!(attributes)
|
46
48
|
transaction_data.push(attributes)
|
47
49
|
attributes
|
@@ -69,10 +71,10 @@ module JSONORM
|
|
69
71
|
end
|
70
72
|
|
71
73
|
def commit_transaction
|
72
|
-
logger.info(
|
74
|
+
logger.info('Starting transaction commit')
|
73
75
|
database.write(transaction_data)
|
74
|
-
logger.info(
|
75
|
-
rescue => e
|
76
|
+
logger.info('Transaction committed successfully')
|
77
|
+
rescue StandardError => e
|
76
78
|
logger.error("Failed to commit transaction: #{e.message}")
|
77
79
|
raise "Failed to commit transaction: #{e.message}"
|
78
80
|
ensure
|
@@ -95,20 +97,17 @@ module JSONORM
|
|
95
97
|
end
|
96
98
|
|
97
99
|
def validate_attributes!(attributes, check_id = true)
|
98
|
-
raise
|
100
|
+
raise 'Record must have an id' if check_id && !attributes[:id]
|
99
101
|
|
100
102
|
attributes.each do |key, value|
|
101
103
|
validate_attribute(key, value)
|
102
104
|
end
|
103
105
|
end
|
104
106
|
|
105
|
-
# Update the validation method
|
106
107
|
def validate_attribute(key, value)
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
# Default validations (if any)
|
111
|
-
end
|
108
|
+
return unless self.class.custom_validators.key?(key)
|
109
|
+
|
110
|
+
self.class.custom_validators[key].call(value)
|
112
111
|
end
|
113
112
|
end
|
114
|
-
end
|
113
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSONORM
|
4
|
+
module Validations
|
5
|
+
def self.included(base)
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def validate(attribute, validation_type, options = {})
|
11
|
+
@validators ||= {}
|
12
|
+
@validators[attribute] ||= []
|
13
|
+
@validators[attribute] << { type: validation_type, options: options }
|
14
|
+
end
|
15
|
+
|
16
|
+
def validators
|
17
|
+
@validators || {}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def validate!
|
22
|
+
self.class.validators.each do |attribute, validators|
|
23
|
+
validators.each do |validator|
|
24
|
+
value = send(attribute)
|
25
|
+
case validator[:type]
|
26
|
+
when :presence
|
27
|
+
raise "Validation failed: #{attribute} can't be blank" if value.nil? || value.to_s.empty?
|
28
|
+
when :format
|
29
|
+
regex = validator[:options][:with]
|
30
|
+
raise "Validation failed: #{attribute} is invalid" unless value.match?(regex)
|
31
|
+
when :numericality
|
32
|
+
raise "Validation failed: #{attribute} is not a number" unless value.is_a?(Numeric)
|
33
|
+
when :length
|
34
|
+
min_length = validator[:options][:minimum] || 0
|
35
|
+
max_length = validator[:options][:maximum] || Float::INFINITY
|
36
|
+
actual_length = value.to_s.length
|
37
|
+
if actual_length < min_length
|
38
|
+
raise "Validation failed: #{attribute} is too short (minimum is #{min_length} characters)"
|
39
|
+
elsif actual_length > max_length
|
40
|
+
raise "Validation failed: #{attribute} is too long (maximum is #{max_length} characters)"
|
41
|
+
end
|
42
|
+
when :inclusion
|
43
|
+
in_set = validator[:options][:in]
|
44
|
+
raise "Validation failed: #{attribute} is not included in the list" unless in_set.include?(value)
|
45
|
+
when :exclusion
|
46
|
+
in_set = validator[:options][:in]
|
47
|
+
raise "Validation failed: #{attribute} is reserved" if in_set.include?(value)
|
48
|
+
when :custom
|
49
|
+
custom_validation = validator[:options][:with]
|
50
|
+
raise "Validation failed: #{attribute} is not valid" unless custom_validation.call(value)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/json-orm/version.rb
CHANGED
data/lib/json-orm.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'logger'
|
2
4
|
require_relative 'json-orm/version'
|
3
5
|
require_relative 'json-orm/db'
|
4
6
|
require_relative 'json-orm/orm'
|
5
7
|
require_relative 'json-orm/chainable-query'
|
8
|
+
require_relative 'json-orm/validations'
|
6
9
|
|
7
10
|
module JSONORM
|
8
|
-
|
9
|
-
end
|
11
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: json-orm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Damir Mukimov
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-02-
|
11
|
+
date: 2024-02-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '5.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '5.0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: rake
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -39,19 +53,19 @@ dependencies:
|
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
version: '13.0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
56
|
+
name: rubocop
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
|
-
- - "
|
59
|
+
- - ">="
|
46
60
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
61
|
+
version: '0'
|
48
62
|
type: :development
|
49
63
|
prerelease: false
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
51
65
|
requirements:
|
52
|
-
- - "
|
66
|
+
- - ">="
|
53
67
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
68
|
+
version: '0'
|
55
69
|
description: Provides basic ORM functionalities like CRUD operations, transaction
|
56
70
|
support, and custom validations.
|
57
71
|
email:
|
@@ -60,16 +74,21 @@ executables: []
|
|
60
74
|
extensions: []
|
61
75
|
extra_rdoc_files: []
|
62
76
|
files:
|
77
|
+
- ".github/workflows/gem-push.yml"
|
78
|
+
- ".github/workflows/test.yml"
|
63
79
|
- ".gitignore"
|
80
|
+
- ".rubocop.yml"
|
64
81
|
- LICENSE
|
65
82
|
- README.md
|
83
|
+
- Rakefile
|
66
84
|
- json-orm.gemspec
|
67
85
|
- lib/json-orm.rb
|
86
|
+
- lib/json-orm/base_model.rb
|
68
87
|
- lib/json-orm/chainable-query.rb
|
69
88
|
- lib/json-orm/db.rb
|
70
89
|
- lib/json-orm/orm.rb
|
90
|
+
- lib/json-orm/validations.rb
|
71
91
|
- lib/json-orm/version.rb
|
72
|
-
- test_jsorm.rb
|
73
92
|
homepage: https://www.glowing-pixels.com/json-orm
|
74
93
|
licenses:
|
75
94
|
- MIT
|
@@ -89,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
89
108
|
- !ruby/object:Gem::Version
|
90
109
|
version: '0'
|
91
110
|
requirements: []
|
92
|
-
rubygems_version: 3.
|
111
|
+
rubygems_version: 3.5.6
|
93
112
|
signing_key:
|
94
113
|
specification_version: 4
|
95
114
|
summary: A lightweight, JSON-based ORM for Ruby
|
data/test_jsorm.rb
DELETED
@@ -1,109 +0,0 @@
|
|
1
|
-
require 'minitest/autorun'
|
2
|
-
require_relative 'lib/json-orm'
|
3
|
-
|
4
|
-
class JSONORMTest < Minitest::Test
|
5
|
-
def setup
|
6
|
-
@db = JSONORM::DB.new('test_data.json', 'orm.test.log')
|
7
|
-
@orm = JSONORM::ORM.new(@db, 'orm.test.log')
|
8
|
-
@orm.begin_transaction
|
9
|
-
end
|
10
|
-
|
11
|
-
def after_tests
|
12
|
-
File.delete('test_data.json.backup') if File.exist?('test_data.backup')
|
13
|
-
end
|
14
|
-
|
15
|
-
def teardown
|
16
|
-
@orm.rollback_transaction
|
17
|
-
File.delete('test_data.json') if File.exist?('test_data.json')
|
18
|
-
File.delete('test_data.json.lock') if File.exist?('test_data.json.lock')
|
19
|
-
File.delete('test_data.json.backup') if File.exist?('test_data.backup')
|
20
|
-
end
|
21
|
-
|
22
|
-
def test_create
|
23
|
-
record = @orm.create({"name": "John Doe", "email": "john@example.com"})
|
24
|
-
assert_equal "John Doe", record[:name]
|
25
|
-
assert_equal "john@example.com", record[:email]
|
26
|
-
end
|
27
|
-
|
28
|
-
def test_read
|
29
|
-
record = @orm.create({"name": "Jane Doe", "email": "jane@example.com"})
|
30
|
-
found = @orm.find(record[:id])
|
31
|
-
assert_equal "Jane Doe", found[:name]
|
32
|
-
assert_equal "jane@example.com", found[:email]
|
33
|
-
end
|
34
|
-
|
35
|
-
def test_update
|
36
|
-
record = @orm.create({"name": "Jim Doe", "email": "jim@example.com"})
|
37
|
-
@orm.update(record[:id], {name: "James Doe"})
|
38
|
-
updated = @orm.find(record[:id])
|
39
|
-
|
40
|
-
assert_equal "James Doe", updated[:name]
|
41
|
-
assert_equal "jim@example.com", updated[:email]
|
42
|
-
end
|
43
|
-
|
44
|
-
def test_delete
|
45
|
-
record = @orm.create({"name": "Jack Doe", "email": "jack@example.com"})
|
46
|
-
@orm.delete(record[:id])
|
47
|
-
|
48
|
-
assert_nil @orm.find(record[:id])
|
49
|
-
end
|
50
|
-
|
51
|
-
def test_transaction_commit
|
52
|
-
@orm.begin_transaction
|
53
|
-
record = @orm.create({"name": "Jill Doe", "email": "jill@example.com"})
|
54
|
-
@orm.commit_transaction
|
55
|
-
assert_equal "Jill Doe", @orm.find(record[:id])[:name]
|
56
|
-
end
|
57
|
-
|
58
|
-
def test_transaction_rollback
|
59
|
-
record = @orm.create({"name": "Joe Doe", "email": "joe@example.com"})
|
60
|
-
@orm.rollback_transaction
|
61
|
-
assert_nil @orm.find(record[:id])
|
62
|
-
end
|
63
|
-
|
64
|
-
def test_valid_email
|
65
|
-
JSONORM::ORM.register_validator(:email) do |value|
|
66
|
-
raise "Invalid email format" unless value.match?(/\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i)
|
67
|
-
end
|
68
|
-
|
69
|
-
assert_raises("Invalid email format") do
|
70
|
-
@orm.create({"name": "Invalid Email", "email": "invalid"})
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def test_valid_age
|
75
|
-
JSONORM::ORM.register_validator(:age) do |value|
|
76
|
-
raise "Invalid age" unless value.is_a?(Integer) && value >= 0
|
77
|
-
end
|
78
|
-
|
79
|
-
assert_raises(RuntimeError) do
|
80
|
-
@orm.create({"name": "Invalid Age", "age": -5})
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def test_query_chaining
|
85
|
-
@orm.create({"name": "Alice", "age": 30, "city": "Wonderland"})
|
86
|
-
@orm.create({"name": "Bob", "age": 30, "city": "Gotham"})
|
87
|
-
@orm.create({"name": "Charlie", "age": 40, "city": "Wonderland"})
|
88
|
-
|
89
|
-
results = @orm.where(:age, 30).where(:city, "Wonderland").execute
|
90
|
-
assert_equal 1, results.size
|
91
|
-
assert_equal "Alice", results.first[:name]
|
92
|
-
end
|
93
|
-
|
94
|
-
|
95
|
-
def test_error_handling_on_write
|
96
|
-
# Simulate an error during write operation, e.g., invalid data format
|
97
|
-
@orm.create({"name": "Test", "email": "test@example.com"})
|
98
|
-
@orm.database.stub :write, ->(_data) { raise IOError, "Write error" } do
|
99
|
-
assert_raises(RuntimeError) { @orm.commit_transaction }
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
def test_file_locking
|
104
|
-
# Test to ensure file locking is working (may require mocking)
|
105
|
-
# Mock file locking and simulate concurrent access
|
106
|
-
end
|
107
|
-
|
108
|
-
# Additional tests for other features or edge cases
|
109
|
-
end
|