Skip to content

Commit

Permalink
Merge pull request #3883 from a-alle/schema-model-arguments
Browse files Browse the repository at this point in the history
Add Argument to SchemaModel
  • Loading branch information
a-alle authored Sep 6, 2023
2 parents ece8449 + bd3cd20 commit 6852a8c
Show file tree
Hide file tree
Showing 12 changed files with 431 additions and 7 deletions.
48 changes: 48 additions & 0 deletions packages/graphql/src/schema-model/argument/Argument.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [http://neo4j.com]
*
* This file is part of Neo4j.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import type { ValueNode } from "graphql";
import { parseValueNode } from "../parser/parse-value-node";
import type { AttributeType } from "../attribute/AttributeType";

export class Argument {
public readonly name: string;
public readonly type: AttributeType;
public readonly defaultValue?: string;
public readonly description: string;
// Arguments can have annotations but we don't seem to use this feature
// public readonly annotations: Partial<Annotations> = {};

constructor({
name,
type,
defaultValue,
description,
}: {
name: string;
type: AttributeType;
defaultValue?: ValueNode;
description?: string;
}) {
this.name = name;
this.type = type;
this.defaultValue = defaultValue ? parseValueNode(defaultValue) : undefined;
this.description = description || "";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
/*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [http://neo4j.com]
*
* This file is part of Neo4j.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import type { AttributeType } from "../../attribute/AttributeType";
import {
EnumType,
GraphQLBuiltInScalarType,
InterfaceType,
ListType,
Neo4jCartesianPointType,
Neo4jGraphQLNumberType,
Neo4jGraphQLSpatialType,
Neo4jGraphQLTemporalType,
Neo4jPointType,
ObjectType,
ScalarType,
UnionType,
UserScalarType,
} from "../../attribute/AttributeType";
import type { Argument } from "../Argument";

// TODO: this file has a lot in common with AttributeAdapter
// if going to use this, design a solution to avoid this code duplication

export class ArgumentAdapter {
public name: string;
public type: AttributeType;
public description: string;
public defaultValue?: string;
private assertionOptions: {
includeLists: boolean;
};
constructor(argument: Argument) {
this.name = argument.name;
this.type = argument.type;
this.defaultValue = argument.defaultValue;
this.description = argument.description;
this.assertionOptions = {
includeLists: true,
};
}

/**
* Just a helper to get the wrapped type in case of a list, useful for the assertions
*/
private getTypeForAssertion(includeLists: boolean) {
if (includeLists) {
return this.isList() ? this.type.ofType : this.type;
}
return this.type;
}

isBoolean(options = this.assertionOptions): boolean {
const type = this.getTypeForAssertion(options.includeLists);
return type instanceof ScalarType && type.name === GraphQLBuiltInScalarType.Boolean;
}

isID(options = this.assertionOptions): boolean {
const type = this.getTypeForAssertion(options.includeLists);
return type instanceof ScalarType && type.name === GraphQLBuiltInScalarType.ID;
}

isInt(options = this.assertionOptions): boolean {
const type = this.getTypeForAssertion(options.includeLists);
return type instanceof ScalarType && type.name === GraphQLBuiltInScalarType.Int;
}

isFloat(options = this.assertionOptions): boolean {
const type = this.getTypeForAssertion(options.includeLists);
return type instanceof ScalarType && type.name === GraphQLBuiltInScalarType.Float;
}

isString(options = this.assertionOptions): boolean {
const type = this.getTypeForAssertion(options.includeLists);
return type instanceof ScalarType && type.name === GraphQLBuiltInScalarType.String;
}

isCartesianPoint(options = this.assertionOptions): boolean {
const type = this.getTypeForAssertion(options.includeLists);
return type instanceof Neo4jCartesianPointType;
}

isPoint(options = this.assertionOptions): boolean {
const type = this.getTypeForAssertion(options.includeLists);
return type instanceof Neo4jPointType;
}

isBigInt(options = this.assertionOptions): boolean {
const type = this.getTypeForAssertion(options.includeLists);
return type instanceof ScalarType && type.name === Neo4jGraphQLNumberType.BigInt;
}

isDate(options = this.assertionOptions): boolean {
const type = this.getTypeForAssertion(options.includeLists);
return type instanceof ScalarType && type.name === Neo4jGraphQLTemporalType.Date;
}

isDateTime(options = this.assertionOptions): boolean {
const type = this.getTypeForAssertion(options.includeLists);
return type instanceof ScalarType && type.name === Neo4jGraphQLTemporalType.DateTime;
}

isLocalDateTime(options = this.assertionOptions): boolean {
const type = this.getTypeForAssertion(options.includeLists);
return type instanceof ScalarType && type.name === Neo4jGraphQLTemporalType.LocalDateTime;
}

isTime(options = this.assertionOptions): boolean {
const type = this.getTypeForAssertion(options.includeLists);
return type instanceof ScalarType && type.name === Neo4jGraphQLTemporalType.Time;
}

isLocalTime(options = this.assertionOptions): boolean {
const type = this.getTypeForAssertion(options.includeLists);
return (type.name as Neo4jGraphQLTemporalType) === Neo4jGraphQLTemporalType.LocalTime;
}

isDuration(options = this.assertionOptions): boolean {
const type = this.getTypeForAssertion(options.includeLists);
return (type.name as Neo4jGraphQLTemporalType) === Neo4jGraphQLTemporalType.Duration;
}

isObject(options = this.assertionOptions): boolean {
const type = this.getTypeForAssertion(options.includeLists);
return type instanceof ObjectType;
}

isEnum(options = this.assertionOptions): boolean {
const type = this.getTypeForAssertion(options.includeLists);
return type instanceof EnumType;
}

isInterface(options = this.assertionOptions): boolean {
const type = this.getTypeForAssertion(options.includeLists);
return type instanceof InterfaceType;
}

isUnion(options = this.assertionOptions): boolean {
const type = this.getTypeForAssertion(options.includeLists);
return type instanceof UnionType;
}

isList(): this is this & { type: ListType } {
return this.type instanceof ListType;
}

isUserScalar(options = this.assertionOptions): boolean {
const type = this.getTypeForAssertion(options.includeLists);
return type instanceof UserScalarType;
}

isTemporal(options = this.assertionOptions): boolean {
const type = this.getTypeForAssertion(options.includeLists);
return type.name in Neo4jGraphQLTemporalType;
}

isListElementRequired(): boolean {
if (!(this.type instanceof ListType)) {
return false;
}
return this.type.ofType.isRequired;
}

isRequired(): boolean {
return this.type.isRequired;
}

/**
*
* Schema Generator Stuff
*
*/
isGraphQLBuiltInScalar(options = this.assertionOptions): boolean {
const type = this.getTypeForAssertion(options.includeLists);
return type.name in GraphQLBuiltInScalarType;
}

isSpatial(options = this.assertionOptions): boolean {
const type = this.getTypeForAssertion(options.includeLists);
return type.name in Neo4jGraphQLSpatialType;
}

isAbstract(options = this.assertionOptions): boolean {
return this.isInterface(options) || this.isUnion(options);
}
/**
* Returns true for both built-in and user-defined scalars
**/
isScalar(options = this.assertionOptions): boolean {
return (
this.isGraphQLBuiltInScalar(options) ||
this.isTemporal(options) ||
this.isBigInt(options) ||
this.isUserScalar(options)
);
}

isNumeric(options = this.assertionOptions): boolean {
return this.isBigInt(options) || this.isFloat(options) || this.isInt(options);
}

/**
* END of category assertions
*/

/**
*
* Schema Generator Stuff
*
*/

getTypePrettyName(): string {
if (this.isList()) {
return `[${this.getTypeName()}${this.isListElementRequired() ? "!" : ""}]${this.isRequired() ? "!" : ""}`;
}
return `${this.getTypeName()}${this.isRequired() ? "!" : ""}`;
}

getTypeName(): string {
return this.isList() ? this.type.ofType.name : this.type.name;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ describe("Attribute", () => {
name: "test",
annotations: [],
type: new ScalarType(GraphQLBuiltInScalarType.String, true),
args: [],
});
const clone = attribute.clone();
expect(attribute).toStrictEqual(clone);
Expand Down
11 changes: 11 additions & 0 deletions packages/graphql/src/schema-model/attribute/Attribute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,37 @@

import { Neo4jGraphQLSchemaValidationError } from "../../classes/Error";
import { annotationToKey, type Annotation, type Annotations } from "../annotation/Annotation";
import type { Argument } from "../argument/Argument";
import type { AttributeType } from "./AttributeType";

export class Attribute {
public readonly name: string;
public readonly annotations: Partial<Annotations> = {};
public readonly type: AttributeType;
public readonly databaseName: string;
public readonly description: string;
public readonly args: Argument[];

constructor({
name,
annotations = [],
type,
args,
databaseName,
description,
}: {
name: string;
annotations: Annotation[];
type: AttributeType;
args: Argument[];
databaseName?: string;
description?: string;
}) {
this.name = name;
this.type = type;
this.args = args;
this.databaseName = databaseName ?? name;
this.description = description || "";

for (const annotation of annotations) {
this.addAnnotation(annotation);
Expand All @@ -52,7 +61,9 @@ export class Attribute {
name: this.name,
annotations: Object.values(this.annotations),
type: this.type,
args: this.args,
databaseName: this.databaseName,
description: this.description,
});
}

Expand Down
Loading

0 comments on commit 6852a8c

Please sign in to comment.