@anephenix/objection-relations 0.0.13 → 0.0.14
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/README.md +1 -1
- package/package.json +63 -65
- package/src/global.d.ts +11 -11
- package/src/helpers.ts +12 -12
- package/src/index.ts +51 -51
- package/src/relations.ts +92 -92
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# objection-relations
|
|
2
2
|
|
|
3
|
-
[](https://badge.fury.io/js/%40anephenix%2Fobjection-relations) [](https://github.com/anephenix/objection-relations/actions/workflows/node.js.yml) [](https://badge.fury.io/js/%40anephenix%2Fobjection-relations) [](https://github.com/anephenix/objection-relations/actions/workflows/node.js.yml) [](https://socket.dev/npm/package/@anephenix/objection-relations)
|
|
4
4
|
|
|
5
5
|
A relations helper for Objection.js. This provides a convenient way to define
|
|
6
6
|
relations in the `relationMappings` function on an Objection.js model.
|
package/package.json
CHANGED
|
@@ -1,67 +1,65 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
]
|
|
2
|
+
"version": "0.0.14",
|
|
3
|
+
"license": "MIT",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"typings": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"src"
|
|
10
|
+
],
|
|
11
|
+
"engines": {
|
|
12
|
+
"node": ">=10"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"lodash.snakecase": "^4.1.1",
|
|
16
|
+
"objection": "^3.1.5",
|
|
17
|
+
"pluralize": "^8.0.0"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@biomejs/biome": "2.2.5",
|
|
21
|
+
"@types/lodash.snakecase": "^4.1.9",
|
|
22
|
+
"@types/node": "^24.6.2",
|
|
23
|
+
"@types/pluralize": "^0.0.33",
|
|
24
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
25
|
+
"globals": "^16.4.0",
|
|
26
|
+
"husky": "^9.1.7",
|
|
27
|
+
"size-limit": "^11.2.0",
|
|
28
|
+
"size-limit-preset-node-lib": "^0.4.0",
|
|
29
|
+
"typescript": "^5.9.3",
|
|
30
|
+
"vitest": "^3.2.4"
|
|
31
|
+
},
|
|
32
|
+
"author": "Paul Jensen <paul@anephenix.com>",
|
|
33
|
+
"scripts": {
|
|
34
|
+
"analyze": "size-limit --why",
|
|
35
|
+
"build": "tsc --project tsconfig.json",
|
|
36
|
+
"cover": "NODE_ENV=test vitest --coverage --run",
|
|
37
|
+
"lint": "npx @biomejs/biome check --write src test scripts",
|
|
38
|
+
"prepare-patch-release": "npm run update-changelog && git add CHANGELOG.md && git commit -m \"Updated changelog\" && npm version patch",
|
|
39
|
+
"publish-patch-release": "npm run prepare-patch-release && git push origin main && git push --tags",
|
|
40
|
+
"size": "size-limit",
|
|
41
|
+
"start": "tsdx watch --target node",
|
|
42
|
+
"test": "NODE_ENV=test vitest --run",
|
|
43
|
+
"update-changelog": "node --experimental-strip-types scripts/update-changelog.ts",
|
|
44
|
+
"prepare": "husky"
|
|
45
|
+
},
|
|
46
|
+
"husky": {
|
|
47
|
+
"hooks": {
|
|
48
|
+
"pre-commit": "npm run lint && npm test"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"name": "@anephenix/objection-relations",
|
|
52
|
+
"module": "dist/objection-relations.esm.js",
|
|
53
|
+
"prettier": {
|
|
54
|
+
"printWidth": 80,
|
|
55
|
+
"semi": true,
|
|
56
|
+
"singleQuote": true,
|
|
57
|
+
"trailingComma": "es5"
|
|
58
|
+
},
|
|
59
|
+
"size-limit": [
|
|
60
|
+
{
|
|
61
|
+
"path": "dist/*.js",
|
|
62
|
+
"limit": "10 KB"
|
|
63
|
+
}
|
|
64
|
+
]
|
|
67
65
|
}
|
package/src/global.d.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
export type OptionsProps = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
subjectTable?: string;
|
|
3
|
+
objectTable?: string;
|
|
4
|
+
subjectForeignKey?: string;
|
|
5
|
+
objectForeignKey?: string;
|
|
6
|
+
modelPath?: string;
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
-
type CommonRelationOrTableOrForeignKeyProps = {
|
|
10
|
-
|
|
9
|
+
export type CommonRelationOrTableOrForeignKeyProps = {
|
|
10
|
+
options?: OptionsProps;
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
type RelationTypeProps = {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
export type RelationTypeProps = {
|
|
14
|
+
modelClass: string;
|
|
15
|
+
from: string;
|
|
16
|
+
to: string;
|
|
17
17
|
};
|
package/src/helpers.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import { CommonRelationOrTableOrForeignKeyProps } from
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import snakeCase from "lodash.snakecase";
|
|
3
|
+
import pluralize from "pluralize";
|
|
4
|
+
import type { CommonRelationOrTableOrForeignKeyProps } from "./global";
|
|
5
5
|
|
|
6
6
|
// Types
|
|
7
7
|
|
|
8
8
|
type SubjectProps = CommonRelationOrTableOrForeignKeyProps & {
|
|
9
|
-
|
|
9
|
+
subject: string;
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
type ObjectProps = CommonRelationOrTableOrForeignKeyProps & {
|
|
13
|
-
|
|
13
|
+
object: string;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
type ViaProps = string | undefined;
|
|
@@ -20,7 +20,7 @@ type ViaProps = string | undefined;
|
|
|
20
20
|
plural version of the subject model.
|
|
21
21
|
*/
|
|
22
22
|
export function getSubjectTable({ subject, options }: SubjectProps) {
|
|
23
|
-
|
|
23
|
+
return options?.subjectTable || pluralize(snakeCase(subject));
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/*
|
|
@@ -28,7 +28,7 @@ export function getSubjectTable({ subject, options }: SubjectProps) {
|
|
|
28
28
|
plural version of the object model.
|
|
29
29
|
*/
|
|
30
30
|
export function getObjectTable({ object, options }: ObjectProps) {
|
|
31
|
-
|
|
31
|
+
return options?.objectTable || pluralize(snakeCase(object));
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
/*
|
|
@@ -36,7 +36,7 @@ export function getObjectTable({ object, options }: ObjectProps) {
|
|
|
36
36
|
or the snake case of the subject model.
|
|
37
37
|
*/
|
|
38
38
|
export function getSubjectForeignKey({ subject, options }: SubjectProps) {
|
|
39
|
-
|
|
39
|
+
return options?.subjectForeignKey || `${snakeCase(subject)}_id`;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
/*
|
|
@@ -44,16 +44,16 @@ export function getSubjectForeignKey({ subject, options }: SubjectProps) {
|
|
|
44
44
|
or the snake case of the object model.
|
|
45
45
|
*/
|
|
46
46
|
export function getObjectForeignKey({ object, options }: ObjectProps) {
|
|
47
|
-
|
|
47
|
+
return options?.objectForeignKey || `${snakeCase(object)}_id`;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
/*
|
|
51
51
|
Allows you to define the model path for a model
|
|
52
52
|
*/
|
|
53
53
|
export function getModelClass({ object, options }: ObjectProps) {
|
|
54
|
-
|
|
54
|
+
return options?.modelPath ? join(options.modelPath, object) : object;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
export function getViaTable(via: ViaProps) {
|
|
58
|
-
|
|
58
|
+
return via ? pluralize(snakeCase(via)) : null;
|
|
59
59
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,64 +1,64 @@
|
|
|
1
1
|
// Dependencies
|
|
2
|
-
import { OptionsProps } from
|
|
3
|
-
import { relation } from
|
|
2
|
+
import type { OptionsProps } from "./global";
|
|
3
|
+
import { relation } from "./relations";
|
|
4
4
|
|
|
5
5
|
// Types
|
|
6
6
|
|
|
7
7
|
type ObjectionRelationProps = {
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
subject: string;
|
|
9
|
+
modelPath: string;
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
export class ObjectionRelation {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
subject: string;
|
|
14
|
+
modelPath: string;
|
|
15
|
+
constructor({ subject, modelPath }: ObjectionRelationProps) {
|
|
16
|
+
this.subject = subject;
|
|
17
|
+
this.modelPath = modelPath;
|
|
18
|
+
}
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
belongsTo(object: string, options?: OptionsProps) {
|
|
21
|
+
if (!options) options = { modelPath: this.modelPath };
|
|
22
|
+
if (!options.modelPath) options.modelPath = this.modelPath;
|
|
23
|
+
return relation({
|
|
24
|
+
subject: this.subject,
|
|
25
|
+
relType: "belongsTo",
|
|
26
|
+
object,
|
|
27
|
+
options,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
31
|
+
hasOne(object: string, options?: OptionsProps) {
|
|
32
|
+
if (!options) options = { modelPath: this.modelPath };
|
|
33
|
+
if (!options.modelPath) options.modelPath = this.modelPath;
|
|
34
|
+
return relation({
|
|
35
|
+
subject: this.subject,
|
|
36
|
+
relType: "hasOne",
|
|
37
|
+
object,
|
|
38
|
+
options,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
42
|
+
hasMany(object: string, options?: OptionsProps) {
|
|
43
|
+
if (!options) options = { modelPath: this.modelPath };
|
|
44
|
+
if (!options.modelPath) options.modelPath = this.modelPath;
|
|
45
|
+
return relation({
|
|
46
|
+
subject: this.subject,
|
|
47
|
+
relType: "hasMany",
|
|
48
|
+
object,
|
|
49
|
+
options,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
53
|
+
hasManyThrough(object: string, via: string, options?: OptionsProps) {
|
|
54
|
+
if (!options) options = { modelPath: this.modelPath };
|
|
55
|
+
if (!options.modelPath) options.modelPath = this.modelPath;
|
|
56
|
+
return relation({
|
|
57
|
+
subject: this.subject,
|
|
58
|
+
relType: "hasManyThrough",
|
|
59
|
+
object,
|
|
60
|
+
via,
|
|
61
|
+
options,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
64
|
}
|
package/src/relations.ts
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
// Dependencies
|
|
2
|
-
import { Model } from
|
|
2
|
+
import { Model } from "objection";
|
|
3
|
+
import type {
|
|
4
|
+
CommonRelationOrTableOrForeignKeyProps,
|
|
5
|
+
RelationTypeProps,
|
|
6
|
+
} from "./global";
|
|
3
7
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
getObjectForeignKey,
|
|
12
|
-
getModelClass,
|
|
13
|
-
getViaTable,
|
|
14
|
-
} from './helpers';
|
|
8
|
+
getModelClass,
|
|
9
|
+
getObjectForeignKey,
|
|
10
|
+
getObjectTable,
|
|
11
|
+
getSubjectForeignKey,
|
|
12
|
+
getSubjectTable,
|
|
13
|
+
getViaTable,
|
|
14
|
+
} from "./helpers";
|
|
15
15
|
|
|
16
16
|
const {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
HasOneRelation,
|
|
18
|
+
BelongsToOneRelation,
|
|
19
|
+
HasManyRelation,
|
|
20
|
+
ManyToManyRelation,
|
|
21
21
|
} = Model;
|
|
22
22
|
|
|
23
23
|
// Types
|
|
24
24
|
|
|
25
|
-
type AdvancedRelationTypeProps = RelationTypeProps & {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
export type AdvancedRelationTypeProps = RelationTypeProps & {
|
|
26
|
+
through: {
|
|
27
|
+
from: string;
|
|
28
|
+
to: string;
|
|
29
|
+
};
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
/*
|
|
@@ -34,11 +34,11 @@ type AdvancedRelationTypeProps = RelationTypeProps & {
|
|
|
34
34
|
another model.
|
|
35
35
|
*/
|
|
36
36
|
export function belongsRelation({ modelClass, from, to }: RelationTypeProps) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
return {
|
|
38
|
+
relation: BelongsToOneRelation,
|
|
39
|
+
modelClass,
|
|
40
|
+
join: { from, to },
|
|
41
|
+
};
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
/*
|
|
@@ -46,11 +46,11 @@ export function belongsRelation({ modelClass, from, to }: RelationTypeProps) {
|
|
|
46
46
|
model.
|
|
47
47
|
*/
|
|
48
48
|
export function hasOneRelation({ modelClass, from, to }: RelationTypeProps) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
return {
|
|
50
|
+
relation: HasOneRelation,
|
|
51
|
+
modelClass,
|
|
52
|
+
join: { from, to },
|
|
53
|
+
};
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
/*
|
|
@@ -58,11 +58,11 @@ export function hasOneRelation({ modelClass, from, to }: RelationTypeProps) {
|
|
|
58
58
|
another model.
|
|
59
59
|
*/
|
|
60
60
|
export function hasManyRelation({ modelClass, from, to }: RelationTypeProps) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
61
|
+
return {
|
|
62
|
+
relation: HasManyRelation,
|
|
63
|
+
modelClass,
|
|
64
|
+
join: { from, to },
|
|
65
|
+
};
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
/*
|
|
@@ -70,23 +70,23 @@ export function hasManyRelation({ modelClass, from, to }: RelationTypeProps) {
|
|
|
70
70
|
another model, via a join table
|
|
71
71
|
*/
|
|
72
72
|
export function hasManyThroughRelation({
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
modelClass,
|
|
74
|
+
from,
|
|
75
|
+
through,
|
|
76
|
+
to,
|
|
77
77
|
}: AdvancedRelationTypeProps) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
78
|
+
return {
|
|
79
|
+
relation: ManyToManyRelation,
|
|
80
|
+
modelClass,
|
|
81
|
+
join: { from, through, to },
|
|
82
|
+
};
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
type RelationProps = CommonRelationOrTableOrForeignKeyProps & {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
subject: string;
|
|
87
|
+
relType: "hasOne" | "hasMany" | "hasManyThrough" | "belongsTo";
|
|
88
|
+
object: string;
|
|
89
|
+
via?: string;
|
|
90
90
|
};
|
|
91
91
|
|
|
92
92
|
/*
|
|
@@ -94,48 +94,48 @@ type RelationProps = CommonRelationOrTableOrForeignKeyProps & {
|
|
|
94
94
|
along with an optional via model.
|
|
95
95
|
*/
|
|
96
96
|
export function relation({
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
97
|
+
subject,
|
|
98
|
+
relType,
|
|
99
|
+
object,
|
|
100
|
+
via,
|
|
101
|
+
options,
|
|
102
102
|
}: RelationProps) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
103
|
+
const subjectTable = getSubjectTable({ subject, options });
|
|
104
|
+
const objectTable = getObjectTable({ object, options });
|
|
105
|
+
const subjectForeignKey = getSubjectForeignKey({ subject, options });
|
|
106
|
+
const objectForeignKey = getObjectForeignKey({ object, options });
|
|
107
|
+
const modelClass = getModelClass({ object, options });
|
|
108
|
+
const viaTable = getViaTable(via);
|
|
109
|
+
switch (relType) {
|
|
110
|
+
case "hasOne":
|
|
111
|
+
return hasOneRelation({
|
|
112
|
+
modelClass,
|
|
113
|
+
from: `${subjectTable}.id`,
|
|
114
|
+
to: `${objectTable}.${subjectForeignKey}`,
|
|
115
|
+
});
|
|
116
|
+
case "hasMany":
|
|
117
|
+
return hasManyRelation({
|
|
118
|
+
modelClass,
|
|
119
|
+
from: `${subjectTable}.id`,
|
|
120
|
+
to: `${objectTable}.${subjectForeignKey}`,
|
|
121
|
+
});
|
|
122
|
+
case "hasManyThrough":
|
|
123
|
+
return hasManyThroughRelation({
|
|
124
|
+
modelClass,
|
|
125
|
+
from: `${subjectTable}.id`,
|
|
126
|
+
through: {
|
|
127
|
+
from: `${viaTable}.${subjectForeignKey}`,
|
|
128
|
+
to: `${viaTable}.${objectForeignKey}`,
|
|
129
|
+
},
|
|
130
|
+
to: `${objectTable}.id`,
|
|
131
|
+
});
|
|
132
|
+
case "belongsTo":
|
|
133
|
+
return belongsRelation({
|
|
134
|
+
modelClass,
|
|
135
|
+
from: `${subjectTable}.${objectForeignKey}`,
|
|
136
|
+
to: `${objectTable}.id`,
|
|
137
|
+
});
|
|
138
|
+
default:
|
|
139
|
+
throw new Error("No valid relationship type specified");
|
|
140
|
+
}
|
|
141
141
|
}
|