@reldens/storage 0.87.0 → 0.89.0
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.
- package/.claude/driver-methods-complete-analysis.md +1978 -0
- package/.claude/test-architecture.md +973 -0
- package/CLAUDE.md +141 -7
- package/README.md +14 -2
- package/bin/reldens-storage.js +1 -1
- package/lib/base-driver.js +8 -0
- package/lib/entities-generator.js +1 -3
- package/lib/entity-templates/mikro-orm-model.template +2 -1
- package/lib/generators/models-generation.js +126 -5
- package/lib/mikro-orm/mikro-orm-data-server.js +24 -10
- package/lib/mikro-orm/mikro-orm-driver.js +184 -116
- package/lib/objection-js/objection-js-driver.js +111 -19
- package/lib/prisma/prisma-client-loader.js +4 -0
- package/lib/prisma/prisma-data-server.js +3 -2
- package/lib/prisma/prisma-driver.js +12 -10
- package/lib/prisma/prisma-filter-processor.js +193 -146
- package/lib/prisma/prisma-metadata-loader.js +0 -4
- package/lib/prisma/prisma-relation-resolver.js +292 -267
- package/lib/prisma/prisma-type-caster.js +280 -260
- package/package.json +15 -6
- package/tests/.env.test.example +7 -0
- package/tests/fixtures/categories-fixtures.js +164 -0
- package/tests/fixtures/expected-entities-mikro-orm/entities/test-categories-entity.js +70 -0
- package/tests/fixtures/expected-entities-mikro-orm/entities/test-products-entity.js +95 -0
- package/tests/fixtures/expected-entities-mikro-orm/entities/test-reviews-entity.js +84 -0
- package/tests/fixtures/expected-entities-mikro-orm/entities-config.js +17 -0
- package/tests/fixtures/expected-entities-mikro-orm/entities-translations.js +13 -0
- package/tests/fixtures/expected-entities-mikro-orm/models/mikro-orm/registered-models-mikro-orm.js +23 -0
- package/tests/fixtures/expected-entities-mikro-orm/models/mikro-orm/test-categories-model.js +57 -0
- package/tests/fixtures/expected-entities-mikro-orm/models/mikro-orm/test-products-model.js +79 -0
- package/tests/fixtures/expected-entities-mikro-orm/models/mikro-orm/test-reviews-model.js +70 -0
- package/tests/fixtures/expected-entities-objection-js/entities/test-categories-entity.js +70 -0
- package/tests/fixtures/expected-entities-objection-js/entities/test-products-entity.js +95 -0
- package/tests/fixtures/expected-entities-objection-js/entities/test-reviews-entity.js +84 -0
- package/tests/fixtures/expected-entities-objection-js/entities-config.js +17 -0
- package/tests/fixtures/expected-entities-objection-js/entities-translations.js +13 -0
- package/tests/fixtures/expected-entities-objection-js/models/objection-js/registered-models-objection-js.js +23 -0
- package/tests/fixtures/expected-entities-objection-js/models/objection-js/test-categories-model.js +33 -0
- package/tests/fixtures/expected-entities-objection-js/models/objection-js/test-products-model.js +42 -0
- package/tests/fixtures/expected-entities-objection-js/models/objection-js/test-reviews-model.js +33 -0
- package/tests/fixtures/expected-entities-prisma/entities/test-categories-entity.js +70 -0
- package/tests/fixtures/expected-entities-prisma/entities/test-products-entity.js +95 -0
- package/tests/fixtures/expected-entities-prisma/entities/test-reviews-entity.js +84 -0
- package/tests/fixtures/expected-entities-prisma/entities-config.js +17 -0
- package/tests/fixtures/expected-entities-prisma/entities-translations.js +13 -0
- package/tests/fixtures/expected-entities-prisma/models/prisma/registered-models-prisma.js +23 -0
- package/tests/fixtures/expected-entities-prisma/models/prisma/test-categories-model.js +43 -0
- package/tests/fixtures/expected-entities-prisma/models/prisma/test-products-model.js +50 -0
- package/tests/fixtures/expected-entities-prisma/models/prisma/test-reviews-model.js +46 -0
- package/tests/fixtures/products-fixtures.js +119 -0
- package/tests/fixtures/reviews-fixtures.js +42 -0
- package/tests/fixtures/sql/test-schema.sql +59 -0
- package/tests/integration/test-drivers.js +257 -0
- package/tests/integration/test-nested-filters.js +408 -0
- package/tests/integration/test-relations.js +349 -0
- package/tests/run-tests.js +213 -0
- package/tests/unit/test-drivers.js +89 -0
- package/tests/unit/test-entities-generator.js +533 -0
- package/tests/unit/test-entity-manager.js +128 -0
- package/tests/unit/test-type-mapper.js +232 -0
- package/tests/utils/custom-reporter.js +73 -0
- package/tests/utils/driver-registry.js +144 -0
- package/tests/utils/prisma-subprocess-worker.js +150 -0
- package/tests/utils/test-helpers.js +726 -0
- package/tests/utils/test-runner.js +63 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - Registered Models
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { TestCategoriesModel } = require('./test-categories-model');
|
|
8
|
+
const { TestProductsModel } = require('./test-products-model');
|
|
9
|
+
const { TestReviewsModel } = require('./test-reviews-model');
|
|
10
|
+
const { entitiesConfig } = require('../../entities-config');
|
|
11
|
+
const { entitiesTranslations } = require('../../entities-translations');
|
|
12
|
+
|
|
13
|
+
let rawRegisteredEntities = {
|
|
14
|
+
testCategories: TestCategoriesModel,
|
|
15
|
+
testProducts: TestProductsModel,
|
|
16
|
+
testReviews: TestReviewsModel
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
module.exports.rawRegisteredEntities = rawRegisteredEntities;
|
|
20
|
+
|
|
21
|
+
module.exports.entitiesConfig = entitiesConfig;
|
|
22
|
+
|
|
23
|
+
module.exports.entitiesTranslations = entitiesTranslations;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - TestCategoriesModel
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
class TestCategoriesModel
|
|
8
|
+
{
|
|
9
|
+
|
|
10
|
+
constructor(id, name, slug, description, is_active, display_order, created_at, updated_at)
|
|
11
|
+
{
|
|
12
|
+
this.id = id;
|
|
13
|
+
this.name = name;
|
|
14
|
+
this.slug = slug;
|
|
15
|
+
this.description = description;
|
|
16
|
+
this.is_active = is_active;
|
|
17
|
+
this.display_order = display_order;
|
|
18
|
+
this.created_at = created_at;
|
|
19
|
+
this.updated_at = updated_at;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static get tableName()
|
|
23
|
+
{
|
|
24
|
+
return 'test_categories';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
static get relationTypes()
|
|
29
|
+
{
|
|
30
|
+
return {
|
|
31
|
+
test_products: 'many'
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static get relationMappings()
|
|
36
|
+
{
|
|
37
|
+
return {
|
|
38
|
+
'related_test_products': 'test_products'
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports.TestCategoriesModel = TestCategoriesModel;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - TestProductsModel
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
class TestProductsModel
|
|
8
|
+
{
|
|
9
|
+
|
|
10
|
+
constructor(id, category_id, name, sku, description, price, stock_quantity, is_featured, metadata, tags, status, created_at, updated_at)
|
|
11
|
+
{
|
|
12
|
+
this.id = id;
|
|
13
|
+
this.category_id = category_id;
|
|
14
|
+
this.name = name;
|
|
15
|
+
this.sku = sku;
|
|
16
|
+
this.description = description;
|
|
17
|
+
this.price = price;
|
|
18
|
+
this.stock_quantity = stock_quantity;
|
|
19
|
+
this.is_featured = is_featured;
|
|
20
|
+
this.metadata = metadata;
|
|
21
|
+
this.tags = tags;
|
|
22
|
+
this.status = status;
|
|
23
|
+
this.created_at = created_at;
|
|
24
|
+
this.updated_at = updated_at;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
static get tableName()
|
|
28
|
+
{
|
|
29
|
+
return 'test_products';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
static get relationTypes()
|
|
34
|
+
{
|
|
35
|
+
return {
|
|
36
|
+
test_categories: 'one',
|
|
37
|
+
test_reviews: 'many'
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static get relationMappings()
|
|
42
|
+
{
|
|
43
|
+
return {
|
|
44
|
+
'related_test_categories': 'test_categories',
|
|
45
|
+
'related_test_reviews': 'test_reviews'
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports.TestProductsModel = TestProductsModel;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - TestReviewsModel
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
class TestReviewsModel
|
|
8
|
+
{
|
|
9
|
+
|
|
10
|
+
constructor(id, product_id, reviewer_name, reviewer_email, rating, title, comment, is_verified, helpful_count, created_at, updated_at)
|
|
11
|
+
{
|
|
12
|
+
this.id = id;
|
|
13
|
+
this.product_id = product_id;
|
|
14
|
+
this.reviewer_name = reviewer_name;
|
|
15
|
+
this.reviewer_email = reviewer_email;
|
|
16
|
+
this.rating = rating;
|
|
17
|
+
this.title = title;
|
|
18
|
+
this.comment = comment;
|
|
19
|
+
this.is_verified = is_verified;
|
|
20
|
+
this.helpful_count = helpful_count;
|
|
21
|
+
this.created_at = created_at;
|
|
22
|
+
this.updated_at = updated_at;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static get tableName()
|
|
26
|
+
{
|
|
27
|
+
return 'test_reviews';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
static get relationTypes()
|
|
32
|
+
{
|
|
33
|
+
return {
|
|
34
|
+
test_products: 'one'
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static get relationMappings()
|
|
39
|
+
{
|
|
40
|
+
return {
|
|
41
|
+
'related_test_products': 'test_products'
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
module.exports.TestReviewsModel = TestReviewsModel;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - Test Products Fixtures
|
|
4
|
+
* Universal fixtures for all drivers (no driver-specific nesting)
|
|
5
|
+
*
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
module.exports.ProductsFixtures = {
|
|
9
|
+
product_create_json: {
|
|
10
|
+
name: 'Laptop Pro 15',
|
|
11
|
+
description: 'High-performance laptop',
|
|
12
|
+
sku: 'LAPTOP-PRO-15',
|
|
13
|
+
price: 1299.99,
|
|
14
|
+
stock_quantity: 50,
|
|
15
|
+
is_featured: 1,
|
|
16
|
+
metadata: JSON.stringify({warranty: '2 years', color: 'silver'}),
|
|
17
|
+
tags: 'electronics,computers,featured',
|
|
18
|
+
status: 'published'
|
|
19
|
+
},
|
|
20
|
+
product_create_enum: {
|
|
21
|
+
name: 'T-Shirt Classic',
|
|
22
|
+
description: 'Cotton t-shirt',
|
|
23
|
+
sku: 'TSHIRT-CLASSIC',
|
|
24
|
+
price: 24.99,
|
|
25
|
+
stock_quantity: 200,
|
|
26
|
+
is_featured: 0,
|
|
27
|
+
metadata: JSON.stringify({size: 'M', material: 'cotton'}),
|
|
28
|
+
tags: 'clothing,apparel',
|
|
29
|
+
status: 'published'
|
|
30
|
+
},
|
|
31
|
+
product_fk_test: {
|
|
32
|
+
category_id: 9999,
|
|
33
|
+
name: 'Invalid Category Product',
|
|
34
|
+
description: 'Product with invalid category FK',
|
|
35
|
+
sku: 'INVALID-FK-TEST',
|
|
36
|
+
price: 9.99,
|
|
37
|
+
stock_quantity: 1,
|
|
38
|
+
is_featured: 0,
|
|
39
|
+
metadata: JSON.stringify({}),
|
|
40
|
+
tags: 'test',
|
|
41
|
+
status: 'draft'
|
|
42
|
+
},
|
|
43
|
+
product_reviews_crud: {
|
|
44
|
+
id: 2400,
|
|
45
|
+
category_id: 1400,
|
|
46
|
+
name: 'Reviews CRUD Product',
|
|
47
|
+
description: 'Product for reviews CRUD tests',
|
|
48
|
+
sku: 'REVIEWS-CRUD-PROD',
|
|
49
|
+
price: 99.99,
|
|
50
|
+
stock_quantity: 10,
|
|
51
|
+
is_featured: 1,
|
|
52
|
+
metadata: JSON.stringify({test: 'reviews'}),
|
|
53
|
+
tags: 'test,reviews',
|
|
54
|
+
status: 'published'
|
|
55
|
+
},
|
|
56
|
+
product_filters_1: {
|
|
57
|
+
id: 2500,
|
|
58
|
+
category_id: 1500,
|
|
59
|
+
name: 'Filters Product 1',
|
|
60
|
+
description: 'First product for filter tests',
|
|
61
|
+
sku: 'FILTERS-PROD-1',
|
|
62
|
+
price: 49.99,
|
|
63
|
+
stock_quantity: 25,
|
|
64
|
+
is_featured: 1,
|
|
65
|
+
metadata: JSON.stringify({test: 'filters'}),
|
|
66
|
+
tags: 'test,filters',
|
|
67
|
+
status: 'published'
|
|
68
|
+
},
|
|
69
|
+
product_filters_2: {
|
|
70
|
+
id: 2501,
|
|
71
|
+
category_id: 1500,
|
|
72
|
+
name: 'Filters Product 2',
|
|
73
|
+
description: 'Second product for filter tests',
|
|
74
|
+
sku: 'FILTERS-PROD-2',
|
|
75
|
+
price: 79.99,
|
|
76
|
+
stock_quantity: 15,
|
|
77
|
+
is_featured: 0,
|
|
78
|
+
metadata: JSON.stringify({test: 'filters'}),
|
|
79
|
+
tags: 'test,filters',
|
|
80
|
+
status: 'draft'
|
|
81
|
+
},
|
|
82
|
+
product_relations_1: {
|
|
83
|
+
id: 2600,
|
|
84
|
+
category_id: 1600,
|
|
85
|
+
name: 'Relations Product 1',
|
|
86
|
+
description: 'First product for relations tests',
|
|
87
|
+
sku: 'RELATIONS-PROD-1',
|
|
88
|
+
price: 149.99,
|
|
89
|
+
stock_quantity: 30,
|
|
90
|
+
is_featured: 1,
|
|
91
|
+
metadata: JSON.stringify({test: 'relations'}),
|
|
92
|
+
tags: 'test,relations',
|
|
93
|
+
status: 'published'
|
|
94
|
+
},
|
|
95
|
+
product_relations_2: {
|
|
96
|
+
id: 2601,
|
|
97
|
+
category_id: 1601,
|
|
98
|
+
name: 'Relations Product 2',
|
|
99
|
+
description: 'Second product for relations tests',
|
|
100
|
+
sku: 'RELATIONS-PROD-2',
|
|
101
|
+
price: 199.99,
|
|
102
|
+
stock_quantity: 20,
|
|
103
|
+
is_featured: 1,
|
|
104
|
+
metadata: JSON.stringify({test: 'relations'}),
|
|
105
|
+
tags: 'test,relations',
|
|
106
|
+
status: 'published'
|
|
107
|
+
},
|
|
108
|
+
product_create_nested: {
|
|
109
|
+
name: 'Nested Create Product',
|
|
110
|
+
description: 'Product for createWithRelations test',
|
|
111
|
+
sku: 'NESTED-PROD-001',
|
|
112
|
+
price: 99.99,
|
|
113
|
+
stock_quantity: 10,
|
|
114
|
+
is_featured: 0,
|
|
115
|
+
metadata: JSON.stringify({test: 'nested'}),
|
|
116
|
+
tags: 'test,nested',
|
|
117
|
+
status: 'draft'
|
|
118
|
+
}
|
|
119
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - Test Reviews Fixtures
|
|
4
|
+
* Universal fixtures for all drivers (no driver-specific nesting)
|
|
5
|
+
*
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
module.exports.ReviewsFixtures = {
|
|
9
|
+
review_crud_1: {
|
|
10
|
+
id: 3400,
|
|
11
|
+
product_id: 2400,
|
|
12
|
+
reviewer_name: 'John Doe',
|
|
13
|
+
reviewer_email: 'john@example.com',
|
|
14
|
+
rating: 5,
|
|
15
|
+
title: 'Excellent product!',
|
|
16
|
+
comment: 'Very satisfied with this purchase',
|
|
17
|
+
is_verified: 1,
|
|
18
|
+
helpful_count: 10
|
|
19
|
+
},
|
|
20
|
+
review_relations_1: {
|
|
21
|
+
id: 3600,
|
|
22
|
+
product_id: 2600,
|
|
23
|
+
reviewer_name: 'Jane Smith',
|
|
24
|
+
reviewer_email: 'jane@example.com',
|
|
25
|
+
rating: 4,
|
|
26
|
+
title: 'Good value',
|
|
27
|
+
comment: 'Works as expected',
|
|
28
|
+
is_verified: 1,
|
|
29
|
+
helpful_count: 5
|
|
30
|
+
},
|
|
31
|
+
review_relations_2: {
|
|
32
|
+
id: 3601,
|
|
33
|
+
product_id: 2601,
|
|
34
|
+
reviewer_name: 'Bob Johnson',
|
|
35
|
+
reviewer_email: 'bob@example.com',
|
|
36
|
+
rating: 5,
|
|
37
|
+
title: 'Great quality',
|
|
38
|
+
comment: 'Highly recommended',
|
|
39
|
+
is_verified: 1,
|
|
40
|
+
helpful_count: 8
|
|
41
|
+
}
|
|
42
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
DROP TABLE IF EXISTS `test_reviews`;
|
|
2
|
+
DROP TABLE IF EXISTS `test_products`;
|
|
3
|
+
DROP TABLE IF EXISTS `test_categories`;
|
|
4
|
+
|
|
5
|
+
CREATE TABLE `test_categories` (
|
|
6
|
+
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
7
|
+
`name` VARCHAR(100) NOT NULL,
|
|
8
|
+
`slug` VARCHAR(100) NOT NULL,
|
|
9
|
+
`description` TEXT NULL,
|
|
10
|
+
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
|
|
11
|
+
`display_order` INT NOT NULL DEFAULT 0,
|
|
12
|
+
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
13
|
+
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
14
|
+
PRIMARY KEY (`id`),
|
|
15
|
+
UNIQUE KEY `slug` (`slug`),
|
|
16
|
+
KEY `is_active` (`is_active`),
|
|
17
|
+
KEY `display_order` (`display_order`)
|
|
18
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
19
|
+
|
|
20
|
+
CREATE TABLE `test_products` (
|
|
21
|
+
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
22
|
+
`category_id` INT UNSIGNED NOT NULL,
|
|
23
|
+
`name` VARCHAR(200) NOT NULL,
|
|
24
|
+
`sku` VARCHAR(50) NOT NULL,
|
|
25
|
+
`description` TEXT NULL,
|
|
26
|
+
`price` DECIMAL(10,2) NOT NULL,
|
|
27
|
+
`stock_quantity` INT NOT NULL DEFAULT 0,
|
|
28
|
+
`is_featured` TINYINT(1) NOT NULL DEFAULT 0,
|
|
29
|
+
`metadata` JSON NULL,
|
|
30
|
+
`tags` VARCHAR(255) NULL,
|
|
31
|
+
`status` ENUM('draft','published','archived') NOT NULL DEFAULT 'draft',
|
|
32
|
+
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
33
|
+
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
34
|
+
PRIMARY KEY (`id`),
|
|
35
|
+
UNIQUE KEY `sku` (`sku`),
|
|
36
|
+
KEY `category_id` (`category_id`),
|
|
37
|
+
KEY `status` (`status`),
|
|
38
|
+
KEY `is_featured` (`is_featured`),
|
|
39
|
+
CONSTRAINT `fk_products_category` FOREIGN KEY (`category_id`) REFERENCES `test_categories` (`id`) ON DELETE CASCADE
|
|
40
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
41
|
+
|
|
42
|
+
CREATE TABLE `test_reviews` (
|
|
43
|
+
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
44
|
+
`product_id` INT UNSIGNED NOT NULL,
|
|
45
|
+
`reviewer_name` VARCHAR(100) NOT NULL,
|
|
46
|
+
`reviewer_email` VARCHAR(255) NOT NULL,
|
|
47
|
+
`rating` TINYINT UNSIGNED NOT NULL,
|
|
48
|
+
`title` VARCHAR(200) NULL,
|
|
49
|
+
`comment` TEXT NULL,
|
|
50
|
+
`is_verified` TINYINT(1) NOT NULL DEFAULT 0,
|
|
51
|
+
`helpful_count` INT NOT NULL DEFAULT 0,
|
|
52
|
+
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
53
|
+
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
54
|
+
PRIMARY KEY (`id`),
|
|
55
|
+
KEY `product_id` (`product_id`),
|
|
56
|
+
KEY `rating` (`rating`),
|
|
57
|
+
KEY `is_verified` (`is_verified`),
|
|
58
|
+
CONSTRAINT `fk_reviews_product` FOREIGN KEY (`product_id`) REFERENCES `test_products` (`id`) ON DELETE CASCADE
|
|
59
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Reldens - Drivers Integration Test
|
|
4
|
+
* Tests CRUD operations across all three storage drivers
|
|
5
|
+
*
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { TestRunner, assert } = require('../utils/test-runner');
|
|
9
|
+
const { TestHelpers } = require('../utils/test-helpers');
|
|
10
|
+
const { CategoriesFixtures } = require('../fixtures/categories-fixtures');
|
|
11
|
+
const { ProductsFixtures } = require('../fixtures/products-fixtures');
|
|
12
|
+
const { ReviewsFixtures } = require('../fixtures/reviews-fixtures');
|
|
13
|
+
|
|
14
|
+
class DriversTest
|
|
15
|
+
{
|
|
16
|
+
|
|
17
|
+
constructor(dataServer, repos, driverName)
|
|
18
|
+
{
|
|
19
|
+
this.dataServer = dataServer;
|
|
20
|
+
this.categoriesRepo = repos.testCategories;
|
|
21
|
+
this.productsRepo = repos.testProducts;
|
|
22
|
+
this.reviewsRepo = repos.testReviews;
|
|
23
|
+
this.driverName = driverName;
|
|
24
|
+
this.runner = new TestRunner();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async run()
|
|
28
|
+
{
|
|
29
|
+
this.runner.suite('Driver: '+this.driverName);
|
|
30
|
+
await this.testCreateOperations();
|
|
31
|
+
await this.testUpdateOperations();
|
|
32
|
+
await this.testQueryOperations();
|
|
33
|
+
await this.testDeleteOperations();
|
|
34
|
+
await this.testReviewsCrud();
|
|
35
|
+
return this.runner.getResults();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async testCreateOperations()
|
|
39
|
+
{
|
|
40
|
+
this.runner.group('CREATE Operations');
|
|
41
|
+
await TestHelpers.cleanDatabase(this.dataServer);
|
|
42
|
+
await this.categoriesRepo.create(CategoriesFixtures.category_create_single);
|
|
43
|
+
let categoryJson = await this.categoriesRepo.create(CategoriesFixtures.category_create_json);
|
|
44
|
+
await this.productsRepo.create({...ProductsFixtures.product_create_json, category_id: categoryJson.id});
|
|
45
|
+
let categoryEnum = await this.categoriesRepo.create(CategoriesFixtures.category_create_enum);
|
|
46
|
+
await this.productsRepo.create({...ProductsFixtures.product_create_enum, category_id: categoryEnum.id});
|
|
47
|
+
await this.categoriesRepo.create(CategoriesFixtures.category_unique_test);
|
|
48
|
+
await this.runner.test('should create single record', async () => {
|
|
49
|
+
let created = await this.categoriesRepo.loadOne({slug: 'electronics'});
|
|
50
|
+
assert.ok(created);
|
|
51
|
+
assert.ok(created.id);
|
|
52
|
+
assert.strictEqual(created.name, 'Electronics');
|
|
53
|
+
});
|
|
54
|
+
await this.runner.test('should create record with JSON field', async () => {
|
|
55
|
+
let category = await this.categoriesRepo.loadOne({slug: 'books'});
|
|
56
|
+
let product = await this.productsRepo.loadOne({sku: 'LAPTOP-PRO-15'});
|
|
57
|
+
assert.ok(category);
|
|
58
|
+
assert.ok(product);
|
|
59
|
+
assert.ok(product.metadata);
|
|
60
|
+
});
|
|
61
|
+
await this.runner.test('should create record with ENUM field', async () => {
|
|
62
|
+
let category = await this.categoriesRepo.loadOne({slug: 'clothing'});
|
|
63
|
+
let product = await this.productsRepo.loadOne({sku: 'TSHIRT-CLASSIC'});
|
|
64
|
+
assert.ok(category);
|
|
65
|
+
assert.ok(product);
|
|
66
|
+
assert.strictEqual(product.status, 'published');
|
|
67
|
+
});
|
|
68
|
+
await this.runner.test('should enforce UNIQUE constraints', async () => {
|
|
69
|
+
let categoryData = CategoriesFixtures.category_unique_test;
|
|
70
|
+
try {
|
|
71
|
+
await this.categoriesRepo.create(categoryData);
|
|
72
|
+
assert.fail('Should have thrown duplicate key error');
|
|
73
|
+
} catch(error){
|
|
74
|
+
assert.ok(error);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
await this.runner.test('should enforce FOREIGN KEY constraints', async () => {
|
|
78
|
+
let productData = ProductsFixtures.product_fk_test;
|
|
79
|
+
try {
|
|
80
|
+
await this.productsRepo.create(productData);
|
|
81
|
+
assert.fail('Should have thrown foreign key error');
|
|
82
|
+
} catch(error){
|
|
83
|
+
assert.ok(error);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async testUpdateOperations()
|
|
89
|
+
{
|
|
90
|
+
this.runner.group('UPDATE Operations');
|
|
91
|
+
await TestHelpers.cleanDatabase(this.dataServer);
|
|
92
|
+
await TestHelpers.insertFixturesViaRawSQL(this.dataServer, 'test_categories', [
|
|
93
|
+
CategoriesFixtures.category_update_by_id
|
|
94
|
+
]);
|
|
95
|
+
await this.runner.test('should update record by ID', async () => {
|
|
96
|
+
let updated = await this.categoriesRepo.updateById(1100, {name: 'Updated Name'});
|
|
97
|
+
assert.ok(updated);
|
|
98
|
+
assert.strictEqual(updated.name, 'Updated Name');
|
|
99
|
+
});
|
|
100
|
+
await this.runner.test('should update record by filters', async () => {
|
|
101
|
+
let updated = await this.categoriesRepo.updateBy('id', 1100, {name: 'Updated via filters'});
|
|
102
|
+
assert.ok(updated);
|
|
103
|
+
});
|
|
104
|
+
await this.runner.test('should update record by single field', async () => {
|
|
105
|
+
let updated = await this.categoriesRepo.updateBy('id', 1100, {name: 'Updated via field'});
|
|
106
|
+
assert.ok(updated);
|
|
107
|
+
});
|
|
108
|
+
await this.runner.test('should upsert when record does not exist', async () => {
|
|
109
|
+
let newData = CategoriesFixtures.category_upsert_new;
|
|
110
|
+
let result = await this.categoriesRepo.upsert(newData, {id: newData.id});
|
|
111
|
+
assert.ok(result);
|
|
112
|
+
});
|
|
113
|
+
await this.runner.test('should upsert when record exists', async () => {
|
|
114
|
+
let result = await this.categoriesRepo.upsert({id: 1100}, {name: 'Upserted Name'});
|
|
115
|
+
assert.ok(result);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async testQueryOperations()
|
|
120
|
+
{
|
|
121
|
+
this.runner.group('QUERY Operations');
|
|
122
|
+
await TestHelpers.cleanDatabase(this.dataServer);
|
|
123
|
+
await TestHelpers.insertFixturesViaRawSQL(this.dataServer, 'test_categories', [
|
|
124
|
+
CategoriesFixtures.category_query_1,
|
|
125
|
+
CategoriesFixtures.category_query_2,
|
|
126
|
+
CategoriesFixtures.category_query_3
|
|
127
|
+
]);
|
|
128
|
+
await this.runner.test('should load all records', async () => {
|
|
129
|
+
let all = await this.categoriesRepo.loadAll();
|
|
130
|
+
assert.strictEqual(all.length, 3);
|
|
131
|
+
});
|
|
132
|
+
await this.runner.test('should load records by filters', async () => {
|
|
133
|
+
let filtered = await this.categoriesRepo.load({name: 'Query Test 1'});
|
|
134
|
+
assert.strictEqual(filtered.length, 1);
|
|
135
|
+
assert.strictEqual(filtered[0].id, 1300);
|
|
136
|
+
});
|
|
137
|
+
await this.runner.test('should load records by single field', async () => {
|
|
138
|
+
let result = await this.categoriesRepo.loadBy('name', 'Query Test 2');
|
|
139
|
+
assert.strictEqual(result.length, 1);
|
|
140
|
+
assert.strictEqual(result[0].id, 1301);
|
|
141
|
+
});
|
|
142
|
+
await this.runner.test('should load record by ID', async () => {
|
|
143
|
+
let record = await this.categoriesRepo.loadById(1300);
|
|
144
|
+
assert.ok(record);
|
|
145
|
+
assert.strictEqual(record.id, 1300);
|
|
146
|
+
});
|
|
147
|
+
await this.runner.test('should load records by multiple IDs', async () => {
|
|
148
|
+
let records = await this.categoriesRepo.loadByIds([1300, 1301]);
|
|
149
|
+
assert.strictEqual(records.length, 2);
|
|
150
|
+
});
|
|
151
|
+
await this.runner.test('should load one record', async () => {
|
|
152
|
+
let record = await this.categoriesRepo.loadOne({name: 'Query Test 1'});
|
|
153
|
+
assert.ok(record);
|
|
154
|
+
assert.strictEqual(record.id, 1300);
|
|
155
|
+
});
|
|
156
|
+
await this.runner.test('should load one record by field', async () => {
|
|
157
|
+
let record = await this.categoriesRepo.loadOneBy('name', 'Query Test 3');
|
|
158
|
+
assert.ok(record);
|
|
159
|
+
assert.strictEqual(record.id, 1302);
|
|
160
|
+
});
|
|
161
|
+
await this.runner.test('should count records with filters', async () => {
|
|
162
|
+
let count = await this.categoriesRepo.count({name: 'Query Test 1'});
|
|
163
|
+
assert.strictEqual(count, 1);
|
|
164
|
+
});
|
|
165
|
+
await this.runner.test('should apply limit', async () => {
|
|
166
|
+
this.categoriesRepo.limit = 2;
|
|
167
|
+
let records = await this.categoriesRepo.load();
|
|
168
|
+
assert.strictEqual(records.length, 2);
|
|
169
|
+
this.categoriesRepo.limit = 0;
|
|
170
|
+
});
|
|
171
|
+
await this.runner.test('should apply offset', async () => {
|
|
172
|
+
this.categoriesRepo.offset = 1;
|
|
173
|
+
this.categoriesRepo.limit = 2;
|
|
174
|
+
let records = await this.categoriesRepo.load();
|
|
175
|
+
assert.strictEqual(records.length, 2);
|
|
176
|
+
this.categoriesRepo.offset = 0;
|
|
177
|
+
this.categoriesRepo.limit = 0;
|
|
178
|
+
});
|
|
179
|
+
await this.runner.test('should apply sortBy and sortDirection', async () => {
|
|
180
|
+
this.categoriesRepo.sortBy = 'name';
|
|
181
|
+
this.categoriesRepo.sortDirection = 'DESC';
|
|
182
|
+
let records = await this.categoriesRepo.load();
|
|
183
|
+
assert.strictEqual(records.length, 3);
|
|
184
|
+
assert.strictEqual(records[0].name, 'Query Test 3');
|
|
185
|
+
assert.strictEqual(records[1].name, 'Query Test 2');
|
|
186
|
+
assert.strictEqual(records[2].name, 'Query Test 1');
|
|
187
|
+
this.categoriesRepo.sortBy = false;
|
|
188
|
+
this.categoriesRepo.sortDirection = 'ASC';
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async testDeleteOperations()
|
|
193
|
+
{
|
|
194
|
+
this.runner.group('DELETE Operations');
|
|
195
|
+
await TestHelpers.cleanDatabase(this.dataServer);
|
|
196
|
+
await TestHelpers.insertFixturesViaRawSQL(this.dataServer, 'test_categories', [
|
|
197
|
+
CategoriesFixtures.category_delete_by_id,
|
|
198
|
+
CategoriesFixtures.category_delete_by_filters
|
|
199
|
+
]);
|
|
200
|
+
await this.runner.test('should delete record by ID', async () => {
|
|
201
|
+
let result = await this.categoriesRepo.deleteById(1200);
|
|
202
|
+
assert.ok(result);
|
|
203
|
+
let remaining = await this.categoriesRepo.loadAll();
|
|
204
|
+
assert.strictEqual(remaining.length, 1);
|
|
205
|
+
});
|
|
206
|
+
await this.runner.test('should delete records by filters', async () => {
|
|
207
|
+
let result = await this.categoriesRepo.delete({name: 'Art'});
|
|
208
|
+
assert.ok(result);
|
|
209
|
+
let remaining = await this.categoriesRepo.loadAll();
|
|
210
|
+
assert.strictEqual(remaining.length, 0);
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async testReviewsCrud()
|
|
215
|
+
{
|
|
216
|
+
this.runner.group('REVIEWS CRUD Operations');
|
|
217
|
+
await TestHelpers.cleanDatabase(this.dataServer);
|
|
218
|
+
await TestHelpers.insertFixturesViaRawSQL(this.dataServer, 'test_categories', [
|
|
219
|
+
CategoriesFixtures.category_reviews_crud
|
|
220
|
+
]);
|
|
221
|
+
await TestHelpers.insertFixturesViaRawSQL(this.dataServer, 'test_products', [
|
|
222
|
+
ProductsFixtures.product_reviews_crud
|
|
223
|
+
]);
|
|
224
|
+
await TestHelpers.insertFixturesViaRawSQL(this.dataServer, 'test_reviews', [
|
|
225
|
+
ReviewsFixtures.review_crud_1
|
|
226
|
+
]);
|
|
227
|
+
await this.runner.test('should create review record', async () => {
|
|
228
|
+
let created = await this.reviewsRepo.loadById(3400);
|
|
229
|
+
assert.ok(created);
|
|
230
|
+
assert.strictEqual(created.product_id, 2400);
|
|
231
|
+
});
|
|
232
|
+
await this.runner.test('should load review by ID', async () => {
|
|
233
|
+
let record = await this.reviewsRepo.loadById(3400);
|
|
234
|
+
assert.ok(record);
|
|
235
|
+
assert.strictEqual(record.id, 3400);
|
|
236
|
+
});
|
|
237
|
+
await this.runner.test('should update review by ID', async () => {
|
|
238
|
+
let updated = await this.reviewsRepo.updateById(3400, {rating: 5});
|
|
239
|
+
assert.ok(updated);
|
|
240
|
+
assert.strictEqual(updated.rating, 5);
|
|
241
|
+
});
|
|
242
|
+
await this.runner.test('should delete review by ID', async () => {
|
|
243
|
+
let result = await this.reviewsRepo.deleteById(3400);
|
|
244
|
+
assert.ok(result);
|
|
245
|
+
});
|
|
246
|
+
await this.runner.test('should load reviews by product_id', async () => {
|
|
247
|
+
await TestHelpers.insertFixturesViaRawSQL(this.dataServer, 'test_reviews', [
|
|
248
|
+
ReviewsFixtures.review_crud_1
|
|
249
|
+
]);
|
|
250
|
+
let reviews = await this.reviewsRepo.loadBy('product_id', 2400);
|
|
251
|
+
assert.strictEqual(reviews.length, 1);
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
module.exports = DriversTest;
|