diff --git a/src/Core/Azure.DataApiBuilder.Core.csproj b/src/Core/Azure.DataApiBuilder.Core.csproj
index 3850c5f587..a4ac48aeb5 100644
--- a/src/Core/Azure.DataApiBuilder.Core.csproj
+++ b/src/Core/Azure.DataApiBuilder.Core.csproj
@@ -11,6 +11,7 @@
+
diff --git a/src/Core/Parsers/EdmModelBuilder.cs b/src/Core/Parsers/EdmModelBuilder.cs
index 9babe11280..d895c8391b 100644
--- a/src/Core/Parsers/EdmModelBuilder.cs
+++ b/src/Core/Parsers/EdmModelBuilder.cs
@@ -67,30 +67,9 @@ SourceDefinition sourceDefinition
// each column represents a property of the current entity we are adding
foreach (string column in sourceDefinition.Columns.Keys)
{
- // need to convert our column system type to an Edm type
Type columnSystemType = sourceDefinition.Columns[column].SystemType;
- EdmPrimitiveTypeKind type = EdmPrimitiveTypeKind.None;
- if (columnSystemType.IsArray)
- {
- columnSystemType = columnSystemType.GetElementType()!;
- }
-
- type = columnSystemType.Name switch
- {
- "String" => EdmPrimitiveTypeKind.String,
- "Guid" => EdmPrimitiveTypeKind.Guid,
- "Byte" => EdmPrimitiveTypeKind.Byte,
- "Int16" => EdmPrimitiveTypeKind.Int16,
- "Int32" => EdmPrimitiveTypeKind.Int32,
- "Int64" => EdmPrimitiveTypeKind.Int64,
- "Single" => EdmPrimitiveTypeKind.Single,
- "Double" => EdmPrimitiveTypeKind.Double,
- "Decimal" => EdmPrimitiveTypeKind.Decimal,
- "Boolean" => EdmPrimitiveTypeKind.Boolean,
- "DateTime" or "DateTimeOffset" => EdmPrimitiveTypeKind.DateTimeOffset,
- "Date" => EdmPrimitiveTypeKind.Date,
- _ => throw new ArgumentException($"Column type {columnSystemType.Name} not yet supported."),
- };
+ // need to convert our column system type to an Edm type
+ EdmPrimitiveTypeKind type = TypeHelper.GetEdmPrimitiveTypeFromSystemType(columnSystemType);
// The mapped (aliased) field name defined in the runtime config is used to create a representative
// OData StructuralProperty. The created property is then added to the EdmEntityType.
diff --git a/src/Core/Parsers/ODataASTVisitor.cs b/src/Core/Parsers/ODataASTVisitor.cs
index 829602f677..901de39935 100644
--- a/src/Core/Parsers/ODataASTVisitor.cs
+++ b/src/Core/Parsers/ODataASTVisitor.cs
@@ -143,6 +143,8 @@ private static object GetParamWithSystemType(string param, IEdmTypeReference edm
return DateTimeOffset.Parse(param);
case EdmPrimitiveTypeKind.String:
return param;
+ case EdmPrimitiveTypeKind.TimeOfDay:
+ return TimeOnly.Parse(param);
default:
// should never happen due to the config being validated for correct types
throw new NotSupportedException($"{edmType} is not supported");
diff --git a/src/Core/Resolvers/Sql Query Structures/BaseSqlQueryStructure.cs b/src/Core/Resolvers/Sql Query Structures/BaseSqlQueryStructure.cs
index 30bcd60710..b3c89b9004 100644
--- a/src/Core/Resolvers/Sql Query Structures/BaseSqlQueryStructure.cs
+++ b/src/Core/Resolvers/Sql Query Structures/BaseSqlQueryStructure.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT License.
using System.Data;
+using System.Globalization;
using System.Net;
using Azure.DataApiBuilder.Auth;
using Azure.DataApiBuilder.Config.DatabasePrimitives;
@@ -360,10 +361,12 @@ protected static object ParseParamAsSystemType(string param, Type systemType)
"Double" => double.Parse(param),
"Decimal" => decimal.Parse(param),
"Boolean" => bool.Parse(param),
- "DateTime" => DateTimeOffset.Parse(param),
- "DateTimeOffset" => DateTimeOffset.Parse(param),
+ "DateTime" => DateTimeOffset.Parse(param, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal),
+ "DateTimeOffset" => DateTimeOffset.Parse(param, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal),
"Date" => DateOnly.Parse(param),
"Guid" => Guid.Parse(param),
+ "TimeOnly" => TimeOnly.Parse(param),
+ "TimeSpan" => TimeOnly.Parse(param),
_ => throw new NotSupportedException($"{systemType.Name} is not supported")
};
}
diff --git a/src/Core/Services/ResolverMiddleware.cs b/src/Core/Services/ResolverMiddleware.cs
index aa3c857807..d3941e7805 100644
--- a/src/Core/Services/ResolverMiddleware.cs
+++ b/src/Core/Services/ResolverMiddleware.cs
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
+using System.Globalization;
using System.Text.Json;
using Azure.DataApiBuilder.Core.Authorization;
using Azure.DataApiBuilder.Core.Models;
@@ -9,8 +10,10 @@
using HotChocolate.Execution;
using HotChocolate.Language;
using HotChocolate.Resolvers;
+using HotChocolate.Types.NodaTime;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
+using NodaTime.Text;
using static Azure.DataApiBuilder.Service.GraphQLBuilder.GraphQLTypes.SupportedTypes;
namespace Azure.DataApiBuilder.Core.Services
@@ -196,8 +199,9 @@ private static object PreParseLeaf(IMiddlewareContext context, string leafJson)
{
ByteType => byte.Parse(leafJson),
SingleType => Single.Parse(leafJson),
- DateTimeType => DateTimeOffset.Parse(leafJson),
+ DateTimeType => DateTimeOffset.Parse(leafJson, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal),
ByteArrayType => Convert.FromBase64String(leafJson),
+ LocalTimeType => LocalTimePattern.ExtendedIso.Parse(leafJson).Value,
_ => leafJson
};
}
diff --git a/src/Core/Services/TypeHelper.cs b/src/Core/Services/TypeHelper.cs
index 7c41909748..2bd6d448af 100644
--- a/src/Core/Services/TypeHelper.cs
+++ b/src/Core/Services/TypeHelper.cs
@@ -5,6 +5,7 @@
using System.Net;
using Azure.DataApiBuilder.Core.Services.OpenAPI;
using Azure.DataApiBuilder.Service.Exceptions;
+using Microsoft.OData.Edm;
namespace Azure.DataApiBuilder.Core.Services
{
@@ -16,6 +17,10 @@ public static class TypeHelper
{
///
/// Maps .NET Framework types to DbType enum
+ /// Not Adding a hard mapping for System.DateTime to DbType.DateTime as
+ /// Hotchocolate only has Hotchocolate.Types.DateTime for DbType.DateTime/DateTime2/DateTimeOffset,
+ /// which throws error when inserting/updating dateTime values due to type mismatch.
+ /// Therefore, seperate logic exists for proper mapping conversion in BaseSqlQueryStructure.
///
private static Dictionary _systemTypeToDbTypeMap = new()
{
@@ -34,21 +39,10 @@ public static class TypeHelper
[typeof(string)] = DbType.String,
[typeof(char)] = DbType.StringFixedLength,
[typeof(Guid)] = DbType.Guid,
+ [typeof(DateTimeOffset)] = DbType.DateTimeOffset,
[typeof(byte[])] = DbType.Binary,
- [typeof(byte?)] = DbType.Byte,
- [typeof(sbyte?)] = DbType.SByte,
- [typeof(short?)] = DbType.Int16,
- [typeof(ushort?)] = DbType.UInt16,
- [typeof(int?)] = DbType.Int32,
- [typeof(uint?)] = DbType.UInt32,
- [typeof(long?)] = DbType.Int64,
- [typeof(ulong?)] = DbType.UInt64,
- [typeof(float?)] = DbType.Single,
- [typeof(double?)] = DbType.Double,
- [typeof(decimal?)] = DbType.Decimal,
- [typeof(bool?)] = DbType.Boolean,
- [typeof(char?)] = DbType.StringFixedLength,
- [typeof(Guid?)] = DbType.Guid,
+ [typeof(TimeOnly)] = DbType.Time,
+ [typeof(TimeSpan)] = DbType.Time,
[typeof(object)] = DbType.Object
};
@@ -77,6 +71,7 @@ public static class TypeHelper
[typeof(Guid)] = JsonDataType.String,
[typeof(byte[])] = JsonDataType.String,
[typeof(TimeSpan)] = JsonDataType.String,
+ [typeof(TimeOnly)] = JsonDataType.String,
[typeof(object)] = JsonDataType.Object,
[typeof(DateTime)] = JsonDataType.String,
[typeof(DateTimeOffset)] = JsonDataType.String
@@ -108,7 +103,7 @@ public static class TypeHelper
[SqlDbType.SmallInt] = typeof(short),
[SqlDbType.SmallMoney] = typeof(decimal),
[SqlDbType.Text] = typeof(string),
- [SqlDbType.Time] = typeof(TimeSpan),
+ [SqlDbType.Time] = typeof(TimeOnly),
[SqlDbType.Timestamp] = typeof(byte[]),
[SqlDbType.TinyInt] = typeof(byte),
[SqlDbType.UniqueIdentifier] = typeof(Guid),
@@ -116,6 +111,43 @@ public static class TypeHelper
[SqlDbType.VarChar] = typeof(string)
};
+ ///
+ /// Given the system type, returns the corresponding primitive type kind.
+ ///
+ /// Type of the column.
+ /// EdmPrimitiveTypeKind
+ /// Throws when the column
+ public static EdmPrimitiveTypeKind GetEdmPrimitiveTypeFromSystemType(Type columnSystemType)
+ {
+ if (columnSystemType.IsArray)
+ {
+ columnSystemType = columnSystemType.GetElementType()!;
+ }
+
+ EdmPrimitiveTypeKind type = columnSystemType.Name switch
+ {
+ "String" => EdmPrimitiveTypeKind.String,
+ "Guid" => EdmPrimitiveTypeKind.Guid,
+ "Byte" => EdmPrimitiveTypeKind.Byte,
+ "Int16" => EdmPrimitiveTypeKind.Int16,
+ "Int32" => EdmPrimitiveTypeKind.Int32,
+ "Int64" => EdmPrimitiveTypeKind.Int64,
+ "Single" => EdmPrimitiveTypeKind.Single,
+ "Double" => EdmPrimitiveTypeKind.Double,
+ "Decimal" => EdmPrimitiveTypeKind.Decimal,
+ "Boolean" => EdmPrimitiveTypeKind.Boolean,
+ "DateTime" => EdmPrimitiveTypeKind.DateTimeOffset,
+ "DateTimeOffset" => EdmPrimitiveTypeKind.DateTimeOffset,
+ "Date" => EdmPrimitiveTypeKind.Date,
+ "TimeOnly" => EdmPrimitiveTypeKind.TimeOfDay,
+ "TimeSpan" => EdmPrimitiveTypeKind.TimeOfDay,
+ _ => throw new ArgumentException($"Column type" +
+ $" {columnSystemType.Name} not yet supported.")
+ };
+
+ return type;
+ }
+
///
/// Converts the .NET Framework (System/CLR) type to JsonDataType.
/// Primitive data types in the OpenAPI standard (OAS) are based on the types supported
@@ -151,6 +183,15 @@ public static JsonDataType GetJsonDataTypeFromSystemType(Type type)
/// DbType for the given system type. Null when no mapping exists.
public static DbType? GetDbTypeFromSystemType(Type systemType)
{
+ // Get the underlying type argument if the 'systemType' argument is a nullable type.
+ Type? nullableUnderlyingType = Nullable.GetUnderlyingType(systemType);
+
+ // Will not be null when the input argument 'systemType' is a closed generic nullable type.
+ if (nullableUnderlyingType is not null)
+ {
+ systemType = nullableUnderlyingType;
+ }
+
if (!_systemTypeToDbTypeMap.TryGetValue(systemType, out DbType dbType))
{
return null;
diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props
index dde5860283..ec66e68506 100644
--- a/src/Directory.Packages.props
+++ b/src/Directory.Packages.props
@@ -9,6 +9,7 @@
+
@@ -19,7 +20,7 @@
-
+
diff --git a/src/Service.GraphQLBuilder/Azure.DataApiBuilder.Service.GraphQLBuilder.csproj b/src/Service.GraphQLBuilder/Azure.DataApiBuilder.Service.GraphQLBuilder.csproj
index 71530f1eba..80fc4b94eb 100644
--- a/src/Service.GraphQLBuilder/Azure.DataApiBuilder.Service.GraphQLBuilder.csproj
+++ b/src/Service.GraphQLBuilder/Azure.DataApiBuilder.Service.GraphQLBuilder.csproj
@@ -20,6 +20,7 @@
+
diff --git a/src/Service.GraphQLBuilder/GraphQLTypes/DefaultValueType.cs b/src/Service.GraphQLBuilder/GraphQLTypes/DefaultValueType.cs
index 2ce9d6b95e..be27c13555 100644
--- a/src/Service.GraphQLBuilder/GraphQLTypes/DefaultValueType.cs
+++ b/src/Service.GraphQLBuilder/GraphQLTypes/DefaultValueType.cs
@@ -3,6 +3,7 @@
using Azure.DataApiBuilder.Service.GraphQLBuilder.CustomScalars;
using HotChocolate.Types;
+using HotChocolate.Types.NodaTime;
using static Azure.DataApiBuilder.Service.GraphQLBuilder.GraphQLTypes.SupportedTypes;
namespace Azure.DataApiBuilder.Service.GraphQLBuilder.GraphQLTypes
@@ -24,6 +25,7 @@ protected override void Configure(IInputObjectTypeDescriptor descriptor)
descriptor.Field(DECIMAL_TYPE).Type();
descriptor.Field(DATETIME_TYPE).Type();
descriptor.Field(BYTEARRAY_TYPE).Type();
+ descriptor.Field(LOCALTIME_TYPE).Type();
}
}
}
diff --git a/src/Service.GraphQLBuilder/GraphQLTypes/SupportedTypes.cs b/src/Service.GraphQLBuilder/GraphQLTypes/SupportedTypes.cs
index 52c1b25ad4..4470f8e2d1 100644
--- a/src/Service.GraphQLBuilder/GraphQLTypes/SupportedTypes.cs
+++ b/src/Service.GraphQLBuilder/GraphQLTypes/SupportedTypes.cs
@@ -18,8 +18,10 @@ public static class SupportedTypes
public const string STRING_TYPE = "String";
public const string BOOLEAN_TYPE = "Boolean";
public const string DATETIME_TYPE = "DateTime";
- public const string DATETIME_NONUTC_TYPE = "DateTimeNonUTC";
+ public const string DATETIMEOFFSET_TYPE = "DateTimeOffset";
public const string BYTEARRAY_TYPE = "ByteArray";
public const string GUID_TYPE = "Guid";
+ public const string LOCALTIME_TYPE = "LocalTime";
+ public const string TIME_TYPE = "Time";
}
}
diff --git a/src/Service.GraphQLBuilder/GraphQLUtils.cs b/src/Service.GraphQLBuilder/GraphQLUtils.cs
index 3b7d10bb1b..972ec5f5b4 100644
--- a/src/Service.GraphQLBuilder/GraphQLUtils.cs
+++ b/src/Service.GraphQLBuilder/GraphQLUtils.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT License.
using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
using System.Net;
using Azure.DataApiBuilder.Config.DatabasePrimitives;
using Azure.DataApiBuilder.Config.ObjectModel;
@@ -11,6 +12,8 @@
using Azure.DataApiBuilder.Service.GraphQLBuilder.Sql;
using HotChocolate.Language;
using HotChocolate.Types;
+using HotChocolate.Types.NodaTime;
+using NodaTime.Text;
using static Azure.DataApiBuilder.Service.GraphQLBuilder.GraphQLTypes.SupportedTypes;
namespace Azure.DataApiBuilder.Service.GraphQLBuilder
@@ -52,7 +55,8 @@ public static bool IsBuiltInType(ITypeNode typeNode)
STRING_TYPE,
BOOLEAN_TYPE,
DATETIME_TYPE,
- BYTEARRAY_TYPE
+ BYTEARRAY_TYPE,
+ LOCALTIME_TYPE
};
string name = typeNode.NamedType().Name.Value;
return inBuiltTypes.Contains(name);
@@ -239,8 +243,10 @@ public static Tuple ConvertValueToGraphQLType(string default
SINGLE_TYPE => new(SINGLE_TYPE, new SingleType().ParseValue(float.Parse(defaultValueFromConfig))),
FLOAT_TYPE => new(FLOAT_TYPE, new FloatValueNode(double.Parse(defaultValueFromConfig))),
DECIMAL_TYPE => new(DECIMAL_TYPE, new FloatValueNode(decimal.Parse(defaultValueFromConfig))),
- DATETIME_TYPE => new(DATETIME_TYPE, new DateTimeType().ParseResult(DateTime.Parse(defaultValueFromConfig))),
+ DATETIME_TYPE => new(DATETIME_TYPE, new DateTimeType().ParseResult(
+ DateTime.Parse(defaultValueFromConfig, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal))),
BYTEARRAY_TYPE => new(BYTEARRAY_TYPE, new ByteArrayType().ParseValue(Convert.FromBase64String(defaultValueFromConfig))),
+ LOCALTIME_TYPE => new(LOCALTIME_TYPE, new LocalTimeType().ParseResult(LocalTimePattern.ExtendedIso.Parse(defaultValueFromConfig).Value)),
_ => throw new NotSupportedException(message: $"The {defaultValueFromConfig} parameter's value type [{paramValueType}] is not supported.")
};
diff --git a/src/Service.GraphQLBuilder/Queries/StandardQueryInputs.cs b/src/Service.GraphQLBuilder/Queries/StandardQueryInputs.cs
index 69ead89827..365aca7f74 100644
--- a/src/Service.GraphQLBuilder/Queries/StandardQueryInputs.cs
+++ b/src/Service.GraphQLBuilder/Queries/StandardQueryInputs.cs
@@ -4,6 +4,7 @@
using Azure.DataApiBuilder.Service.GraphQLBuilder.CustomScalars;
using HotChocolate.Language;
using HotChocolate.Types;
+using HotChocolate.Types.NodaTime;
using static Azure.DataApiBuilder.Service.GraphQLBuilder.GraphQLTypes.SupportedTypes;
namespace Azure.DataApiBuilder.Service.GraphQLBuilder.Queries
@@ -201,6 +202,23 @@ public static InputObjectTypeDefinitionNode ByteArrayInputType() =>
}
);
+ public static InputObjectTypeDefinitionNode LocalTimeInputType() =>
+ new(
+ location: null,
+ new NameNode("LocalTimeFilterInput"),
+ new StringValueNode("Input type for adding LocalTime filters"),
+ new List(),
+ new List {
+ new InputValueDefinitionNode(null, new NameNode("eq"), new StringValueNode("Equals"), new LocalTimeType().ToTypeNode(), null, new List()),
+ new InputValueDefinitionNode(null, new NameNode("gt"), new StringValueNode("Greater Than"), new LocalTimeType().ToTypeNode(), null, new List()),
+ new InputValueDefinitionNode(null, new NameNode("gte"), new StringValueNode("Greater Than or Equal To"), new LocalTimeType().ToTypeNode(), null, new List()),
+ new InputValueDefinitionNode(null, new NameNode("lt"), new StringValueNode("Less Than"), new LocalTimeType().ToTypeNode(), null, new List()),
+ new InputValueDefinitionNode(null, new NameNode("lte"), new StringValueNode("Less Than or Equal To"), new LocalTimeType().ToTypeNode(), null, new List()),
+ new InputValueDefinitionNode(null, new NameNode("neq"), new StringValueNode("Not Equals"), new LocalTimeType().ToTypeNode(), null, new List()),
+ new InputValueDefinitionNode(null, new NameNode("isNull"), new StringValueNode("is null test"), new BooleanType().ToTypeNode(), null, new List())
+ }
+ );
+
public static Dictionary InputTypes = new()
{
{ "ID", IdInputType() },
@@ -214,7 +232,8 @@ public static InputObjectTypeDefinitionNode ByteArrayInputType() =>
{ BOOLEAN_TYPE, BooleanInputType() },
{ STRING_TYPE, StringInputType() },
{ DATETIME_TYPE, DateTimeInputType() },
- { BYTEARRAY_TYPE, ByteArrayInputType() }
+ { BYTEARRAY_TYPE, ByteArrayInputType() },
+ { LOCALTIME_TYPE, LocalTimeInputType() },
};
///
diff --git a/src/Service.GraphQLBuilder/Sql/SchemaConverter.cs b/src/Service.GraphQLBuilder/Sql/SchemaConverter.cs
index 703dc2c975..d51d397a71 100644
--- a/src/Service.GraphQLBuilder/Sql/SchemaConverter.cs
+++ b/src/Service.GraphQLBuilder/Sql/SchemaConverter.cs
@@ -12,6 +12,7 @@
using Azure.DataApiBuilder.Service.GraphQLBuilder.Queries;
using HotChocolate.Language;
using HotChocolate.Types;
+using HotChocolate.Types.NodaTime;
using static Azure.DataApiBuilder.Service.GraphQLBuilder.GraphQLNaming;
using static Azure.DataApiBuilder.Service.GraphQLBuilder.GraphQLStoredProcedureBuilder;
using static Azure.DataApiBuilder.Service.GraphQLBuilder.GraphQLTypes.SupportedTypes;
@@ -231,6 +232,8 @@ public static string GetGraphQLTypeFromSystemType(Type type)
"DateTime" => DATETIME_TYPE,
"DateTimeOffset" => DATETIME_TYPE,
"Byte[]" => BYTEARRAY_TYPE,
+ "TimeOnly" => LOCALTIME_TYPE,
+ "TimeSpan" => LOCALTIME_TYPE,
_ => throw new DataApiBuilderException(
message: $"Column type {type} not handled by case. Please add a case resolving {type} to the appropriate GraphQL type",
statusCode: HttpStatusCode.InternalServerError,
@@ -264,6 +267,7 @@ public static IValueNode CreateValueNodeFromDbObjectMetadata(object metadataValu
DateTimeOffset value => new ObjectValueNode(new ObjectFieldNode(DATETIME_TYPE, new DateTimeType().ParseValue(value))),
DateTime value => new ObjectValueNode(new ObjectFieldNode(DATETIME_TYPE, new DateTimeType().ParseResult(value))),
byte[] value => new ObjectValueNode(new ObjectFieldNode(BYTEARRAY_TYPE, new ByteArrayType().ParseValue(value))),
+ TimeOnly value => new ObjectValueNode(new ObjectFieldNode(LOCALTIME_TYPE, new LocalTimeType().ParseResult(value))),
_ => throw new DataApiBuilderException(
message: $"The type {metadataValue.GetType()} is not supported as a GraphQL default value",
statusCode: HttpStatusCode.InternalServerError,
diff --git a/src/Service.Tests/DatabaseSchema-MsSql.sql b/src/Service.Tests/DatabaseSchema-MsSql.sql
index 38a4f9c329..4768723a12 100644
--- a/src/Service.Tests/DatabaseSchema-MsSql.sql
+++ b/src/Service.Tests/DatabaseSchema-MsSql.sql
@@ -66,7 +66,7 @@ CREATE TABLE books(
CREATE TABLE players(
id int IDENTITY(5001, 1) PRIMARY KEY,
- name varchar(max) NOT NULL,
+ [name] varchar(max) NOT NULL,
current_club_id int NOT NULL,
new_club_id int NOT NULL
);
@@ -162,6 +162,7 @@ CREATE TABLE type_table(
datetime2_types datetime2,
datetimeoffset_types datetimeoffset,
smalldatetime_types smalldatetime,
+ time_types time,
bytearray_types varbinary(max),
guid_types uniqueidentifier DEFAULT newid()
);
@@ -377,7 +378,7 @@ VALUES (1, 'Awesome book', 1234),
SET IDENTITY_INSERT books OFF
SET IDENTITY_INSERT players ON
-INSERT INTO players(id, name, current_club_id, new_club_id)
+INSERT INTO players(id, [name], current_club_id, new_club_id)
VALUES (1, 'Cristiano Ronaldo', 1113, 1111),
(2, 'Leonel Messi', 1112, 1113);
SET IDENTITY_INSERT players OFF
@@ -398,22 +399,22 @@ byte_types, short_types, int_types, long_types,
string_types,
single_types, float_types, decimal_types,
boolean_types,
-date_types, datetime_types, datetime2_types, datetimeoffset_types, smalldatetime_types,
+date_types, datetime_types, datetime2_types, datetimeoffset_types, smalldatetime_types, time_types,
bytearray_types)
VALUES
(1, 1, 1, 1, 1, '', 0.33, 0.33, 0.333333, 1,
- '1999-01-08', '1999-01-08 10:23:54', '1999-01-08 10:23:54.9999999', '1999-01-08 10:23:54.9999999-14:00', '1999-01-08 10:23:54',
+ '1999-01-08', '1999-01-08 10:23:54', '1999-01-08 10:23:54.9999999', '1999-01-08 10:23:54.9999999-14:00', '1999-01-08 10:23:54', '10:23:54.9999999',
0xABCDEF0123),
(2, 0, -1, -1, -1, 'lksa;jdflasdf;alsdflksdfkldj', -9.2, -9.2, -9.292929, 0,
- '1999-01-08', '1999-01-08 10:23:00', '1999-01-08 10:23:00.9999999', '1999-01-08 10:23:00.9999999+13:00', '1999-01-08 10:23:00',
+ '1999-01-08', '1999-01-08 10:23:00', '1999-01-08 10:23:00.9999999', '1999-01-08 10:23:00.9999999+13:00', '1999-01-08 10:23:00', '10:23:00.9999999',
0x98AB7511AABB1234),
(3, 0, -32768, -2147483648, -9223372036854775808, 'null', -3.4E38, -1.7E308, 2.929292E-19, 1,
- '0001-01-01', '1753-01-01 00:00:00.000', '0001-01-01 00:00:00.0000000', '0001-01-01 00:00:00.0000000+0:00', '1900-01-01 00:00:00',
+ '0001-01-01', '1753-01-01 00:00:00.000', '0001-01-01 00:00:00.0000000', '0001-01-01 00:00:00.0000000+0:00', '1900-01-01 00:00:00', '00:00:00.0000000',
0x00000000),
(4, 255, 32767, 2147483647, 9223372036854775807, 'null', 3.4E38, 1.7E308, 2.929292E-14, 1,
- '9998-12-31', '9998-12-31 23:59:59', '9998-12-31 23:59:59.9999999', '9998-12-31 23:59:59.9999999+00:00', '2079-06-06',
+ '9999-12-31', '9999-12-31 23:59:59', '9999-12-31 23:59:59.9999999', '9999-12-31 23:59:59.9999999+14:00', '2079-06-06', '23:59:59.9999999',
0xFFFFFFFF),
- (5, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ (5, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
SET IDENTITY_INSERT type_table OFF
SET IDENTITY_INSERT sales ON
diff --git a/src/Service.Tests/DatabaseSchema-MySql.sql b/src/Service.Tests/DatabaseSchema-MySql.sql
index 034041d70a..ecc27255c1 100644
--- a/src/Service.Tests/DatabaseSchema-MySql.sql
+++ b/src/Service.Tests/DatabaseSchema-MySql.sql
@@ -334,7 +334,7 @@ INSERT INTO type_table(id, byte_types, short_types, int_types, long_types, strin
(1, 1, 1, 1, 1, '', 0.33, 0.33, 0.333333, true, '1999-01-08 10:23:54', 0xABCDEF0123),
(2, 0, -1, -1, -1, 'lksa;jdflasdf;alsdflksdfkldj', -9.2, -9.2, -9.292929, false, '1999-01-08 10:23:00', 0x98AB7511AABB1234),
(3, 0, -32768, -2147483648, -9223372036854775808, '', -3.4E38, -1.7E308, 2.929292E-19, true, '1753-01-01 00:00:00.000', 0x00000000),
- (4, 255, 32767, 2147483647, 9223372036854775807, 'null', 3.4E38, 1.7E308, 2.929292E-14, true, '9998-12-31 23:59:59', 0xFFFFFFFF),
+ (4, 255, 32767, 2147483647, 9223372036854775807, 'null', 3.4E38, 1.7E308, 2.929292E-14, true, '9999-12-31 23:59:59', 0xFFFFFFFF),
(5, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO trees(treeId, species, region, height) VALUES (1, 'Tsuga terophylla', 'Pacific Northwest', '30m'), (2, 'Pseudotsuga menziesii', 'Pacific Northwest', '40m');
INSERT INTO fungi(speciesid, region) VALUES (1, 'northeast'), (2, 'southwest');
diff --git a/src/Service.Tests/DatabaseSchema-PostgreSql.sql b/src/Service.Tests/DatabaseSchema-PostgreSql.sql
index 091c5958b6..2a01af8c79 100644
--- a/src/Service.Tests/DatabaseSchema-PostgreSql.sql
+++ b/src/Service.Tests/DatabaseSchema-PostgreSql.sql
@@ -326,7 +326,7 @@ INSERT INTO type_table(id, short_types, int_types, long_types, string_types, sin
(1, 1, 1, 1, '', 0.33, 0.33, 0.333333, true, '1999-01-08 10:23:54', '\xABCDEF0123'),
(2, -1, -1, -1, 'lksa;jdflasdf;alsdflksdfkldj', -9.2, -9.2, -9.292929, false, '19990108 10:23:00', '\x98AB7511AABB1234'),
(3, -32768, -2147483648, -9223372036854775808, '', -3.4E38, -1.7E308, 2.929292E-19, true, '1753-01-01 00:00:00.000', '\x00000000'),
- (4, 32767, 2147483647, 9223372036854775807, 'null', 3.4E38, 1.7E308, 2.929292E-14, true, '9998-12-31 23:59:59.997', '\xFFFFFFFF'),
+ (4, 32767, 2147483647, 9223372036854775807, 'null', 3.4E38, 1.7E308, 2.929292E-14, true, '9999-12-31 23:59:59.997', '\xFFFFFFFF'),
(5, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO trees("treeId", species, region, height) VALUES (1, 'Tsuga terophylla', 'Pacific Northwest', '30m'), (2, 'Pseudotsuga menziesii', 'Pacific Northwest', '40m');
INSERT INTO fungi(speciesid, region) VALUES (1, 'northeast'), (2, 'southwest');
diff --git a/src/Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs b/src/Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs
index fb51f0fd5e..fb0f8180ad 100644
--- a/src/Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs
+++ b/src/Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs
@@ -230,6 +230,7 @@ public void MultipleColumnsAllMapped()
[DataRow(typeof(DateTimeOffset), DATETIME_TYPE)]
[DataRow(typeof(byte[]), BYTEARRAY_TYPE)]
[DataRow(typeof(Guid), STRING_TYPE)]
+ [DataRow(typeof(TimeOnly), LOCALTIME_TYPE)]
public void SystemTypeMapsToCorrectGraphQLType(Type systemType, string graphQLType)
{
SourceDefinition table = new();
diff --git a/src/Service.Tests/GraphQLBuilder/Sql/StoredProcedureBuilderTests.cs b/src/Service.Tests/GraphQLBuilder/Sql/StoredProcedureBuilderTests.cs
index b758fdf829..be33d35d58 100644
--- a/src/Service.Tests/GraphQLBuilder/Sql/StoredProcedureBuilderTests.cs
+++ b/src/Service.Tests/GraphQLBuilder/Sql/StoredProcedureBuilderTests.cs
@@ -54,6 +54,7 @@ public class StoredProcedureBuilderTests
[DataRow(typeof(DateTime), DATETIME_TYPE, "12/31/2030 12:00:00 AM", false, DisplayName = "DateTime")]
[DataRow(typeof(DateTime), DATETIME_TYPE, "12/31/2030 12000 AM", true, DisplayName = "DateTime")]
[DataRow(typeof(DateTimeOffset), DATETIME_TYPE, "11/19/2012 10:57:11 AM -08:00", false, DisplayName = "DateTimeOffset")]
+ [DataRow(typeof(TimeOnly), LOCALTIME_TYPE, "10:57:11.0000", false, DisplayName = "LocalTime")]
[DataRow(typeof(byte[]), BYTEARRAY_TYPE, "AgQGCAoMDhASFA==", false, DisplayName = "Byte[]")]
public void StoredProcedure_ParameterValueTypeResolution(
Type systemType,
diff --git a/src/Service.Tests/OpenApiDocumentor/CLRtoJsonValueTypeUnitTests.cs b/src/Service.Tests/OpenApiDocumentor/CLRtoJsonValueTypeUnitTests.cs
index 7d497ed8ca..b5964a04d2 100644
--- a/src/Service.Tests/OpenApiDocumentor/CLRtoJsonValueTypeUnitTests.cs
+++ b/src/Service.Tests/OpenApiDocumentor/CLRtoJsonValueTypeUnitTests.cs
@@ -75,8 +75,8 @@ private static IEnumerable