1818 */
1919
2020import { Neo4jGraphQLSchemaValidationError } from "../../classes/Error" ;
21+ import { AGGREGATION_COMPARISON_OPERATORS } from "../../constants" ;
22+ import type {
23+ PrimitiveField ,
24+ CustomScalarField ,
25+ CustomEnumField ,
26+ UnionField ,
27+ ObjectField ,
28+ TemporalField ,
29+ PointField ,
30+ CypherField ,
31+ } from "../../types" ;
2132import type { Annotation , Annotations } from "../annotation/Annotation" ;
2233import { AnnotationsKey , annotationToKey } from "../annotation/Annotation" ;
2334
24- export enum StandardGraphQLScalarType {
35+ export enum GraphQLBuiltInScalarType {
2536 Int = "Int" ,
2637 Float = "Float" ,
2738 String = "String" ,
2839 Boolean = "Boolean" ,
2940 ID = "ID" ,
30- }
41+ }
3142
32- export enum Neo4jGraphQLPointType {
43+ export enum Neo4jGraphQLSpatialType {
3344 CartesianPoint = "CartesianPoint" ,
3445 Point = "Point" ,
3546}
@@ -47,24 +58,27 @@ export enum Neo4jGraphQLTemporalType {
4758 Duration = "Duration" ,
4859}
4960
50- type Neo4jGraphQLScalarType = Neo4jGraphQLTemporalType | Neo4jGraphQLNumberType | Neo4jGraphQLPointType ;
61+ type Neo4jGraphQLScalarType = Neo4jGraphQLTemporalType | Neo4jGraphQLNumberType | Neo4jGraphQLSpatialType ;
5162
5263export type AttributeType = ScalarType | UserScalarType | ObjectType | ListType | EnumType ;
5364
65+ export type ScalarTypeType =
66+ | "Neo4jGraphQLTemporalType"
67+ | "Neo4jGraphQLNumberType"
68+ | "Neo4jGraphQLPointType"
69+ | "GraphQLBuiltInScalarType" ;
5470
55- export type ScalarTypeType = "Neo4jGraphQLTemporalType" | "Neo4jGraphQLNumberType" | "Neo4jGraphQLPointType" | "StandardGraphQLScalarType" ;
56- export class ScalarType {
57- name : StandardGraphQLScalarType | Neo4jGraphQLScalarType ;
71+ export class ScalarType {
72+ name : GraphQLBuiltInScalarType | Neo4jGraphQLScalarType ;
5873 isRequired : boolean ;
5974 ofType : ScalarTypeType ;
60- constructor ( name : StandardGraphQLScalarType | Neo4jGraphQLScalarType , isRequired : boolean , ofType : ScalarTypeType ) {
75+ constructor ( name : GraphQLBuiltInScalarType | Neo4jGraphQLScalarType , isRequired : boolean , ofType : ScalarTypeType ) {
6176 this . name = name ;
6277 this . isRequired = isRequired ;
6378 this . ofType = ofType ;
6479 }
6580}
6681
67-
6882export class UserScalarType {
6983 name : string ;
7084 isRequired : boolean ;
@@ -74,7 +88,7 @@ export class UserScalarType {
7488 }
7589}
7690
77- export class ObjectType {
91+ export class ObjectType {
7892 name : string ;
7993 isRequired : boolean ;
8094 constructor ( name : string , isRequired : boolean ) {
@@ -104,16 +118,9 @@ export class Attribute {
104118 public readonly annotations : Partial < Annotations > = { } ;
105119 public readonly type : AttributeType ;
106120 public isCypherField = false ;
121+ private _attributeModel : AttributeModel | undefined ;
107122
108- constructor ( {
109- name,
110- annotations,
111- type,
112- } : {
113- name : string ;
114- annotations : Annotation [ ] ;
115- type : AttributeType ;
116- } ) {
123+ constructor ( { name, annotations, type } : { name : string ; annotations : Annotation [ ] ; type : AttributeType } ) {
117124 this . name = name ;
118125 this . type = type ;
119126
@@ -130,7 +137,6 @@ export class Attribute {
130137 } ) ;
131138 }
132139
133-
134140 private addAnnotation ( annotation : Annotation ) : void {
135141 const annotationKey = annotationToKey ( annotation ) ;
136142 if ( this . annotations [ annotationKey ] ) {
@@ -144,4 +150,229 @@ export class Attribute {
144150 // There's no reason to narrow either, since we care more about performance.
145151 this . annotations [ annotationKey ] = annotation as any ;
146152 }
153+
154+ get attributeModel ( ) : AttributeModel {
155+ if ( ! this . _attributeModel ) {
156+ this . _attributeModel = new AttributeModel ( this ) ;
157+ }
158+ return this . _attributeModel ;
159+ }
160+
161+ isInt ( ) : boolean {
162+ return false ;
163+ }
164+
165+ isBigInt ( ) : boolean {
166+ return false ;
167+ }
168+
169+ isFloat ( ) : boolean {
170+ return false ;
171+ }
172+
173+ isList ( ) : boolean {
174+ return false ;
175+ }
176+
177+ isRequired ( ) : boolean {
178+ return true ;
179+ }
180+
181+ isScalar ( ) : boolean {
182+ return this . type instanceof ScalarType ;
183+ }
184+
185+ isCustomScalar ( ) : boolean {
186+ return false ;
187+ }
188+
189+ isSpatial ( ) : boolean {
190+ return false ;
191+ }
192+
193+ isTemporal ( ) : boolean {
194+ return false ;
195+ }
196+
197+ isObject ( ) : boolean {
198+ return false ;
199+ }
200+
201+ isEnum ( ) : boolean {
202+ return false ;
203+ }
204+ // isGraphQLBuiltInScalarType is the same as isPrimitive
205+ isGraphQLBuiltInScalar ( ) : boolean {
206+ return this . isScalar ( ) && ( this . type as ScalarType ) . ofType === "GraphQLBuiltInScalarType" ;
207+ }
208+ }
209+
210+ type MutableField =
211+ | PrimitiveField
212+ | CustomScalarField
213+ | CustomEnumField
214+ | UnionField
215+ | ObjectField
216+ | TemporalField
217+ | PointField
218+ | CypherField ;
219+
220+ class AttributeModel {
221+ readonly attribute : Attribute ;
222+ constructor ( attribute : Attribute ) {
223+ this . attribute = attribute ;
224+ }
225+
226+ isMutable ( ) : boolean {
227+ // this is based on the assumption that interface fields and union fields are object fields
228+ return (
229+ this . isSpatial ( ) || this . isTemporal ( ) || this . isEnum ( ) || this . isObject ( ) || this . isGraphQLBuiltInScalar ( )
230+ ) ;
231+ }
232+
233+ isUnique ( ) : boolean {
234+ //return this.attribute.annotations.unique ? true : false;
235+ return false ;
236+ }
237+ // TODO: remember to figure out constrainableFields
238+
239+ /**
240+ * @throws {Error } if the attribute is not a list
241+ */
242+ getListModel ( ) : ListModel {
243+ return new ListModel ( this ) ;
244+ }
245+
246+ /**
247+ * @throws {Error } if the attribute is not a scalar
248+ */
249+ getMathModel ( ) : MathModel {
250+ return new MathModel ( this ) ;
251+ }
252+
253+ /**
254+ * The following are just proxy methods to the attribute methods for convenience.
255+ * the idea is to improve the ergonomic for the client for case when they want to access information about the Attribute model,
256+ * and they are forced to switch between the attribute and the attribute model.
257+ *
258+ **/
259+ /**
260+ * START OF PROXY METHODS
261+ **/
262+ isCustomScalar ( ) : boolean {
263+ return this . attribute . isCustomScalar ( ) ;
264+ }
265+
266+ isInt ( ) : boolean {
267+ return this . attribute . isInt ( ) ;
268+ }
269+
270+ isBigInt ( ) : boolean {
271+ return this . attribute . isBigInt ( ) ;
272+ }
273+
274+ isFloat ( ) : boolean {
275+ return this . attribute . isFloat ( ) ;
276+ }
277+
278+ isList ( ) : boolean {
279+ return this . attribute . isList ( ) ;
280+ }
281+
282+ isRequired ( ) : boolean {
283+ return this . attribute . isRequired ( ) ;
284+ }
285+
286+ isScalar ( ) : boolean {
287+ return this . attribute . isScalar ( ) ;
288+ }
289+
290+ isGraphQLBuiltInScalar ( ) : boolean {
291+ return this . attribute . isGraphQLBuiltInScalar ( ) ;
292+ }
293+
294+ isSpatial ( ) : boolean {
295+ return this . attribute . isSpatial ( ) ;
296+ }
297+
298+ isTemporal ( ) : boolean {
299+ return this . attribute . isSpatial ( ) ;
300+ }
301+
302+ isObject ( ) : boolean {
303+ return this . attribute . isObject ( ) ;
304+ }
305+
306+ isEnum ( ) : boolean {
307+ return this . attribute . isEnum ( ) ;
308+ }
309+ /**
310+ * END OF PROXY METHODS
311+ **/
312+ }
313+
314+ class MathModel {
315+ readonly attributeModel : AttributeModel ;
316+ constructor ( attributeModel : AttributeModel ) {
317+ if ( ! attributeModel . isScalar ( ) ) {
318+ throw new Error ( "Attribute is not a scalar" ) ;
319+ }
320+ this . attributeModel = attributeModel ;
321+ }
322+
323+ getMathMethods ( ) : string [ ] {
324+ return [ this . getAdd ( ) ] ;
325+ }
326+
327+ getAdd ( ) : string {
328+ return this . attributeModel . attribute . isInt ( ) || this . attributeModel . attribute . isBigInt ( )
329+ ? `${ this . attributeModel . attribute . name } _ADD`
330+ : `${ this . attributeModel . attribute . name } _INCREMENT` ;
331+ }
332+ }
333+
334+ class AggregationModel {
335+ readonly attributeModel : AttributeModel ;
336+ constructor ( attributeModel : AttributeModel ) {
337+ if ( ! attributeModel . isScalar ( ) ) {
338+ throw new Error ( "Attribute is not a scalar" ) ;
339+ }
340+ this . attributeModel = attributeModel ;
341+ }
342+
343+ getAggregationMethods ( ) : string [ ] {
344+ return [ ...this . getAverageMethods ( ) ] ;
345+ }
346+
347+ getAverageMethods ( ) : string [ ] {
348+ return AGGREGATION_COMPARISON_OPERATORS . map (
349+ ( operator ) => `${ this . attributeModel . attribute . name } _AVERAGE_${ operator } `
350+ ) ;
351+ }
352+ isAggregate ( string ) : boolean {
353+
354+ }
355+ }
356+
357+ class ListModel {
358+ readonly attributeModel : AttributeModel ;
359+
360+ constructor ( attributeModel : AttributeModel ) {
361+ if ( ! attributeModel . attribute . isList ( ) ) {
362+ throw new Error ( "Attribute is not a list" ) ;
363+ }
364+ this . attributeModel = attributeModel ;
365+ }
366+
367+ getArrayMethods ( ) : string [ ] {
368+ return [ this . getPush ( ) , this . getPop ( ) ] ;
369+ }
370+
371+ getPush ( ) : string {
372+ return `${ this . attributeModel . attribute . name } _PUSH` ;
373+ }
374+
375+ getPop ( ) : string {
376+ return `${ this . attributeModel . attribute . name } _POP` ;
377+ }
147378}
0 commit comments