Skip to content

Commit 2760d47

Browse files
inlcude initial design for the GraphQL models
1 parent ca61b8e commit 2760d47

File tree

5 files changed

+391
-0
lines changed

5 files changed

+391
-0
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
import type { AttributeModel } from "./AttributeModel";
21+
22+
import { AGGREGATION_COMPARISON_OPERATORS } from "../../../constants";
23+
24+
type ComparisonOperator = typeof AGGREGATION_COMPARISON_OPERATORS[number];
25+
26+
export class AggregationModel {
27+
readonly attributeModel: AttributeModel;
28+
constructor(attributeModel: AttributeModel) {
29+
if (!attributeModel.isScalar()) {
30+
throw new Error("Attribute is not a scalar");
31+
}
32+
this.attributeModel = attributeModel;
33+
}
34+
35+
getAggregationComparators(): string[] {
36+
return AGGREGATION_COMPARISON_OPERATORS.map((comparator) => [
37+
this.getAverageComparator(comparator),
38+
this.getMinComparator(comparator),
39+
this.getMaxComparator(comparator),
40+
this.getSumComparator(comparator),
41+
]).flat();
42+
}
43+
44+
getAverageComparator(comparator: ComparisonOperator): string {
45+
return this.attributeModel.isString()
46+
? `${this.attributeModel.name}_AVERAGE_LENGTH_${comparator}`
47+
: `${this.attributeModel.name}_AVERAGE_${comparator}`;
48+
}
49+
50+
getMinComparator(comparator: ComparisonOperator): string {
51+
return `${this.attributeModel.name}_MIN_${comparator}`;
52+
}
53+
54+
getMaxComparator(comparator: ComparisonOperator): string {
55+
return `${this.attributeModel.name}_MAX_${comparator}`;
56+
}
57+
58+
getSumComparator(comparator: ComparisonOperator): string {
59+
return `${this.attributeModel.name}_SUM_${comparator}`;
60+
}
61+
62+
/**
63+
* Given the GraphQL field name, returns the semantic information about the aggregation it tries to perform
64+
**/
65+
getAggregationMetadata(graphQLField: string): { fieldName: string; operator: string; comparator: string } {
66+
throw new Error("Not implemented");
67+
}
68+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
import { MathModel } from "./MathModel";
21+
import { AggregationModel } from "./AggregationModel";
22+
import { ListModel } from "./ListModel";
23+
import type { Attribute } from "../Attribute";
24+
import type { Annotations } from "../../annotation/Annotation";
25+
import type { AttributeType } from "../AbstractAttribute";
26+
import { AbstractAttribute } from "../AbstractAttribute";
27+
import { ne } from "@faker-js/faker";
28+
29+
// Maybe rename it to GraphQL model
30+
export class AttributeModel extends AbstractAttribute {
31+
private _listModel: ListModel | undefined;
32+
private _mathModel: MathModel | undefined;
33+
private _aggregationModel: AggregationModel | undefined;
34+
public name: string;
35+
public annotations: Partial<Annotations>;
36+
public type: AttributeType;
37+
38+
constructor(attribute: Attribute) {
39+
super({ name: attribute.name, type: attribute.type, annotations: attribute.annotations });
40+
this.name = attribute.name;
41+
this.annotations = attribute.annotations;
42+
this.type = attribute.type;
43+
}
44+
45+
/**
46+
*
47+
* /**
48+
* Previously defined as:
49+
* [
50+
...this.temporalFields,
51+
...this.enumFields,
52+
...this.objectFields,
53+
...this.scalarFields,
54+
...this.primitiveFields,
55+
...this.interfaceFields,
56+
...this.objectFields,
57+
...this.unionFields,
58+
...this.pointFields,
59+
];
60+
*/
61+
isMutable(): boolean {
62+
// this is based on the assumption that interface fields and union fields are object fields
63+
return this.isTemporal() || this.isEnum() || this.isObject() || this.isScalar() ||
64+
this.isPrimitive() || this.isInterface() || this.isUnion() || this.isPoint();
65+
}
66+
67+
isUnique(): boolean {
68+
// TODO: add it when the annotations are merged
69+
// return this.attribute.annotations.unique ? true : false;
70+
return false;
71+
}
72+
/**
73+
* Previously defined as:
74+
* [...this.primitiveFields,
75+
...this.scalarFields,
76+
...this.enumFields,
77+
...this.temporalFields,
78+
...this.pointFields,]
79+
*/
80+
81+
isConstrainable(): boolean {
82+
return this.isPrimitive() || this.isScalar() || this.isEnum() || this.isTemporal() || this.isPoint();
83+
}
84+
// TODO: remember to figure out constrainableFields
85+
86+
/**
87+
* @throws {Error} if the attribute is not a list
88+
*/
89+
get listModel(): ListModel {
90+
if (!this._listModel) {
91+
this._listModel = new ListModel(this);
92+
}
93+
return this._listModel;
94+
}
95+
96+
/**
97+
* @throws {Error} if the attribute is not a scalar
98+
*/
99+
get mathModel(): MathModel {
100+
if (!this._mathModel) {
101+
this._mathModel = new MathModel(this);
102+
}
103+
return this._mathModel;
104+
}
105+
106+
get aggregationModel(): AggregationModel {
107+
if (!this._aggregationModel) {
108+
this._aggregationModel = new AggregationModel(this);
109+
}
110+
return this._aggregationModel;
111+
}
112+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
import type { AttributeModel } from "./AttributeModel";
21+
22+
export class ListModel {
23+
readonly attributeModel: AttributeModel;
24+
25+
constructor(attributeModel: AttributeModel) {
26+
if (!attributeModel.isList()) {
27+
throw new Error("Attribute is not a list");
28+
}
29+
this.attributeModel = attributeModel;
30+
}
31+
32+
getPush(): string {
33+
return `${this.attributeModel.name}_PUSH`;
34+
}
35+
36+
getPop(): string {
37+
return `${this.attributeModel.name}_POP`;
38+
}
39+
40+
getIncludes(): string {
41+
return `${this.attributeModel.name}_INCLUDES`;
42+
}
43+
44+
getNotIncludes(): string {
45+
return `${this.attributeModel.name}_NOT_INCLUDES`;
46+
}
47+
/**
48+
* Given the GraphQL field name, returns the semantic information about the list operation it tries to perform
49+
**/
50+
getListMetadata(graphQLField: string): { fieldName: string; operator: string; comparator?: string } {
51+
throw new Error("Not implemented");
52+
}
53+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
2+
/*
3+
* Copyright (c) "Neo4j"
4+
* Neo4j Sweden AB [http://neo4j.com]
5+
*
6+
* This file is part of Neo4j.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* Unless required by applicable law or agreed to in writing, software
16+
* distributed under the License is distributed on an "AS IS" BASIS,
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
import type { AttributeModel } from "./AttributeModel";
22+
23+
export class MathModel {
24+
readonly attributeModel: AttributeModel;
25+
constructor(attributeModel: AttributeModel) {
26+
if (!attributeModel.isScalar()) {
27+
throw new Error("Attribute is not a scalar");
28+
}
29+
this.attributeModel = attributeModel;
30+
}
31+
32+
getMathOperations(): string[] {
33+
return [this.getAdd(), this.getSubtract(), this.getMultiply(), this.getDecrement()];
34+
}
35+
36+
getAdd(): string {
37+
return this.attributeModel.isInt() || this.attributeModel.isBigInt()
38+
? `${this.attributeModel.name}_INCREMENT`
39+
: `${this.attributeModel.name}_ADD`;
40+
}
41+
42+
getSubtract(): string {
43+
return `${this.attributeModel.name}_SUBTRACT`;
44+
}
45+
46+
getMultiply(): string {
47+
return `${this.attributeModel.name}_MULTIPLY`;
48+
}
49+
50+
getDecrement(): string {
51+
return `${this.attributeModel.name}_DECREMENT`;
52+
}
53+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
import { AttributeModel } from "../../attribute/graphql-models/AttributeModel";
21+
import type { Relationship } from "../../relationship/Relationship";
22+
import { getFromMap } from "../../utils/get-from-map";
23+
import type { Entity } from "../Entity";
24+
import { AbstractEntity } from "../Entity";
25+
import { singular, plural } from "../../utils/string-manipulation";
26+
import type { ConcreteEntity } from "../ConcreteEntity";
27+
import type { Attribute } from "../../attribute/Attribute";
28+
29+
export class ConcreteEntityModel extends AbstractEntity {
30+
public readonly attributes: Map<string, AttributeModel> = new Map();
31+
// TODO: change Relationship to RelationshipModel
32+
public readonly relationships: Map<string, Relationship> = new Map();
33+
34+
// These keys allow to store the keys of the map in memory and avoid keep iterating over the map.
35+
private mutableFieldsKeys: string[] = [];
36+
private uniqueFieldsKeys: string[] = [];
37+
private constrainableFieldsKeys: string[] = [];
38+
39+
// TODO: remove this just added to help the migration.
40+
private readonly listAttributes: Attribute[] = [];
41+
42+
// typesNames
43+
private _singular: string | undefined;
44+
private _plural: string | undefined;
45+
46+
constructor(entity: ConcreteEntity) {
47+
super({ name: entity.name, labels: [...entity.labels] });
48+
this.initAttributes();
49+
}
50+
51+
private initAttributes() {
52+
this.listAttributes.forEach((attribute) => {
53+
const attributeModel = new AttributeModel(attribute);
54+
if (attributeModel.isMutable()) {
55+
this.mutableFieldsKeys.push(attribute.name);
56+
}
57+
if (attributeModel.isUnique()) {
58+
this.uniqueFieldsKeys.push(attribute.name);
59+
}
60+
if (attributeModel.isConstrainable()) {
61+
this.constrainableFieldsKeys.push(attribute.name);
62+
}
63+
64+
this.attributes.set(attribute.name, attributeModel);
65+
});
66+
}
67+
68+
public get mutableFields(): AttributeModel[] {
69+
return this.mutableFieldsKeys.map((key) => getFromMap(this.attributes, key));
70+
}
71+
72+
public get uniqueFields(): AttributeModel[] {
73+
return this.uniqueFieldsKeys.map((key) => getFromMap(this.attributes, key));
74+
}
75+
76+
public get constrainableFields(): AttributeModel[] {
77+
return this.constrainableFieldsKeys.map((key) => getFromMap(this.attributes, key));
78+
}
79+
80+
public get relationshipAttributesName(): string[] {
81+
return [...this.relationships.keys()];
82+
}
83+
84+
public getRelatedEntities(): Entity[] {
85+
return [...this.relationships.values()].map((relationship) => relationship.target);
86+
}
87+
88+
public getAllLabels(): string[] {
89+
throw new Error("Method not implemented.");
90+
}
91+
92+
public get singular(): string {
93+
if (!this._singular) {
94+
this._singular = singular(this.name);
95+
}
96+
return this._singular;
97+
}
98+
99+
public get plural(): string {
100+
if (!this._plural) {
101+
this._plural = plural(this.name);
102+
}
103+
return this._plural;
104+
}
105+
}

0 commit comments

Comments
 (0)