├── gel.toml ├── tools ├── Gel.DotnetTool │ ├── gel.toml │ ├── ICommand.cs │ ├── Schemas │ │ ├── Models │ │ │ ├── Constraint.cs │ │ │ ├── Module.cs │ │ │ ├── Annotation.cs │ │ │ ├── Type.cs │ │ │ └── Property.cs │ │ └── ClassBuilderContext.cs │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Lexer │ │ ├── Token.cs │ │ └── TokenType.cs │ ├── Gel.DotnetTool.csproj │ └── Util │ │ └── CodeWriter.cs ├── Gel.DocGenerator │ ├── Properties │ │ └── launchSettings.json │ ├── Gel.DocGenerator.csproj │ └── Extensions │ │ └── TypeExtensions.cs ├── Gel.QueryBuilder.OperatorGenerator │ ├── Models │ │ ├── EdgeQLFunction.cs │ │ └── EdgeQLOperator.cs │ └── Gel.QueryBuilder.OperatorGenerator.csproj └── Gel.BinaryDebugger │ ├── Gel.BinaryDebugger.csproj │ └── Program.cs ├── branding ├── Banner.png └── PackageLogo.png ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── workflows │ ├── tests.yml │ ├── deploy-prerelease.yml │ ├── deploy-release.yml │ └── build-docs.yml ├── src └── Gel.Net.Driver │ ├── Binary │ ├── Codecs │ │ ├── Impl │ │ │ ├── ICacheableCodec.cs │ │ │ ├── ITemporalCodec.cs │ │ │ ├── ICompiledCodec.cs │ │ │ ├── IScalarCodec.cs │ │ │ ├── IWrappingCodec.cs │ │ │ ├── BaseScalarCodec.cs │ │ │ ├── IArgumentCodec.cs │ │ │ ├── IComplexCodec.cs │ │ │ ├── BaseTemporalCodec.cs │ │ │ ├── BaseArgumentCodec.cs │ │ │ ├── ICodec.cs │ │ │ ├── BaseCodec.cs │ │ │ └── BaseComplexScalarCodec.cs │ │ ├── Shared │ │ │ ├── Dimension.cs │ │ │ ├── NumericSign.cs │ │ │ └── Element.cs │ │ ├── ArgumentCodecContext.cs │ │ ├── Visitors │ │ │ └── CodecVisitor.cs │ │ ├── CodecContext.cs │ │ ├── UUIDCodec.cs │ │ ├── BoolCodec.cs │ │ ├── Integer32Codec.cs │ │ ├── Float32Codec.cs │ │ ├── Float64Codec.cs │ │ ├── Integer16Codec.cs │ │ ├── Integer64Codec.cs │ │ ├── MemoryCodec.cs │ │ ├── BytesCodec.cs │ │ ├── CompoundCodec.cs │ │ ├── TextCodec.cs │ │ ├── NullCodec.cs │ │ ├── Temporal │ │ │ ├── LocalDateCodec.cs │ │ │ ├── DurationCodec.cs │ │ │ ├── DateDurationCodec.cs │ │ │ ├── LocalTimeCodec.cs │ │ │ ├── RelativeDurationCodec.cs │ │ │ ├── DateTimeCodec.cs │ │ │ └── LocalDateTimeCodec.cs │ │ ├── JsonCodec.cs │ │ └── EnumerationCodec.cs │ ├── Protocol │ │ ├── ProtocolPhase.cs │ │ ├── Common │ │ │ ├── Descriptors │ │ │ │ ├── ShapeElementFlags.cs │ │ │ │ ├── TypeOperation.cs │ │ │ │ ├── TupleElement.cs │ │ │ │ └── CodecMetadata.cs │ │ │ ├── IProtocolError.cs │ │ │ └── PacketHeader.cs │ │ ├── IReceiveable.cs │ │ ├── V1.0 │ │ │ ├── Sendables │ │ │ │ ├── Sync.cs │ │ │ │ ├── Terminate.cs │ │ │ │ ├── RestoreEOF.cs │ │ │ │ ├── Dump.cs │ │ │ │ ├── RestoreBlock.cs │ │ │ │ ├── Restore.cs │ │ │ │ ├── AuthenticationSASLResponse.cs │ │ │ │ ├── AuthenticationSASLInitialResponse.cs │ │ │ │ └── ClientHandshake.cs │ │ │ ├── Descriptors │ │ │ │ ├── BaseScalarTypeDescriptor.cs │ │ │ │ ├── DescriptorType.cs │ │ │ │ ├── SetDescriptor.cs │ │ │ │ ├── RangeTypeDescriptor.cs │ │ │ │ ├── ScalarTypeDescriptor.cs │ │ │ │ ├── ScalarTypeNameAnnotation.cs │ │ │ │ ├── ShapeElement.cs │ │ │ │ ├── TypeAnnotationDescriptor.cs │ │ │ │ ├── EnumerationTypeDescriptor.cs │ │ │ │ ├── InputShapeDescriptor.cs │ │ │ │ ├── ObjectShapeDescriptor.cs │ │ │ │ ├── NamedTupleTypeDescriptor.cs │ │ │ │ ├── ArrayTypeDescriptor.cs │ │ │ │ └── TupleTypeDescriptor.cs │ │ │ └── Receivables │ │ │ │ ├── StateDataDescription.cs │ │ │ │ ├── ServerKeyData.cs │ │ │ │ ├── AuthStatus.cs │ │ │ │ ├── ParameterStatus.cs │ │ │ │ ├── RestoreReady.cs │ │ │ │ ├── ReadyForCommand.cs │ │ │ │ ├── Data.cs │ │ │ │ ├── LogMessage.cs │ │ │ │ ├── CommandComplete.cs │ │ │ │ ├── ServerHandshake.cs │ │ │ │ └── DumpBlock.cs │ │ ├── ITypeDescriptor.cs │ │ ├── ExecuteResult.cs │ │ ├── V2.0 │ │ │ └── Descriptors │ │ │ │ ├── DescriptorType.cs │ │ │ │ ├── SetDescriptor.cs │ │ │ │ ├── ShapeElement.cs │ │ │ │ ├── TypeAnnotationTextDescriptor.cs │ │ │ │ ├── IMetadataDescriptor.cs │ │ │ │ ├── InputShapeDescriptor.cs │ │ │ │ ├── ObjectTypeDescriptor.cs │ │ │ │ ├── ObjectOutputShapeDescriptor.cs │ │ │ │ ├── ScalarTypeDescriptor.cs │ │ │ │ ├── CompoundTypeDescriptor.cs │ │ │ │ ├── MultiRangeDescriptor.cs │ │ │ │ ├── RangeTypeDescriptor.cs │ │ │ │ ├── TupleTypeDescriptor.cs │ │ │ │ ├── EnumerationTypeDescriptor.cs │ │ │ │ └── NamedTupleTypeDescriptor.cs │ │ ├── ParseResult.cs │ │ ├── ClientMessageTypes.cs │ │ ├── DumpRestore │ │ │ └── V1.0 │ │ │ │ ├── DumpSectionHeader.cs │ │ │ │ └── DumpState.cs │ │ ├── ServerMessageType.cs │ │ ├── QueryParameters.cs │ │ └── Sendable.cs │ ├── Common │ │ ├── MessageSeverity.cs │ │ ├── ConnectionParam.cs │ │ ├── Annotation.cs │ │ ├── KeyValue.cs │ │ └── ProtocolExtension.cs │ └── Builders │ │ ├── Wrappers │ │ ├── NullableWrapper.cs │ │ ├── FSharpOptionWrapper.cs │ │ └── IWrapper.cs │ │ └── Info │ │ └── GelPropertyMapInfo.cs │ ├── Models │ ├── Exceptions │ │ ├── Attributes │ │ │ ├── ShouldRetryAttribute.cs │ │ │ └── ShouldReconnectAttribute.cs │ │ ├── UnexpectedDisconnectException.cs │ │ ├── MissingRequiredException.cs │ │ ├── InvalidSignatureException.cs │ │ ├── CustomClientException.cs │ │ ├── InvalidConnectionException.cs │ │ ├── MissingCodecException.cs │ │ ├── TransactionException.cs │ │ ├── ResultCardinalityMismatchException.cs │ │ ├── ConfigurationException.cs │ │ ├── QueryTimeoutException.cs │ │ ├── ConnectionFailedException.cs │ │ ├── ConnectionFailedTemporarilyException.cs │ │ ├── UnexpectedMessageException.cs │ │ └── NoTypeConverterException.cs │ ├── CloudProfile.cs │ ├── ConnectionRetryMode.cs │ ├── TransactionState.cs │ ├── DataTypes │ │ ├── Memory.cs │ │ └── Json.cs │ ├── ErrorSeverity.cs │ ├── IOFormat.cs │ ├── Cardinality.cs │ ├── Isolation.cs │ └── Capabilities.cs │ ├── Utils │ ├── Ref.cs │ ├── HexConverter.cs │ ├── JsonUtils.cs │ └── ReflectionUtils.cs │ ├── Attributes │ ├── GelDeserializerAttribute.cs │ ├── GelIgnoreAttribute.cs │ ├── GelTypeAttribute.cs │ ├── GelPropertyAttribute.cs │ └── GelTypeConverterAttribute.cs │ ├── NamingStrategies │ ├── DefaultNamingStrategy.cs │ ├── AttributeNamingStrategy.cs │ ├── CamelCaseNamingStrategy.cs │ ├── PascalNamingStrategy.cs │ └── SnakeCaseNamingStrategy.cs │ ├── Extensions │ ├── ConnectionExtensions.cs │ ├── JsonSerializerExtensions.cs │ ├── ReceivableExtensions.cs │ └── GelHostingExtensions.cs │ ├── AssemblyInfo.cs │ ├── ContractResolvers │ └── JsonContractResolver.cs │ └── Gel.Net.Driver.csproj ├── tests ├── Gel.Tests.Benchmarks │ ├── CodecVisitorBenchmarks.cs │ ├── Program.cs │ ├── Gel.Tests.Benchmarks.csproj │ ├── FullExecuteBenchmark.cs │ ├── PacketWritingBenchmark.cs │ └── ClientPoolBenchmarks.cs ├── Gel.Tests.Integration │ ├── HttpClientTests.cs │ ├── Gel.Tests.Integration.csproj │ ├── ClientProvider.cs │ ├── Extensions │ │ ├── TemporalExtensions.cs │ │ └── IEnumerableExtensions.cs │ └── ErrorFormatTests.cs └── Gel.Tests.Unit │ ├── Gel.Tests.Unit.csproj │ └── SCRAMTests.cs ├── .gitmodules ├── examples ├── Gel.Examples.ExampleTODOApi │ ├── appsettings.Development.json │ ├── appsettings.json │ ├── Gel.Examples.ExampleTODOApi.csproj │ ├── Program.cs │ ├── TODOModel.cs │ └── Properties │ │ └── launchSettings.json ├── Gel.Examples.FSharp │ ├── IExample.fs │ ├── Examples │ │ ├── CancelQueries.fs │ │ └── AbstractTypes.fs │ ├── Program.fs │ ├── Gel.Examples.FSharp.fsproj │ └── ExampleRunner.fs └── Gel.Examples.CSharp │ ├── Examples │ ├── Range.cs │ ├── Records.cs │ ├── GlobalsAndConfig.cs │ ├── CancelQueries.cs │ ├── JsonResults.cs │ ├── Transactions.cs │ └── DumpAndRestore.cs │ ├── ExampleRunner.cs │ ├── Gel.Examples.CSharp.csproj │ ├── Program.cs │ └── IExample.cs ├── dbschema ├── migrations │ ├── 00009.edgeql │ ├── 00012.edgeql │ ├── 00001.edgeql │ ├── 00002.edgeql │ ├── 00004.edgeql │ ├── 00008.edgeql │ ├── 00006.edgeql │ ├── 00011.edgeql │ ├── 00010.edgeql │ ├── 00005.edgeql │ ├── 00007.edgeql │ ├── 00003.edgeql │ └── 00013.edgeql ├── tests.esdl └── default.esdl └── Gel.Net.targets /gel.toml: -------------------------------------------------------------------------------- 1 | [gel] 2 | server-version = "nightly" 3 | -------------------------------------------------------------------------------- /tools/Gel.DotnetTool/gel.toml: -------------------------------------------------------------------------------- 1 | [gel] 2 | server-version = "1.1" 3 | -------------------------------------------------------------------------------- /branding/Banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geldata/gel-net/HEAD/branding/Banner.png -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [quinchs] 4 | -------------------------------------------------------------------------------- /branding/PackageLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geldata/gel-net/HEAD/branding/PackageLogo.png -------------------------------------------------------------------------------- /tools/Gel.DotnetTool/ICommand.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.DotnetTool; 2 | 3 | internal interface ICommand 4 | { 5 | void Execute(); 6 | } 7 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Impl/ICacheableCodec.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Codecs; 2 | 3 | internal interface ICacheableCodec 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /tests/Gel.Tests.Benchmarks/CodecVisitorBenchmarks.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Tests.Benchmarks; 2 | 3 | public class CodecVisitorBenchmarks 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /tests/Gel.Tests.Benchmarks/Program.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Running; 2 | using Gel.Tests.Benchmarks; 3 | 4 | BenchmarkRunner.Run(); 5 | 6 | await Task.Delay(-1); 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "tests/Gel.Tests.Unit/shared-client-testcases"] 2 | path = tests/Gel.Tests.Unit/shared-client-testcases 3 | url = https://github.com/geldata/shared-client-testcases.git 4 | -------------------------------------------------------------------------------- /tools/Gel.DocGenerator/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Gel.DocGenerator": { 4 | "commandName": "Project", 5 | "commandLineArgs": "." 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/Exceptions/Attributes/ShouldRetryAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | [AttributeUsage(AttributeTargets.Field)] 4 | internal sealed class ShouldRetryAttribute : Attribute 5 | { 6 | } 7 | -------------------------------------------------------------------------------- /examples/Gel.Examples.ExampleTODOApi/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/Exceptions/Attributes/ShouldReconnectAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | [AttributeUsage(AttributeTargets.Field)] 4 | internal sealed class ShouldReconnectAttribute : Attribute 5 | { 6 | } 7 | -------------------------------------------------------------------------------- /tools/Gel.DotnetTool/Schemas/Models/Constraint.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.DotnetTool; 2 | 3 | internal class Constraint 4 | { 5 | public string? Value { get; set; } 6 | 7 | public bool IsExpression { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /tools/Gel.DotnetTool/Schemas/Models/Module.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.DotnetTool; 2 | 3 | internal class Module 4 | { 5 | public string? Name { get; set; } 6 | 7 | public List Types { get; set; } = new(); 8 | } 9 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Shared/Dimension.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Codecs; 2 | 3 | internal readonly struct Dimension 4 | { 5 | public int Upper { get; init; } 6 | 7 | public int Lower { get; init; } 8 | } 9 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/CloudProfile.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Gel.Models; 4 | 5 | internal sealed class CloudProfile 6 | { 7 | [JsonProperty("secret_key")] public string? SecretKey { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Impl/ITemporalCodec.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Codecs; 2 | 3 | internal interface ITemporalCodec : IComplexCodec 4 | { 5 | Type ModelType { get; } 6 | IEnumerable SystemTypes { get; } 7 | } 8 | -------------------------------------------------------------------------------- /examples/Gel.Examples.ExampleTODOApi/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /dbschema/migrations/00009.edgeql: -------------------------------------------------------------------------------- 1 | CREATE MIGRATION m1yp62tfavybznmg6ywpi7xkbf77ue7ezaubpye7btyv2pco4okf7q 2 | ONTO m1isiclyxqa32luj6hdazr4mft2mvvq4tmmuoygl7m7k2iimxm5y3a 3 | { 4 | CREATE GLOBAL default::current_user_id -> std::uuid; 5 | }; 6 | -------------------------------------------------------------------------------- /examples/Gel.Examples.FSharp/IExample.fs: -------------------------------------------------------------------------------- 1 | namespace Examples 2 | 3 | open Microsoft.Extensions.Logging 4 | 5 | type IExample = 6 | abstract member ExecuteAsync: clientPool: Gel.GelClientPool * logger: ILogger -> System.Threading.Tasks.Task 7 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Impl/ICompiledCodec.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Codecs; 2 | 3 | internal interface ICompiledCodec : ICodec, IWrappingCodec 4 | { 5 | Type CompiledFrom { get; } 6 | CompilableWrappingCodec Template { get; } 7 | } 8 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/ProtocolPhase.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol; 2 | 3 | internal enum ProtocolPhase 4 | { 5 | Connection, 6 | Auth, 7 | Command, 8 | Dump, 9 | Termination, 10 | Errored 11 | } 12 | -------------------------------------------------------------------------------- /dbschema/migrations/00012.edgeql: -------------------------------------------------------------------------------- 1 | CREATE MIGRATION m1qobo3k5z5dg56j3vymsaktqjnff5uv4ndpytjpqfwkda7lxinllq 2 | ONTO m1cpqrhf5f5vdvux4bsgtljnq2sicll7vz4sfmjmztr5ilwgymzc5a 3 | { 4 | CREATE GLOBAL default::abc -> tuple; 5 | }; 6 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Impl/IScalarCodec.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Codecs; 2 | 3 | internal interface IScalarCodec : ICodec, IScalarCodec 4 | { 5 | } 6 | 7 | internal interface IScalarCodec : ICodec, ICacheableCodec 8 | { 9 | } 10 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Shared/NumericSign.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Codecs; 2 | 3 | internal enum NumericSign : ushort 4 | { 5 | // Positive value. 6 | POS = 0x0000, 7 | 8 | // Negative value. 9 | NEG = 0x4000 10 | } 11 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/Common/Descriptors/ShapeElementFlags.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | internal enum ShapeElementFlags : uint 4 | { 5 | Implicit = 1 << 0, 6 | LinkProperty = 1 << 1, 7 | Link = 1 << 2 8 | } 9 | -------------------------------------------------------------------------------- /dbschema/migrations/00001.edgeql: -------------------------------------------------------------------------------- 1 | CREATE MIGRATION m1gajj2cjvikxjfhwnczhcfrcdlycg5pbg7vvehuaohazd2ltajlnq 2 | ONTO initial 3 | { 4 | CREATE TYPE default::Person { 5 | CREATE PROPERTY email -> std::str; 6 | CREATE PROPERTY name -> std::str; 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/Common/Descriptors/TypeOperation.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | internal enum TypeOperation : byte 4 | { 5 | // Foo | Bar 6 | Union = 1, 7 | 8 | // Foo & Bar 9 | Intersection = 2 10 | } 11 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Shared/Element.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Codecs; 2 | 3 | internal readonly struct Element 4 | { 5 | public int Reserved { get; init; } 6 | 7 | public int Length { get; init; } 8 | 9 | public byte[] Data { get; init; } 10 | } 11 | -------------------------------------------------------------------------------- /tools/Gel.DotnetTool/Schemas/Models/Annotation.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.DotnetTool; 2 | 3 | internal class Annotation 4 | { 5 | public string? Title { get; set; } 6 | 7 | public string? Description { get; set; } 8 | 9 | public string? Deprecated { get; set; } 10 | } 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest a feature for Gel.Net 4 | 5 | --- 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Impl/IWrappingCodec.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Codecs; 2 | 3 | internal interface IWrappingCodec 4 | { 5 | ICodec InnerCodec { get; set; } 6 | } 7 | 8 | internal interface IMultiWrappingCodec 9 | { 10 | ICodec[] InnerCodecs { get; set; } 11 | } 12 | -------------------------------------------------------------------------------- /tools/Gel.DotnetTool/Program.cs: -------------------------------------------------------------------------------- 1 | using CommandLine; 2 | using Gel.DotnetTool; 3 | 4 | var commands = typeof(Program).Assembly.GetTypes().Where(x => x.GetInterfaces().Any(x => x == typeof(ICommand))); 5 | 6 | Parser.Default.ParseArguments(args, commands.ToArray()).WithParsed(t => t.Execute()); 7 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Common/MessageSeverity.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | /// 4 | /// Represents the log message severity 5 | /// 6 | internal enum MessageSeverity : byte 7 | { 8 | Debug = 0x14, 9 | Info = 0x28, 10 | Notice = 0x3c, 11 | Warning = 0x50 12 | } 13 | -------------------------------------------------------------------------------- /dbschema/migrations/00002.edgeql: -------------------------------------------------------------------------------- 1 | CREATE MIGRATION m1vqxxs4ie4so3x35nk2wyu3jy3hmolscpyxu6bccucaofjtnrtj3a 2 | ONTO m1gajj2cjvikxjfhwnczhcfrcdlycg5pbg7vvehuaohazd2ltajlnq 3 | { 4 | ALTER TYPE default::Person { 5 | ALTER PROPERTY email { 6 | CREATE CONSTRAINT std::exclusive; 7 | }; 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /dbschema/migrations/00004.edgeql: -------------------------------------------------------------------------------- 1 | CREATE MIGRATION m1xp6ukrooc4chjfnhmaky4ywsoip5wvbz4ffm36tsqosspiyqjy6q 2 | ONTO m1tpouzupcrd2nkhl45qsdykw3dzjbk4ecndr73tmatxskaxkixu3q 3 | { 4 | ALTER TYPE default::Movie { 5 | ALTER PROPERTY title { 6 | CREATE CONSTRAINT std::exclusive; 7 | }; 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /dbschema/migrations/00008.edgeql: -------------------------------------------------------------------------------- 1 | CREATE MIGRATION m1isiclyxqa32luj6hdazr4mft2mvvq4tmmuoygl7m7k2iimxm5y3a 2 | ONTO m1dntdma2rrziv35tbt7mfl7qeg3wpzaqk73edwaw5i4kkz5fg6z6a 3 | { 4 | ALTER TYPE default::AbstractThing { 5 | ALTER PROPERTY name { 6 | CREATE CONSTRAINT std::exclusive; 7 | }; 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Utils/Ref.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Utils; 2 | 3 | internal sealed class Ref(T value) 4 | where T : class 5 | { 6 | public T Value { get; set; } = value; 7 | 8 | public static implicit operator Ref(T value) => new(value); 9 | public static implicit operator T(Ref reference) => reference.Value; 10 | } 11 | -------------------------------------------------------------------------------- /dbschema/migrations/00006.edgeql: -------------------------------------------------------------------------------- 1 | CREATE MIGRATION m1bthirxb7a7lq7mjtrdjsxdcjcy4or3tlprzh74azy44h7n3re6zq 2 | ONTO m1rgfzvgm77nvwkjt5i4hw3ruxtxoed4osu2hv7uj6huagohxxuu2q 3 | { 4 | ALTER TYPE default::TODO { 5 | ALTER PROPERTY date_created { 6 | SET default := (std::datetime_current()); 7 | }; 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /dbschema/migrations/00011.edgeql: -------------------------------------------------------------------------------- 1 | CREATE MIGRATION m1cpqrhf5f5vdvux4bsgtljnq2sicll7vz4sfmjmztr5ilwgymzc5a 2 | ONTO m1wuplszy5bldaagiqypo6nsdwikppnvhtmkosmksmkl3eipujwloq 3 | { 4 | ALTER TYPE default::UserWithSnowflakeId { 5 | ALTER PROPERTY user_id { 6 | CREATE CONSTRAINT std::exclusive; 7 | }; 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/Common/IProtocolError.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.Common; 2 | 3 | internal interface IProtocolError 4 | { 5 | ErrorSeverity Severity { get; } 6 | ServerErrorCodes ErrorCode { get; } 7 | string Message { get; } 8 | 9 | bool TryGetAttribute(in ushort code, out KeyValue kv); 10 | } 11 | -------------------------------------------------------------------------------- /tools/Gel.DotnetTool/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Gel.DotnetTool": { 4 | "commandName": "Project", 5 | "commandLineArgs": "generate -f C:\\Users\\lynch\\source\\repos\\Gel\\src\\Gel.DotnetTool\\test.esdl -v" 6 | }, 7 | "Profile 1": { 8 | "commandName": "Executable" 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /dbschema/migrations/00010.edgeql: -------------------------------------------------------------------------------- 1 | CREATE MIGRATION m1wuplszy5bldaagiqypo6nsdwikppnvhtmkosmksmkl3eipujwloq 2 | ONTO m1yp62tfavybznmg6ywpi7xkbf77ue7ezaubpye7btyv2pco4okf7q 3 | { 4 | CREATE TYPE default::UserWithSnowflakeId { 5 | CREATE REQUIRED PROPERTY user_id -> std::str; 6 | CREATE REQUIRED PROPERTY username -> std::str; 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Attributes/GelDeserializerAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | /// 4 | /// Marks the current method as the method to use to deserialize the current type. 5 | /// 6 | [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor)] 7 | public class GelDeserializerAttribute : Attribute 8 | { 9 | } 10 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/NamingStrategies/DefaultNamingStrategy.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace Gel; 4 | 5 | internal sealed class DefaultNamingStrategy : INamingStrategy 6 | { 7 | public string Convert(PropertyInfo property) 8 | => property.Name; 9 | 10 | public string Convert(string name) 11 | => name; 12 | } 13 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/ArgumentCodecContext.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Codecs; 2 | 3 | internal sealed class ArgumentCodecContext : CodecContext 4 | { 5 | public readonly ICodec[] Codecs; 6 | 7 | public ArgumentCodecContext(ICodec[] codecs, GelBinaryClient client) 8 | : base(client) 9 | { 10 | Codecs = codecs; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Impl/BaseScalarCodec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Codecs; 4 | 5 | internal abstract class BaseScalarCodec 6 | : BaseCodec, IScalarCodec 7 | { 8 | protected BaseScalarCodec(in Guid id, CodecMetadata? metadata) 9 | : base(in id, metadata) 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/IReceiveable.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol; 2 | 3 | /// 4 | /// Represents a generic packet received from the server. 5 | /// 6 | internal interface IReceiveable 7 | { 8 | /// 9 | /// Gets the type of the message. 10 | /// 11 | ServerMessageType Type { get; } 12 | } 13 | -------------------------------------------------------------------------------- /tools/Gel.QueryBuilder.OperatorGenerator/Models/EdgeQLFunction.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.QueryBuilder.OperatorGenerator; 2 | 3 | public class EdgeQLFunction 4 | { 5 | public string? Name { get; set; } 6 | 7 | public List Parameters { get; set; } = new(); 8 | 9 | public string? Return { get; set; } 10 | 11 | public string? Filter { get; set; } 12 | } 13 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Visitors/CodecVisitor.cs: -------------------------------------------------------------------------------- 1 | using Gel.Utils; 2 | 3 | namespace Gel.Binary.Codecs; 4 | 5 | internal abstract class CodecVisitor 6 | { 7 | public Task VisitAsync(Ref codec, CancellationToken token) => VisitCodecAsync(codec, token); 8 | 9 | protected abstract Task VisitCodecAsync(Ref codec, CancellationToken token); 10 | } 11 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Sendables/Sync.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Packets; 2 | 3 | internal sealed class Sync : Sendable 4 | { 5 | public override int Size => 0; 6 | 7 | public override ClientMessageTypes Type 8 | => ClientMessageTypes.Sync; 9 | 10 | protected override void BuildPacket(ref PacketWriter writer) { } // no data 11 | } 12 | -------------------------------------------------------------------------------- /tools/Gel.DotnetTool/Lexer/Token.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.DotnetTool.Lexer; 2 | 3 | internal class Token 4 | { 5 | public TokenType Type { get; set; } 6 | 7 | public string? Value { get; set; } 8 | 9 | public int StartPos { get; set; } 10 | 11 | public int StartLine { get; set; } 12 | 13 | public int EndPos { get; set; } 14 | 15 | public int EndLine { get; set; } 16 | } 17 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/ITypeDescriptor.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary; 2 | 3 | internal interface ITypeDescriptor 4 | { 5 | /// 6 | /// Lifetime of this ref field is dangerous, no scope hints are attached to the ref so make sure 7 | /// that this field is only used inscope of the reference. 8 | /// 9 | ref readonly Guid Id { get; } 10 | } 11 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Sendables/Terminate.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Packets; 2 | 3 | internal sealed class Terminate : Sendable 4 | { 5 | public override int Size => 0; 6 | 7 | public override ClientMessageTypes Type 8 | => ClientMessageTypes.Terminate; 9 | 10 | protected override void BuildPacket(ref PacketWriter writer) { } // no data 11 | } 12 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/NamingStrategies/AttributeNamingStrategy.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace Gel; 4 | 5 | internal sealed class AttributeNamingStrategy : INamingStrategy 6 | { 7 | public string Convert(PropertyInfo property) => 8 | property.GetCustomAttribute()?.Name ?? property.Name; 9 | 10 | public string Convert(string name) => name; 11 | } 12 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Attributes/GelIgnoreAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | /// 4 | /// Marks the current target to be ignored when deserializing or building queries. 5 | /// 6 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | 7 | AttributeTargets.Constructor)] 8 | public class GelIgnoreAttribute : Attribute 9 | { 10 | } 11 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/ExecuteResult.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol; 2 | 3 | internal class ExecuteResult 4 | { 5 | public ExecuteResult(ReadOnlyMemory[] data, CodecInfo outCodecInfo) 6 | { 7 | Data = data; 8 | OutCodecInfo = outCodecInfo; 9 | } 10 | 11 | public CodecInfo OutCodecInfo { get; } 12 | public ReadOnlyMemory[] Data { get; } 13 | } 14 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Impl/IArgumentCodec.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Codecs; 2 | 3 | internal interface IArgumentCodec : IArgumentCodec, ICodec 4 | { 5 | void SerializeArguments(ref PacketWriter writer, T? value, ArgumentCodecContext context); 6 | } 7 | 8 | internal interface IArgumentCodec 9 | { 10 | void SerializeArguments(ref PacketWriter writer, object? value, ArgumentCodecContext context); 11 | } 12 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/Exceptions/UnexpectedDisconnectException.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | /// 4 | /// Represents an exception that was caused by an unexpected disconnection from Gel. 5 | /// 6 | public class UnexpectedDisconnectException : GelException 7 | { 8 | internal UnexpectedDisconnectException() 9 | : base("The connection was unexpectedly closed") 10 | { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/NamingStrategies/CamelCaseNamingStrategy.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace Gel; 4 | 5 | internal sealed class CamelCaseNamingStrategy : INamingStrategy 6 | { 7 | public string Convert(PropertyInfo property) 8 | => Convert(property.Name); 9 | 10 | public string Convert(string name) 11 | => $"{char.ToLowerInvariant(name[0])}{name[1..].Replace("_", string.Empty)}"; 12 | } 13 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/Common/Descriptors/TupleElement.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | internal readonly struct TupleElement 4 | { 5 | public readonly string Name; 6 | 7 | public readonly short TypePos; 8 | 9 | public TupleElement(scoped ref PacketReader reader) 10 | { 11 | Name = reader.ReadString(); 12 | TypePos = reader.ReadInt16(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Sendables/RestoreEOF.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Packets; 2 | 3 | internal sealed class RestoreEOF : Sendable 4 | { 5 | public override int Size => 0; 6 | 7 | public override ClientMessageTypes Type 8 | => ClientMessageTypes.RestoreEOF; 9 | 10 | protected override void BuildPacket(ref PacketWriter writer) 11 | { 12 | // write nothing 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/Gel.Examples.CSharp/Examples/Range.cs: -------------------------------------------------------------------------------- 1 | using Gel.DataTypes; 2 | using Microsoft.Extensions.Logging; 3 | 4 | namespace Gel.ExampleApp.Examples; 5 | 6 | internal class RangeExample : IExample 7 | { 8 | public ILogger? Logger { get; set; } 9 | 10 | public async Task ExecuteAsync(GelClientPool clientPool) 11 | { 12 | var range = await clientPool.QuerySingleAsync>("select range(1, 10)"); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tools/Gel.BinaryDebugger/Gel.BinaryDebugger.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V2.0/Descriptors/DescriptorType.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V2._0.Descriptors; 2 | 3 | internal enum DescriptorType : byte 4 | { 5 | Set = 0, 6 | ObjectOutput = 1, 7 | Scalar = 3, 8 | Tuple = 4, 9 | NamedTuple = 5, 10 | Array = 6, 11 | Enumeration = 7, 12 | Input = 8, 13 | Range = 9, 14 | Object = 10, 15 | Compound = 11, 16 | MultiRange = 12, 17 | TypeAnnotationText = 127 18 | } 19 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Impl/IComplexCodec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol; 2 | 3 | namespace Gel.Binary.Codecs; 4 | 5 | internal interface IComplexCodec : ICodec 6 | { 7 | IEnumerable RuntimeCodecs { get; } 8 | 9 | void BuildRuntimeCodecs(IProtocolProvider provider); 10 | 11 | ICodec GetCodecFor(IProtocolProvider provider, Type type); 12 | } 13 | 14 | internal interface IRuntimeCodec : ICodec 15 | { 16 | IComplexCodec Broker { get; } 17 | } 18 | -------------------------------------------------------------------------------- /dbschema/tests.esdl: -------------------------------------------------------------------------------- 1 | module tests { 2 | type ScalarContainer { 3 | a: int16; 4 | b: int32; 5 | c: int64; 6 | d: str; 7 | e: bool; 8 | f: float32; 9 | g: float64; 10 | h: bigint; 11 | i: decimal; 12 | j: uuid; 13 | k: json; 14 | l: datetime; 15 | m: cal::local_datetime; 16 | n: cal::local_date; 17 | o: cal::local_time; 18 | p: duration; 19 | q: cal::relative_duration; 20 | r: cal::date_duration; 21 | s: bytes; 22 | } 23 | } -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Common/ConnectionParam.cs: -------------------------------------------------------------------------------- 1 | using Gel.Utils; 2 | 3 | namespace Gel.Binary; 4 | 5 | internal readonly struct ConnectionParam 6 | { 7 | public int Size 8 | => BinaryUtils.SizeOfString(Name) + BinaryUtils.SizeOfString(Value); 9 | 10 | public string Name { get; init; } 11 | 12 | public string? Value { get; init; } 13 | 14 | public void Write(ref PacketWriter writer) 15 | { 16 | writer.Write(Name); 17 | writer.Write(Value); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/Exceptions/MissingRequiredException.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | /// 4 | /// Represents an exception that occurs when required data isn't returned. 5 | /// 6 | public class MissingRequiredException : GelException 7 | { 8 | /// 9 | /// Constructs a new . 10 | /// 11 | public MissingRequiredException() 12 | : base("Missing required result from query") 13 | { 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Sendables/Dump.cs: -------------------------------------------------------------------------------- 1 | using Gel.Utils; 2 | 3 | namespace Gel.Binary.Protocol.V1._0.Packets; 4 | 5 | internal sealed class Dump : Sendable 6 | { 7 | public override int Size => BinaryUtils.SizeOfAnnotations(Attributes); 8 | 9 | public override ClientMessageTypes Type 10 | => ClientMessageTypes.Dump; 11 | 12 | public Annotation[]? Attributes { get; set; } 13 | 14 | protected override void BuildPacket(ref PacketWriter writer) => writer.Write(Attributes); 15 | } 16 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Extensions/ConnectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Cryptography.X509Certificates; 2 | using System.Text; 3 | 4 | namespace Gel; 5 | 6 | internal static class ConnectionExtensions 7 | { 8 | public static X509Certificate2? GetCertificate(this GelConnection connection) 9 | { 10 | if (connection.TLSCertificateAuthority is null) 11 | return null; 12 | 13 | return new X509Certificate2(Encoding.ASCII.GetBytes(connection.TLSCertificateAuthority)); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/Exceptions/InvalidSignatureException.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | /// 4 | /// Represents an exception that occurs when the server signature is incorrect. 5 | /// 6 | public class InvalidSignatureException : GelException 7 | { 8 | /// 9 | /// Constructs a new . 10 | /// 11 | public InvalidSignatureException() 12 | : base("The received signature didn't match the expected one") 13 | { 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/CodecContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | 3 | namespace Gel.Binary.Codecs; 4 | 5 | internal class CodecContext 6 | { 7 | public CodecContext(GelBinaryClient client) 8 | { 9 | Client = client; 10 | } 11 | 12 | public GelBinaryClient Client { get; } 13 | 14 | public ILogger Logger 15 | => Client.Logger; 16 | 17 | public GelClientConfig Config 18 | => Client.ClientConfig; 19 | 20 | public TypeVisitor CreateTypeVisitor() => new(Client); 21 | } 22 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/ParseResult.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol; 2 | 3 | internal sealed class ParseResult 4 | { 5 | public ParseResult(CodecInfo inCodecInfo, CodecInfo outCodecInfo, scoped in ReadOnlyMemory? stateData) 6 | { 7 | InCodecInfo = inCodecInfo; 8 | OutCodecInfo = outCodecInfo; 9 | StateData = stateData; 10 | } 11 | 12 | public CodecInfo InCodecInfo { get; } 13 | public CodecInfo OutCodecInfo { get; } 14 | public ReadOnlyMemory? StateData { get; } 15 | } 16 | -------------------------------------------------------------------------------- /examples/Gel.Examples.CSharp/Examples/Records.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | 3 | namespace Gel.ExampleApp.Examples; 4 | 5 | internal class Records : IExample 6 | { 7 | public ILogger? Logger { get; set; } 8 | 9 | public async Task ExecuteAsync(GelClientPool clientPool) 10 | { 11 | var people = await clientPool.QueryAsync("select Person { name, email }"); 12 | 13 | Logger!.LogInformation("People: {@People}", people); 14 | } 15 | 16 | public record Person(string Name, string Email); 17 | } 18 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/ClientMessageTypes.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary; 2 | 3 | internal enum ClientMessageTypes : sbyte 4 | { 5 | AuthenticationSASLInitialResponse = 0x70, 6 | AuthenticationSASLResponse = 0x72, 7 | ClientHandshake = 0x56, 8 | DescribeStatement = 0x44, 9 | Dump = 0x3e, 10 | Execute = 0x4f, 11 | ExecuteScript = 0x51, 12 | Flush = 0x48, 13 | Parse = 0x50, 14 | Restore = 0x3c, 15 | RestoreBlock = 0x3d, 16 | RestoreEOF = 0x2e, 17 | Sync = 0x53, 18 | Terminate = 0x58 19 | } 20 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Sendables/RestoreBlock.cs: -------------------------------------------------------------------------------- 1 | using Gel.Utils; 2 | 3 | namespace Gel.Binary.Protocol.V1._0.Packets; 4 | 5 | internal sealed class RestoreBlock : Sendable 6 | { 7 | public override int Size 8 | => BinaryUtils.SizeOfByteArray(BlockData); 9 | 10 | public override ClientMessageTypes Type 11 | => ClientMessageTypes.RestoreBlock; 12 | 13 | public byte[]? BlockData { get; set; } 14 | 15 | protected override void BuildPacket(ref PacketWriter writer) => writer.WriteArray(BlockData!); 16 | } 17 | -------------------------------------------------------------------------------- /tools/Gel.DotnetTool/Schemas/Models/Type.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.DotnetTool; 2 | 3 | internal class Type 4 | { 5 | public Module? Parent { get; set; } 6 | 7 | public string? Name { get; set; } 8 | 9 | public string? Extending { get; set; } 10 | 11 | public bool IsAbstract { get; set; } 12 | 13 | public bool IsScalar { get; set; } 14 | 15 | public bool IsLink { get; set; } 16 | 17 | public List Properties { get; set; } = new(); 18 | 19 | // used for builder 20 | public string? BuiltName { get; set; } 21 | } 22 | -------------------------------------------------------------------------------- /dbschema/migrations/00005.edgeql: -------------------------------------------------------------------------------- 1 | CREATE MIGRATION m1rgfzvgm77nvwkjt5i4hw3ruxtxoed4osu2hv7uj6huagohxxuu2q 2 | ONTO m1xp6ukrooc4chjfnhmaky4ywsoip5wvbz4ffm36tsqosspiyqjy6q 3 | { 4 | CREATE SCALAR TYPE default::State EXTENDING enum; 5 | CREATE TYPE default::TODO { 6 | CREATE REQUIRED PROPERTY date_created -> std::datetime; 7 | CREATE REQUIRED PROPERTY description -> std::str; 8 | CREATE REQUIRED PROPERTY state -> default::State; 9 | CREATE REQUIRED PROPERTY title -> std::str; 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Descriptors/BaseScalarTypeDescriptor.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Descriptors; 2 | 3 | internal readonly struct BaseScalarTypeDescriptor : ITypeDescriptor 4 | { 5 | public readonly Guid Id; 6 | 7 | public BaseScalarTypeDescriptor(scoped in Guid id) 8 | { 9 | Id = id; 10 | } 11 | 12 | unsafe ref readonly Guid ITypeDescriptor.Id 13 | { 14 | get 15 | { 16 | fixed (Guid* ptr = &Id) 17 | return ref *ptr; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/ConnectionRetryMode.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | /// 4 | /// An enum representing the retry mode when connecting new clients. 5 | /// 6 | public enum ConnectionRetryMode 7 | { 8 | /// 9 | /// The client should retry to connect up to the specified . 10 | /// 11 | AlwaysRetry, 12 | 13 | /// 14 | /// The client should error and not retry to connect. 15 | /// 16 | NeverRetry 17 | } 18 | -------------------------------------------------------------------------------- /tools/Gel.DocGenerator/Gel.DocGenerator.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/Gel.Examples.ExampleTODOApi/Gel.Examples.ExampleTODOApi.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Utils/HexConverter.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Utils; 2 | 3 | internal static class HexConverter 4 | { 5 | public static byte[] FromHex(string hex) 6 | { 7 | hex = hex.Replace("-", ""); 8 | var raw = new byte[hex.Length / 2]; 9 | for (var i = 0; i < raw.Length; i++) 10 | { 11 | raw[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16); 12 | } 13 | 14 | return raw; 15 | } 16 | 17 | public static string ToHex(byte[] arr) 18 | => BitConverter.ToString(arr).Replace("-", ""); 19 | } 20 | -------------------------------------------------------------------------------- /dbschema/migrations/00007.edgeql: -------------------------------------------------------------------------------- 1 | CREATE MIGRATION m1dntdma2rrziv35tbt7mfl7qeg3wpzaqk73edwaw5i4kkz5fg6z6a 2 | ONTO m1bthirxb7a7lq7mjtrdjsxdcjcy4or3tlprzh74azy44h7n3re6zq 3 | { 4 | CREATE ABSTRACT TYPE default::AbstractThing { 5 | CREATE REQUIRED PROPERTY name -> std::str; 6 | }; 7 | CREATE TYPE default::OtherThing EXTENDING default::AbstractThing { 8 | CREATE REQUIRED PROPERTY attribute -> std::str; 9 | }; 10 | CREATE TYPE default::Thing EXTENDING default::AbstractThing { 11 | CREATE REQUIRED PROPERTY description -> std::str; 12 | }; 13 | }; 14 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo("Gel.Net.QueryBuilder")] 4 | [assembly: InternalsVisibleTo("Gel.Runtime")] 5 | [assembly: InternalsVisibleTo("Gel.ExampleApp")] 6 | [assembly: InternalsVisibleTo("Gel.DotnetTool")] 7 | [assembly: InternalsVisibleTo("Gel.Tests.Unit")] 8 | [assembly: InternalsVisibleTo("Gel.Tests.Integration")] 9 | [assembly: InternalsVisibleTo("Gel.Tests.Benchmarks")] 10 | [assembly: InternalsVisibleTo("Gel.BinaryDebugger")] 11 | [assembly: InternalsVisibleTo("Gel.Serializer.Experiments")] 12 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Descriptors/DescriptorType.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Descriptors; 2 | 3 | internal enum DescriptorType : byte 4 | { 5 | SetDescriptor = 0x00, 6 | ObjectShapeDescriptor = 0x01, 7 | BaseScalarTypeDescriptor = 0x02, 8 | ScalarTypeDescriptor = 0x03, 9 | TupleTypeDescriptor = 0x04, 10 | NamedTupleDescriptor = 0x05, 11 | ArrayTypeDescriptor = 0x06, 12 | EnumerationTypeDescriptor = 0x07, 13 | InputShapeDescriptor = 0x08, 14 | RangeTypeDescriptor = 0x09, 15 | ScalarTypeNameAnnotation = 0xff 16 | } 17 | -------------------------------------------------------------------------------- /tools/Gel.DotnetTool/Lexer/TokenType.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.DotnetTool.Lexer; 2 | 3 | internal enum TokenType 4 | { 5 | BeginBrace, 6 | EndBrace, 7 | Required, 8 | Property, 9 | Constraint, 10 | TypeArrow, 11 | Multi, 12 | Link, 13 | Abstract, 14 | Semicolon, 15 | Assignment, 16 | Single, 17 | On, 18 | Extending, 19 | Comma, 20 | BeginParenthesis, 21 | EndParenthesis, 22 | Annotation, 23 | Module, 24 | Type, 25 | Index, 26 | Scalar, 27 | Function, 28 | 29 | Identifier, 30 | EndOfFile 31 | } 32 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Impl/BaseTemporalCodec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Codecs; 4 | 5 | internal abstract class BaseTemporalCodec 6 | : BaseComplexScalarCodec, ITemporalCodec 7 | where T : unmanaged 8 | { 9 | public BaseTemporalCodec(in Guid id, CodecMetadata? metadata) 10 | : base(in id, metadata) 11 | { 12 | } 13 | 14 | Type ITemporalCodec.ModelType => typeof(T); 15 | 16 | IEnumerable ITemporalCodec.SystemTypes => Converters is null ? Array.Empty() : Converters.Keys; 17 | } 18 | -------------------------------------------------------------------------------- /tests/Gel.Tests.Integration/HttpClientTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using System.Threading.Tasks; 3 | 4 | namespace Gel.Tests.Integration; 5 | 6 | [TestClass] 7 | public class HttpClientTests : ClientTests 8 | { 9 | public HttpClientTests() 10 | { 11 | ClientPool = ClientProvider.HttpClientPool; 12 | } 13 | 14 | [TestMethod] 15 | public override Task TestPoolTransactions() 16 | { 17 | Assert.ThrowsExceptionAsync(() => base.TestPoolTransactions()); 18 | return Task.CompletedTask; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/Common/PacketHeader.cs: -------------------------------------------------------------------------------- 1 | using Gel.Utils; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace Gel.Binary.Protocol.Common; 5 | 6 | [StructLayout(LayoutKind.Explicit, Pack = 0, Size = 5)] 7 | internal struct PacketHeader 8 | { 9 | [FieldOffset(0)] public readonly ServerMessageType Type; 10 | 11 | [FieldOffset(1)] public int Length; 12 | 13 | public void CorrectLength() 14 | { 15 | BinaryUtils.CorrectEndianness(ref Length); 16 | // remove the length of "Length" from the length of the packet 17 | Length -= 4; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/Exceptions/CustomClientException.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | /// 4 | /// Represents a generic error with custom clients. 5 | /// 6 | public sealed class CustomClientException : GelException 7 | { 8 | /// 9 | /// Constructs a new with the specified error message. 10 | /// 11 | /// The error message describing why this exception was thrown. 12 | public CustomClientException(string message) 13 | : base(message) 14 | { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/TransactionState.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | /// 4 | /// Represents the transaction state of the client. 5 | /// 6 | public enum TransactionState : byte 7 | { 8 | /// 9 | /// The client isn't in a transaction. 10 | /// 11 | NotInTransaction = 0x49, 12 | 13 | /// 14 | /// The client is in a transaction. 15 | /// 16 | InTransaction = 0x54, 17 | 18 | /// 19 | /// The client is in a failed transaction. 20 | /// 21 | InFailedTransaction = 0x45 22 | } 23 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V2.0/Descriptors/SetDescriptor.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V2._0.Descriptors; 2 | 3 | internal readonly struct SetDescriptor : ITypeDescriptor 4 | { 5 | public readonly Guid Id; 6 | 7 | public readonly ushort Type; 8 | 9 | public SetDescriptor(ref PacketReader reader, in Guid id) 10 | { 11 | Id = id; 12 | Type = reader.ReadUInt16(); 13 | } 14 | 15 | unsafe ref readonly Guid ITypeDescriptor.Id 16 | { 17 | get 18 | { 19 | fixed (Guid* ptr = &Id) 20 | return ref *ptr; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/Exceptions/InvalidConnectionException.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | /// 4 | /// Represents an error with the provided connection details. 5 | /// 6 | public class InvalidConnectionException : GelException 7 | { 8 | /// 9 | /// Constructs a new with the specified error message. 10 | /// 11 | /// The error message describing why this exception was thrown. 12 | public InvalidConnectionException(string message) 13 | : base(message) 14 | { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tools/Gel.DotnetTool/Schemas/ClassBuilderContext.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.DotnetTool; 2 | 3 | internal class ClassBuilderContext 4 | { 5 | public List BuiltTypes { get; set; } = new(); 6 | 7 | public List BuildProperties { get; set; } = new(); 8 | 9 | public Func NameCallback { get; set; } = s => s; 10 | 11 | public List RequestedAttributes { get; set; } = new(); 12 | 13 | public Type? Type { get; set; } 14 | 15 | public Module? Module { get; set; } 16 | 17 | public Property? Property { get; set; } 18 | 19 | public string? OutputDir { get; set; } 20 | } 21 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/DumpRestore/V1.0/DumpSectionHeader.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace Gel.Binary.Protocol.DumpRestore.V1._0; 5 | 6 | // 0x00 -> 0x02 Type 7 | // 0x02 -> 0x16 Hash 8 | // 0x16 -> 0x20 Length 9 | [StructLayout(LayoutKind.Explicit, Size = 26)] 10 | internal struct DumpSectionHeader 11 | { 12 | [FieldOffset(0)] public char Type; 13 | 14 | [FieldOffset(22)] public int Length; 15 | 16 | public readonly unsafe ReadOnlySpan Hash 17 | => new((byte*)Unsafe.AsPointer(ref Unsafe.AsRef(in this)) + 1, 20); 18 | } 19 | -------------------------------------------------------------------------------- /tools/Gel.QueryBuilder.OperatorGenerator/Gel.QueryBuilder.OperatorGenerator.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Descriptors/SetDescriptor.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Descriptors; 2 | 3 | internal readonly struct SetTypeDescriptor : ITypeDescriptor 4 | { 5 | public readonly Guid Id; 6 | 7 | public readonly ushort TypePos; 8 | 9 | public SetTypeDescriptor(scoped in Guid id, scoped ref PacketReader reader) 10 | { 11 | Id = id; 12 | TypePos = reader.ReadUInt16(); 13 | } 14 | 15 | unsafe ref readonly Guid ITypeDescriptor.Id 16 | { 17 | get 18 | { 19 | fixed (Guid* ptr = &Id) 20 | return ref *ptr; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Descriptors/RangeTypeDescriptor.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Descriptors; 2 | 3 | internal readonly struct RangeTypeDescriptor : ITypeDescriptor 4 | { 5 | public readonly Guid Id; 6 | public readonly ushort TypePos; 7 | 8 | public RangeTypeDescriptor(scoped in Guid id, scoped ref PacketReader reader) 9 | { 10 | Id = id; 11 | TypePos = reader.ReadUInt16(); 12 | } 13 | 14 | unsafe ref readonly Guid ITypeDescriptor.Id 15 | { 16 | get 17 | { 18 | fixed (Guid* ptr = &Id) 19 | return ref *ptr; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/DataTypes/Memory.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.DataTypes; 2 | 3 | /// 4 | /// Represents the memory type in Gel. 5 | /// 6 | public readonly struct Memory 7 | { 8 | /// 9 | /// Gets the total amount of bytes for this memory object. 10 | /// 11 | public long TotalBytes { get; } 12 | 13 | /// 14 | /// Gets the total amount of megabytes for this memory object. 15 | /// 16 | public long TotalMegabytes 17 | => TotalBytes / 1024 / 1024; 18 | 19 | internal Memory(long bytes) 20 | { 21 | TotalBytes = bytes; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/Exceptions/MissingCodecException.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | /// 4 | /// Represents an exception that occurs when the client doesn't 5 | /// have a codec for incoming or outgoing data. 6 | /// 7 | public class MissingCodecException : GelException 8 | { 9 | /// 10 | /// Constructs a new with the specified error message. 11 | /// 12 | /// The error message describing why this exception was thrown. 13 | public MissingCodecException(string message) 14 | : base(message) 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/ErrorSeverity.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | /// 4 | /// An enum representing the error severity of a . 5 | /// 6 | public enum ErrorSeverity : byte 7 | { 8 | /// 9 | /// An error. 10 | /// 11 | Error = 0x78, 12 | 13 | /// 14 | /// A fatal error. 15 | /// 16 | Fatal = 0xc8, 17 | 18 | /// 19 | /// 20 | /// A panic. 21 | /// 22 | Panic = 0xff 23 | } 24 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/ServerMessageType.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary; 2 | 3 | /// 4 | /// Represents all supported message types sent by the server. 5 | /// 6 | internal enum ServerMessageType : sbyte 7 | { 8 | RestoreReady = 0x2b, 9 | DumpBlock = 0x3d, 10 | DumpHeader = 0x40, 11 | CommandComplete = 0x43, 12 | Data = 0x44, 13 | ErrorResponse = 0x45, 14 | ServerKeyData = 0x4b, 15 | LogMessage = 0x4c, 16 | Authentication = 0x52, 17 | CommandDataDescription = 0x54, 18 | ParameterStatus = 0x53, 19 | ReadyForCommand = 0x5a, 20 | StateDataDescription = 0x73, 21 | ServerHandshake = 0x76 22 | } 23 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Descriptors/ScalarTypeDescriptor.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Descriptors; 2 | 3 | internal readonly struct ScalarTypeDescriptor : ITypeDescriptor 4 | { 5 | public readonly Guid Id; 6 | 7 | public readonly ushort BaseTypePos; 8 | 9 | public ScalarTypeDescriptor(scoped in Guid id, scoped ref PacketReader reader) 10 | { 11 | Id = id; 12 | BaseTypePos = reader.ReadUInt16(); 13 | } 14 | 15 | unsafe ref readonly Guid ITypeDescriptor.Id 16 | { 17 | get 18 | { 19 | fixed (Guid* ptr = &Id) 20 | return ref *ptr; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Descriptors/ScalarTypeNameAnnotation.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Descriptors; 2 | 3 | internal readonly struct ScalarTypeNameAnnotation : ITypeDescriptor 4 | { 5 | public readonly Guid Id; 6 | 7 | public readonly string Name; 8 | 9 | public ScalarTypeNameAnnotation(scoped in Guid id, scoped ref PacketReader reader) 10 | { 11 | Id = id; 12 | Name = reader.ReadString(); 13 | } 14 | 15 | unsafe ref readonly Guid ITypeDescriptor.Id 16 | { 17 | get 18 | { 19 | fixed (Guid* ptr = &Id) 20 | return ref *ptr; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Impl/BaseArgumentCodec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Codecs; 4 | 5 | internal abstract class BaseArgumentCodec : BaseCodec, IArgumentCodec 6 | { 7 | protected BaseArgumentCodec(in Guid id, CodecMetadata? metadata) 8 | : base(in id, metadata) 9 | { 10 | } 11 | 12 | public abstract void SerializeArguments(ref PacketWriter writer, T? value, ArgumentCodecContext context); 13 | 14 | void IArgumentCodec.SerializeArguments(ref PacketWriter writer, object? value, ArgumentCodecContext context) 15 | => SerializeArguments(ref writer, (T?)value, context); 16 | } 17 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Descriptors/ShapeElement.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Protocol.V1._0.Descriptors; 4 | 5 | internal readonly struct ShapeElement 6 | { 7 | public readonly ShapeElementFlags Flags; 8 | public readonly Cardinality Cardinality; 9 | public readonly string Name; 10 | public readonly ushort TypePos; 11 | 12 | public ShapeElement(ref PacketReader reader) 13 | { 14 | Flags = (ShapeElementFlags)reader.ReadUInt32(); 15 | Cardinality = (Cardinality)reader.ReadByte(); 16 | Name = reader.ReadString(); 17 | TypePos = reader.ReadUInt16(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/Gel.Examples.CSharp/ExampleRunner.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | 3 | namespace Gel.ExampleApp; 4 | 5 | public class ExampleRunner 6 | { 7 | private readonly GelClientPool _clientPool; 8 | private readonly ILogger _logger; 9 | private readonly ILoggerFactory _loggerFactory; 10 | 11 | public ExampleRunner(GelClientPool clientPool, ILogger logger, ILoggerFactory factory) 12 | { 13 | _clientPool = clientPool; 14 | _logger = logger; 15 | _loggerFactory = factory; 16 | } 17 | 18 | public async Task StartAsync() => 19 | await IExample.ExecuteAllAsync(_clientPool, _logger, _loggerFactory).ConfigureAwait(false); 20 | } 21 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/NamingStrategies/PascalNamingStrategy.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace Gel; 4 | 5 | internal sealed class PascalNamingStrategy : INamingStrategy 6 | { 7 | public string Convert(PropertyInfo property) 8 | => Convert(property.Name); 9 | 10 | public string Convert(string name) 11 | { 12 | var sample = string.Join("", 13 | name.Select(c => char.IsLetterOrDigit(c) ? c.ToString().ToLower() : "_").ToArray()); 14 | 15 | var arr = sample 16 | .Split(new[] {'_'}, StringSplitOptions.RemoveEmptyEntries) 17 | .Select(s => $"{s[..1].ToUpper()}{s[1..]}"); 18 | 19 | return string.Join("", arr); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /dbschema/migrations/00003.edgeql: -------------------------------------------------------------------------------- 1 | CREATE MIGRATION m1tpouzupcrd2nkhl45qsdykw3dzjbk4ecndr73tmatxskaxkixu3q 2 | ONTO m1vqxxs4ie4so3x35nk2wyu3jy3hmolscpyxu6bccucaofjtnrtj3a 3 | { 4 | CREATE TYPE default::Movie { 5 | CREATE REQUIRED MULTI LINK actors -> default::Person; 6 | CREATE REQUIRED LINK director -> default::Person; 7 | CREATE REQUIRED PROPERTY title -> std::str; 8 | CREATE REQUIRED PROPERTY year -> std::int32; 9 | }; 10 | ALTER TYPE default::Person { 11 | ALTER PROPERTY email { 12 | SET REQUIRED USING ('e'); 13 | }; 14 | }; 15 | ALTER TYPE default::Person { 16 | ALTER PROPERTY name { 17 | SET REQUIRED USING ('e'); 18 | }; 19 | }; 20 | }; 21 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Impl/ICodec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Codecs; 4 | 5 | internal interface ICodec : ICodec 6 | { 7 | void Serialize(ref PacketWriter writer, T? value, CodecContext context); 8 | 9 | new T? Deserialize(ref PacketReader reader, CodecContext context); 10 | } 11 | 12 | internal interface ICodec 13 | { 14 | Guid Id { get; } 15 | 16 | CodecMetadata? Metadata { get; } 17 | 18 | Type ConverterType { get; } 19 | 20 | bool CanConvert(Type t); 21 | 22 | void Serialize(ref PacketWriter writer, object? value, CodecContext context); 23 | 24 | object? Deserialize(ref PacketReader reader, CodecContext context); 25 | } 26 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/Exceptions/TransactionException.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | /// 4 | /// Represents an exception that occurs within transactions. 5 | /// 6 | public class TransactionException : GelException 7 | { 8 | /// 9 | /// Constructs a new with a specified error message. 10 | /// 11 | /// The error message describing why this exception was thrown. 12 | /// An optional inner exception. 13 | public TransactionException(string message, Exception? innerException = null) 14 | : base(message, innerException) 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/Gel.Examples.CSharp/Examples/GlobalsAndConfig.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | 3 | namespace Gel.ExampleApp.Examples; 4 | 5 | internal class GlobalsAndConfig : IExample 6 | { 7 | public ILogger? Logger { get; set; } 8 | 9 | public async Task ExecuteAsync(GelClientPool baseClientPool) 10 | { 11 | var clientPool = baseClientPool 12 | .WithConfig(conf => conf.AllowDMLInFunctions = true) 13 | .WithGlobals(new Dictionary {{"current_user_id", Guid.NewGuid()}}); 14 | 15 | var result = await clientPool.QueryRequiredSingleAsync("select global current_user_id"); 16 | Logger!.LogInformation("CurrentUserId: {@Id}", result); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/Gel.Examples.ExampleTODOApi/Program.cs: -------------------------------------------------------------------------------- 1 | using Gel; 2 | 3 | var builder = WebApplication.CreateBuilder(args); 4 | 5 | // Add services to the container. 6 | 7 | builder.Services.AddControllers(); 8 | // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle 9 | builder.Services.AddEndpointsApiExplorer(); 10 | builder.Services.AddSwaggerGen(); 11 | 12 | builder.Services.AddGel(); 13 | 14 | var app = builder.Build(); 15 | 16 | // Configure the HTTP request pipeline. 17 | if (app.Environment.IsDevelopment()) 18 | { 19 | app.UseSwagger(); 20 | app.UseSwaggerUI(); 21 | } 22 | 23 | app.UseHttpsRedirection(); 24 | 25 | app.UseAuthorization(); 26 | 27 | app.MapControllers(); 28 | 29 | app.Run(); 30 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/UUIDCodec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Codecs; 4 | 5 | internal sealed class UUIDCodec 6 | : BaseScalarCodec 7 | { 8 | public new static readonly Guid Id = Guid.Parse("00000000-0000-0000-0000-000000000100"); 9 | 10 | public UUIDCodec(CodecMetadata? metadata = null) 11 | : base(in Id, metadata) 12 | { 13 | } 14 | 15 | public override Guid Deserialize(ref PacketReader reader, CodecContext context) => reader.ReadGuid(); 16 | 17 | public override void Serialize(ref PacketWriter writer, Guid value, CodecContext context) => writer.Write(value); 18 | 19 | public override string ToString() 20 | => "std::uuid"; 21 | } 22 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/BoolCodec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Codecs; 4 | 5 | internal sealed class BoolCodec 6 | : BaseScalarCodec 7 | { 8 | public new static readonly Guid Id = Guid.Parse("00000000-0000-0000-0000-000000000109"); 9 | 10 | public BoolCodec(CodecMetadata? metadata = null) 11 | : base(in Id, metadata) 12 | { 13 | } 14 | 15 | public override bool Deserialize(ref PacketReader reader, CodecContext context) => reader.ReadBoolean(); 16 | 17 | public override void Serialize(ref PacketWriter writer, bool value, CodecContext context) => writer.Write(value); 18 | 19 | public override string ToString() 20 | => "std::bool"; 21 | } 22 | -------------------------------------------------------------------------------- /tests/Gel.Tests.Benchmarks/Gel.Tests.Benchmarks.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | 11.0 8 | enable 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Integer32Codec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Codecs; 4 | 5 | internal sealed class Integer32Codec 6 | : BaseScalarCodec 7 | { 8 | public new static readonly Guid Id = Guid.Parse("00000000-0000-0000-0000-000000000104"); 9 | 10 | public Integer32Codec(CodecMetadata? metadata = null) 11 | : base(in Id, metadata) 12 | { 13 | } 14 | 15 | public override int Deserialize(ref PacketReader reader, CodecContext context) => reader.ReadInt32(); 16 | 17 | public override void Serialize(ref PacketWriter writer, int value, CodecContext context) => writer.Write(value); 18 | 19 | public override string ToString() 20 | => "std::int32"; 21 | } 22 | -------------------------------------------------------------------------------- /tests/Gel.Tests.Integration/Gel.Tests.Integration.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Float32Codec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Codecs; 4 | 5 | internal sealed class Float32Codec 6 | : BaseScalarCodec 7 | { 8 | public new static readonly Guid Id = Guid.Parse("00000000-0000-0000-0000-000000000106"); 9 | 10 | public Float32Codec(CodecMetadata? metadata = null) 11 | : base(in Id, metadata) 12 | { 13 | } 14 | 15 | public override float Deserialize(ref PacketReader reader, CodecContext context) => reader.ReadSingle(); 16 | 17 | public override void Serialize(ref PacketWriter writer, float value, CodecContext context) => writer.Write(value); 18 | 19 | public override string ToString() 20 | => "std::float32"; 21 | } 22 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Float64Codec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Codecs; 4 | 5 | internal sealed class Float64Codec 6 | : BaseScalarCodec 7 | { 8 | public new static readonly Guid Id = Guid.Parse("00000000-0000-0000-0000-000000000107"); 9 | 10 | public Float64Codec(CodecMetadata? metadata = null) 11 | : base(in Id, metadata) 12 | { 13 | } 14 | 15 | public override double Deserialize(ref PacketReader reader, CodecContext context) => reader.ReadDouble(); 16 | 17 | public override void Serialize(ref PacketWriter writer, double value, CodecContext context) => writer.Write(value); 18 | 19 | public override string ToString() 20 | => "std::float64"; 21 | } 22 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Integer16Codec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Codecs; 4 | 5 | internal sealed class Integer16Codec 6 | : BaseScalarCodec 7 | { 8 | public new static readonly Guid Id = Guid.Parse("00000000-0000-0000-0000-000000000103"); 9 | 10 | public Integer16Codec(CodecMetadata? metadata = null) 11 | : base(in Id, metadata) 12 | { 13 | } 14 | 15 | public override short Deserialize(ref PacketReader reader, CodecContext context) => reader.ReadInt16(); 16 | 17 | public override void Serialize(ref PacketWriter writer, short value, CodecContext context) => writer.Write(value); 18 | 19 | public override string ToString() 20 | => "std::int16"; 21 | } 22 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Integer64Codec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Codecs; 4 | 5 | internal sealed class Integer64Codec 6 | : BaseScalarCodec 7 | { 8 | public new static readonly Guid Id = Guid.Parse("00000000-0000-0000-0000-000000000105"); 9 | 10 | public Integer64Codec(CodecMetadata? metadata = null) 11 | : base(in Id, metadata) 12 | { 13 | } 14 | 15 | public override long Deserialize(ref PacketReader reader, CodecContext context) => reader.ReadInt64(); 16 | 17 | public override void Serialize(ref PacketWriter writer, long value, CodecContext context) => writer.Write(value); 18 | 19 | public override string ToString() 20 | => "std::int64"; 21 | } 22 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Common/Annotation.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace Gel.Binary; 4 | 5 | /// 6 | /// Represents an annotation within a packet. 7 | /// 8 | internal readonly struct Annotation 9 | { 10 | internal int Size => Encoding.UTF8.GetByteCount(Name) + Encoding.UTF8.GetByteCount(Value); 11 | 12 | /// 13 | /// The name of this annotation. 14 | /// 15 | public readonly string Name; 16 | 17 | /// 18 | /// The value of the annotation (in json format). 19 | /// 20 | public readonly string Value; 21 | 22 | internal Annotation(string name, string value) 23 | { 24 | Name = name; 25 | Value = value; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/Gel.Examples.CSharp/Examples/CancelQueries.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | 3 | namespace Gel.ExampleApp.Examples; 4 | 5 | internal class CancelQueries : IExample 6 | { 7 | public ILogger? Logger { get; set; } 8 | 9 | public async Task ExecuteAsync(GelClientPool clientPool) 10 | { 11 | using var tokenSource = new CancellationTokenSource(); 12 | tokenSource.CancelAfter(TimeSpan.FromTicks(5)); 13 | 14 | try 15 | { 16 | await clientPool.QueryRequiredSingleAsync("select \"Hello, World\"", token: tokenSource.Token); 17 | } 18 | catch (OperationCanceledException) 19 | { 20 | Logger!.LogInformation("Got task cancelled exception"); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V2.0/Descriptors/ShapeElement.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Protocol.V2._0.Descriptors; 4 | 5 | internal readonly struct ShapeElement 6 | { 7 | public readonly ShapeElementFlags Flags; 8 | public readonly Cardinality Cardinality; 9 | public readonly string Name; 10 | public readonly ushort TypePos; 11 | public readonly ushort SourceType; 12 | 13 | public ShapeElement(ref PacketReader reader) 14 | { 15 | Flags = (ShapeElementFlags)reader.ReadUInt32(); 16 | Cardinality = (Cardinality)reader.ReadByte(); 17 | Name = reader.ReadString(); 18 | TypePos = reader.ReadUInt16(); 19 | SourceType = reader.ReadUInt16(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Descriptors/TypeAnnotationDescriptor.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Descriptors; 2 | 3 | internal readonly struct TypeAnnotationDescriptor : ITypeDescriptor 4 | { 5 | public readonly DescriptorType Type; 6 | public readonly Guid Id; 7 | public readonly string Annotation; 8 | 9 | public TypeAnnotationDescriptor(scoped in DescriptorType type, scoped in Guid id, scoped ref PacketReader reader) 10 | { 11 | Type = type; 12 | Id = id; 13 | Annotation = reader.ReadString(); 14 | } 15 | 16 | unsafe ref readonly Guid ITypeDescriptor.Id 17 | { 18 | get 19 | { 20 | fixed (Guid* ptr = &Id) 21 | return ref *ptr; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tools/Gel.QueryBuilder.OperatorGenerator/Models/EdgeQLOperator.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.QueryBuilder.OperatorGenerator; 2 | 3 | public class EdgeQLOperator 4 | { 5 | public string? Expression { get; set; } 6 | 7 | public string? Operator { get; set; } 8 | 9 | public string? Return { get; set; } 10 | 11 | public string? Name { get; set; } 12 | 13 | public List? Functions { get; set; } = new(); 14 | 15 | public List ParameterMap { get; set; } = new(); 16 | 17 | public List PropertyMap { get; set; } = new(); 18 | 19 | public List FunctionMap { get; set; } = new(); 20 | 21 | // enum 22 | public List Elements { get; set; } = new(); 23 | 24 | public string? SerializeMethod { get; set; } 25 | } 26 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Extensions/JsonSerializerExtensions.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Gel; 4 | 5 | internal static class JsonSerializerExtensions 6 | { 7 | public static T? DeserializeObject(this JsonSerializer serializer, string value) 8 | { 9 | using var textReader = new StringReader(value); 10 | using var jsonReader = new JsonTextReader(textReader); 11 | return serializer.Deserialize(jsonReader); 12 | } 13 | 14 | public static string SerializeObject(this JsonSerializer serialier, object? value) 15 | { 16 | using var textWriter = new StringWriter(); 17 | using var jsonWriter = new JsonTextWriter(textWriter); 18 | serialier.Serialize(jsonWriter, value); 19 | return textWriter.ToString(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/Gel.Examples.ExampleTODOApi/TODOModel.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace Gel.Examples.ExampleTODOApi; 4 | 5 | [GelType] 6 | public class TODOModel 7 | { 8 | [JsonPropertyName("title")] 9 | [GelProperty("title")] 10 | public string? Title { get; set; } 11 | 12 | [JsonPropertyName("description")] 13 | [GelProperty("description")] 14 | public string? Description { get; set; } 15 | 16 | [JsonPropertyName("date_created")] 17 | [GelProperty("date_created")] 18 | public DateTimeOffset DateCreated { get; set; } 19 | 20 | [JsonPropertyName("state")] 21 | [GelProperty("state")] 22 | public TODOState State { get; set; } 23 | } 24 | 25 | public enum TODOState 26 | { 27 | NotStarted, 28 | InProgress, 29 | Complete 30 | } 31 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Receivables/StateDataDescription.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Packets; 2 | 3 | /// 4 | /// Represents the 5 | /// State Data Description 6 | /// packet. 7 | /// 8 | internal readonly struct StateDataDescription : IReceiveable 9 | { 10 | public ServerMessageType Type => ServerMessageType.StateDataDescription; 11 | 12 | public readonly Guid TypeDescriptorId; 13 | 14 | internal readonly byte[] TypeDescriptorBuffer; 15 | 16 | internal StateDataDescription(ref PacketReader reader) 17 | { 18 | TypeDescriptorId = reader.ReadGuid(); 19 | TypeDescriptorBuffer = reader.ReadByteArray(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/Exceptions/ResultCardinalityMismatchException.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | /// 4 | /// Represents an exception that occurs when a queries cardinality 5 | /// isn't what the client was expecting. 6 | /// 7 | public class ResultCardinalityMismatchException : GelException 8 | { 9 | /// 10 | /// Constructs a new . 11 | /// 12 | /// The expected cardinality. 13 | /// The actual cardinality 14 | public ResultCardinalityMismatchException(Cardinality expected, Cardinality actual) 15 | : base($"Got mismatch on cardinality of query. Expected \"{expected}\" but got \"{actual}\"") 16 | { 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/MemoryCodec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | using Gel.DataTypes; 3 | 4 | namespace Gel.Binary.Codecs; 5 | 6 | internal sealed class MemoryCodec 7 | : BaseScalarCodec 8 | { 9 | public new static readonly Guid Id = Guid.Parse("00000000-0000-0000-0000-000000000130"); 10 | 11 | public MemoryCodec(CodecMetadata? metadata = null) 12 | : base(in Id, metadata) 13 | { 14 | } 15 | 16 | public override Memory Deserialize(ref PacketReader reader, CodecContext context) => new(reader.ReadInt64()); 17 | 18 | public override void Serialize(ref PacketWriter writer, Memory value, CodecContext context) => 19 | writer.Write(value.TotalBytes); 20 | 21 | public override string ToString() 22 | => "cfg::memory"; 23 | } 24 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Sendables/Restore.cs: -------------------------------------------------------------------------------- 1 | using Gel.Utils; 2 | 3 | namespace Gel.Binary.Protocol.V1._0.Packets; 4 | 5 | internal sealed class Restore : Sendable 6 | { 7 | public override int Size 8 | => BinaryUtils.SizeOfAnnotations(Headers) + sizeof(ushort) + BinaryUtils.SizeOfByteArray(HeaderData); 9 | 10 | public override ClientMessageTypes Type 11 | => ClientMessageTypes.Restore; 12 | 13 | public Annotation[]? Headers { get; set; } 14 | 15 | public ushort Jobs { get; } = 1; 16 | 17 | public byte[]? HeaderData { get; set; } 18 | 19 | protected override void BuildPacket(ref PacketWriter writer) 20 | { 21 | writer.Write(Headers); 22 | writer.Write(Jobs); 23 | writer.WriteArrayWithoutLength(HeaderData!); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tools/Gel.BinaryDebugger/Program.cs: -------------------------------------------------------------------------------- 1 | using Gel; 2 | using Gel.BinaryDebugger; 3 | 4 | var clientPool = new GelClientPool(new GelClientPoolConfig 5 | { 6 | ClientFactory = async (id, conn, conf) => 7 | { 8 | var client = new DebuggerClient(conn, conf, id); 9 | await client.ConnectAsync(); 10 | return client; 11 | }, 12 | ClientType = GelClientType.Custom 13 | }); 14 | 15 | var debugClientPool = await clientPool.GetOrCreateClientAsync(); 16 | 17 | try 18 | { 19 | await debugClientPool.QueryAsync("select \"Hello, World!\""); 20 | } 21 | catch (Exception x) 22 | { 23 | Console.WriteLine(x); 24 | } 25 | finally 26 | { 27 | await debugClientPool.DisconnectAsync(); 28 | await debugClientPool.DisposeAsync(); 29 | } 30 | 31 | await Task.Delay(-1); 32 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/BytesCodec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Codecs; 4 | 5 | internal sealed class BytesCodec 6 | : BaseScalarCodec 7 | { 8 | public new static readonly Guid Id = Guid.Parse("00000000-0000-0000-0000-000000000102"); 9 | 10 | public BytesCodec(CodecMetadata? metadata = null) 11 | : base(in Id, metadata) 12 | { 13 | } 14 | 15 | public override byte[] Deserialize(ref PacketReader reader, CodecContext context) => reader.ConsumeByteArray(); 16 | 17 | public override void Serialize(ref PacketWriter writer, byte[]? value, CodecContext context) 18 | { 19 | if (value is not null) 20 | writer.Write(value); 21 | } 22 | 23 | public override string ToString() 24 | => "std::bytes"; 25 | } 26 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Attributes/GelTypeAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | /// 4 | /// Marks this class or struct as a valid type to use when serializing/deserializing. 5 | /// 6 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] 7 | public class GelTypeAttribute : Attribute 8 | { 9 | internal readonly string? Name; 10 | 11 | /// 12 | /// Marks this as a valid target to use when serializing/deserializing. 13 | /// 14 | /// The name of the type in the gel schema. 15 | public GelTypeAttribute(string name) 16 | { 17 | Name = name; 18 | } 19 | 20 | /// 21 | /// Marks this as a valid target to use when serializing/deserializing. 22 | /// 23 | public GelTypeAttribute() { } 24 | } 25 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Sendables/AuthenticationSASLResponse.cs: -------------------------------------------------------------------------------- 1 | using Gel.Utils; 2 | using System.Text; 3 | 4 | namespace Gel.Binary.Protocol.V1._0.Packets; 5 | 6 | internal sealed class AuthenticationSASLResponse : Sendable 7 | { 8 | private readonly ReadOnlyMemory _payload; 9 | 10 | public AuthenticationSASLResponse(ReadOnlyMemory payload) 11 | { 12 | _payload = payload; 13 | } 14 | 15 | public override ClientMessageTypes Type 16 | => ClientMessageTypes.AuthenticationSASLResponse; 17 | 18 | public override int Size 19 | => BinaryUtils.SizeOfByteArray(_payload); 20 | 21 | protected override void BuildPacket(ref PacketWriter writer) => writer.WriteArray(_payload); 22 | 23 | public override string ToString() => Encoding.UTF8.GetString(_payload.Span); 24 | } 25 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Extensions/ReceivableExtensions.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol; 2 | using Gel.Binary.Protocol.Common; 3 | 4 | namespace Gel; 5 | 6 | internal static class ReceivableExtensions 7 | { 8 | public static void ThrowIfErrrorResponse(this IReceiveable packet, string? query = null) 9 | { 10 | if (packet is IProtocolError err) 11 | throw new ServerErrorException(err, query); 12 | } 13 | 14 | public static TPacket ThrowIfErrorOrNot(this IReceiveable packet) 15 | where TPacket : IReceiveable, new() 16 | { 17 | if (packet is IProtocolError err) 18 | throw new ServerErrorException(err); 19 | 20 | if (packet is not TPacket p) 21 | throw new UnexpectedMessageException(new TPacket().Type, packet.Type); 22 | 23 | return p; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V2.0/Descriptors/TypeAnnotationTextDescriptor.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V2._0.Descriptors; 2 | 3 | internal readonly struct TypeAnnotationTextDescriptor : ITypeDescriptor 4 | { 5 | public readonly Guid Id; 6 | 7 | public readonly ushort Descriptor; 8 | 9 | public readonly string Key; 10 | 11 | public readonly string Value; 12 | 13 | public TypeAnnotationTextDescriptor(ref PacketReader reader) 14 | { 15 | Id = Guid.Empty; 16 | 17 | Descriptor = reader.ReadUInt16(); 18 | 19 | Key = reader.ReadString(); 20 | Value = reader.ReadString(); 21 | } 22 | 23 | unsafe ref readonly Guid ITypeDescriptor.Id 24 | { 25 | get 26 | { 27 | fixed (Guid* ptr = &Id) 28 | return ref *ptr; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/Exceptions/ConfigurationException.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | /// 4 | /// Represents a generic configuration error. 5 | /// 6 | public sealed class ConfigurationException : GelException 7 | { 8 | /// 9 | /// Creates a new . 10 | /// 11 | /// The configuration error message. 12 | public ConfigurationException(string message) : base(message) { } 13 | 14 | /// 15 | /// Creates a new . 16 | /// 17 | /// The configuration error message. 18 | /// An inner exception. 19 | public ConfigurationException(string message, Exception inner) : base(message, inner) { } 20 | } 21 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Receivables/ServerKeyData.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Packets; 2 | 3 | /// 4 | /// Represents the 5 | /// Server Key Data packet. 6 | /// 7 | internal readonly struct ServerKeyData : IReceiveable 8 | { 9 | public const int SERVER_KEY_LENGTH = 32; 10 | 11 | /// 12 | public ServerMessageType Type 13 | => ServerMessageType.ServerKeyData; 14 | 15 | /// 16 | /// The key data buffer. 17 | /// 18 | internal readonly byte[] KeyBuffer; 19 | 20 | internal ServerKeyData(ref PacketReader reader) 21 | { 22 | reader.ReadBytes(SERVER_KEY_LENGTH, out var buff); 23 | KeyBuffer = buff.ToArray(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/Gel.Examples.CSharp/Examples/JsonResults.cs: -------------------------------------------------------------------------------- 1 | using Gel.DataTypes; 2 | using Microsoft.Extensions.Logging; 3 | using Newtonsoft.Json; 4 | 5 | namespace Gel.ExampleApp.Examples; 6 | 7 | internal class JsonResults : IExample 8 | { 9 | public ILogger? Logger { get; set; } 10 | 11 | public async Task ExecuteAsync(GelClientPool clientPool) 12 | { 13 | var result = await clientPool.QueryJsonAsync("select Person {name, email}"); 14 | 15 | var people = JsonConvert.DeserializeObject(result); 16 | if (people is null) { return; } 17 | 18 | Logger!.LogInformation("People from json: {@People}", people); 19 | } 20 | 21 | public class Person 22 | { 23 | [JsonProperty("name")] public string? Name { get; set; } 24 | 25 | [JsonProperty("email")] public string? Email { get; set; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Receivables/AuthStatus.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Packets; 2 | 3 | /// 4 | /// Represents the authentication state. 5 | /// 6 | internal enum AuthStatus : uint 7 | { 8 | /// 9 | /// The authentication was successful and is validated. 10 | /// 11 | AuthenticationOK = 0x0, 12 | 13 | /// 14 | /// The server requires an SASL message. 15 | /// 16 | AuthenticationRequiredSASLMessage = 0xa, 17 | 18 | /// 19 | /// The client should continue sending SASL messages. 20 | /// 21 | AuthenticationSASLContinue = 0xb, 22 | 23 | /// 24 | /// The received message was the final authentication message. 25 | /// 26 | AuthenticationSASLFinal = 0xc 27 | } 28 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/Exceptions/QueryTimeoutException.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | /// 4 | /// Represents an exception thrown when a query operation times out. 5 | /// 6 | public class QueryTimeoutException : GelException 7 | { 8 | internal QueryTimeoutException(uint timeout, string query, OperationCanceledException ce) 9 | : base("The query operation timed out", ce) 10 | { 11 | TimeoutDuration = timeout; 12 | Query = query; 13 | } 14 | 15 | /// 16 | /// Gets the query that caused the operation to time out. 17 | /// 18 | public string Query { get; } 19 | 20 | /// 21 | /// Gets the configured timeout duration allocated for the 22 | /// query when it was timed out. 23 | /// 24 | public uint TimeoutDuration { get; } 25 | } 26 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/IOFormat.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | /// 4 | /// An enum representing the format of a commands result. 5 | /// 6 | public enum IOFormat : byte 7 | { 8 | /// 9 | /// The format will be encoded as binary following the 10 | /// Data Wire Formats 11 | /// protocol. 12 | /// 13 | Binary = 0x62, 14 | 15 | /// 16 | /// The format will be encoded as json. 17 | /// 18 | Json = 0x6a, 19 | 20 | /// 21 | /// The format will be encoded as json elements. 22 | /// 23 | JsonElements = 0x4a, 24 | 25 | /// 26 | /// The format will be nothing. 27 | /// 28 | None = 0x6e 29 | } 30 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/Cardinality.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | /// 4 | /// A enum containing the cardinality specification of a command. 5 | /// 6 | public enum Cardinality : byte 7 | { 8 | /// 9 | /// The command will return no result. 10 | /// 11 | NoResult = 0x6e, 12 | 13 | /// 14 | /// The command will return at most one result. 15 | /// 16 | AtMostOne = 0x6f, 17 | 18 | /// 19 | /// The command will return a single result. 20 | /// 21 | One = 0x41, 22 | 23 | /// 24 | /// The command will return zero to infinite results. 25 | /// 26 | Many = 0x6d, 27 | 28 | /// 29 | /// The command will return one to infinite results. 30 | /// 31 | AtLeastOne = 0x4d 32 | } 33 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/Exceptions/ConnectionFailedException.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | /// 4 | /// Represents a connection failure that cannot be retried. 5 | /// 6 | public sealed class ConnectionFailedException : GelException 7 | { 8 | /// 9 | /// Constructs a new with the number 10 | /// of connection attempts made. 11 | /// 12 | /// The number of attempts made to connect. 13 | public ConnectionFailedException(int attempts) 14 | : base($"The connection failed to be established after {attempts} attempt(s)") 15 | { 16 | Attempts = attempts; 17 | } 18 | 19 | /// 20 | /// Gets the number of attempts the client made to reconnect. 21 | /// 22 | public int Attempts { get; } 23 | } 24 | -------------------------------------------------------------------------------- /tests/Gel.Tests.Benchmarks/FullExecuteBenchmark.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using BenchmarkDotNet.Diagnostics.dotTrace; 3 | using Gel.Tests.Benchmarks.Utils; 4 | 5 | namespace Gel.Tests.Benchmarks; 6 | 7 | [DotTraceDiagnoser] 8 | public class FullExecuteBenchmark 9 | { 10 | public GelClientPool? ClientPool; 11 | 12 | [GlobalSetup] 13 | public void Setup() => 14 | ClientPool = new GelClientPool(new GelClientPoolConfig 15 | { 16 | ClientFactory = (id, c, cng) => 17 | { 18 | var client = new MockQueryClient(c, cng, null!, id); 19 | return ValueTask.FromResult(client); 20 | } 21 | }); 22 | 23 | [Benchmark] 24 | public Task> FullExecuteAsync() => 25 | ClientPool!.QueryAsync("select \"Hello, World!\""); 26 | } 27 | -------------------------------------------------------------------------------- /examples/Gel.Examples.CSharp/Examples/Transactions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | 3 | namespace Gel.ExampleApp.Examples; 4 | 5 | public class Transactions : IExample 6 | { 7 | public ILogger? Logger { get; set; } 8 | 9 | public async Task ExecuteAsync(GelClientPool clientPool) 10 | { 11 | // we can enter a transaction by calling TransactionAsync on a client. 12 | var str = await clientPool.TransactionAsync(async tx => 13 | { 14 | // inside our transaction we can preform queries using the 'tx' object. 15 | // ontop of this, anything we return in the transaction is returned by the 16 | // TransactionAsync function. 17 | return await tx.QueryRequiredSingleAsync("select \"Hello World!\""); 18 | }); 19 | 20 | Logger?.LogInformation("TransactionResult: {Result}", str); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Builders/Wrappers/NullableWrapper.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace Gel.Binary.Builders.Wrappers; 4 | 5 | internal sealed class NullableWrapper : IWrapper 6 | { 7 | private ConstructorInfo? _constructor; 8 | 9 | public Type GetInnerType(Type wrapperType) 10 | => wrapperType.GenericTypeArguments[0]; 11 | 12 | public bool IsWrapping(Type t) 13 | => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>); 14 | 15 | public object? Wrap(Type target, object? value) 16 | { 17 | if (value is null) 18 | return ReflectionUtils.GetDefault(target); 19 | 20 | return ( 21 | _constructor ??= target.GetConstructor(new[] {value.GetType()}) 22 | ?? throw new GelException($"Failed to find constructor for {target}") 23 | ).Invoke(new[] {value}); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/CompoundCodec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Codecs; 4 | 5 | internal class CompoundCodec : BaseCodec 6 | { 7 | private readonly ICodec[] _codecs; 8 | private readonly TypeOperation _operation; 9 | 10 | 11 | public CompoundCodec(in Guid id, TypeOperation operation, ICodec[] codecs, CodecMetadata? metadata = null) 12 | : base(in id, metadata) 13 | { 14 | _operation = operation; 15 | _codecs = codecs; 16 | } 17 | 18 | public override object? Deserialize(ref PacketReader reader, CodecContext context) => 19 | // TODO 20 | null!; 21 | 22 | 23 | public override void Serialize(ref PacketWriter writer, object? value, CodecContext context) 24 | { 25 | // TODO 26 | } 27 | 28 | public override string ToString() 29 | => "compound"; 30 | } 31 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Descriptors/EnumerationTypeDescriptor.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Descriptors; 2 | 3 | internal readonly struct EnumerationTypeDescriptor : ITypeDescriptor 4 | { 5 | public readonly Guid Id; 6 | 7 | public readonly string[] Members; 8 | 9 | public EnumerationTypeDescriptor(scoped in Guid id, scoped ref PacketReader reader) 10 | { 11 | Id = id; 12 | 13 | var count = reader.ReadUInt16(); 14 | 15 | var members = new string[count]; 16 | 17 | for (ushort i = 0; i != count; i++) 18 | { 19 | members[i] = reader.ReadString(); 20 | } 21 | 22 | Members = members; 23 | } 24 | 25 | unsafe ref readonly Guid ITypeDescriptor.Id 26 | { 27 | get 28 | { 29 | fixed (Guid* ptr = &Id) 30 | return ref *ptr; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V2.0/Descriptors/IMetadataDescriptor.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Protocol.V2._0.Descriptors; 4 | 5 | internal interface IMetadataDescriptor 6 | { 7 | static CodecAncestor[] ConstructAncestors(ushort[] ancestors, RelativeCodecDelegate relativeCodec, 8 | RelativeDescriptorDelegate relativeDescriptor) 9 | { 10 | var codecAncestors = new CodecAncestor[ancestors.Length]; 11 | 12 | for (var i = 0; i != ancestors.Length; i++) 13 | { 14 | codecAncestors[i] = new CodecAncestor( 15 | ref relativeCodec(in i), 16 | ref relativeDescriptor(in i) 17 | ); 18 | } 19 | 20 | return codecAncestors; 21 | } 22 | 23 | CodecMetadata? GetMetadata(RelativeCodecDelegate relativeCodec, RelativeDescriptorDelegate relativeDescriptor); 24 | } 25 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Descriptors/InputShapeDescriptor.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Descriptors; 2 | 3 | internal readonly struct InputShapeDescriptor : ITypeDescriptor 4 | { 5 | public readonly Guid Id; 6 | 7 | public readonly ShapeElement[] Shapes; 8 | 9 | public InputShapeDescriptor(scoped in Guid id, scoped ref PacketReader reader) 10 | { 11 | Id = id; 12 | 13 | var elementCount = reader.ReadUInt16(); 14 | 15 | var shapes = new ShapeElement[elementCount]; 16 | for (var i = 0; i != elementCount; i++) 17 | { 18 | shapes[i] = new ShapeElement(ref reader); 19 | } 20 | 21 | Shapes = shapes; 22 | } 23 | 24 | unsafe ref readonly Guid ITypeDescriptor.Id 25 | { 26 | get 27 | { 28 | fixed (Guid* ptr = &Id) 29 | return ref *ptr; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Descriptors/ObjectShapeDescriptor.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Descriptors; 2 | 3 | internal readonly struct ObjectShapeDescriptor : ITypeDescriptor 4 | { 5 | public readonly Guid Id; 6 | 7 | public readonly ShapeElement[] Shapes; 8 | 9 | public ObjectShapeDescriptor(scoped in Guid id, scoped ref PacketReader reader) 10 | { 11 | Id = id; 12 | 13 | var elementCount = reader.ReadUInt16(); 14 | 15 | var shapes = new ShapeElement[elementCount]; 16 | for (var i = 0; i != elementCount; i++) 17 | { 18 | shapes[i] = new ShapeElement(ref reader); 19 | } 20 | 21 | Shapes = shapes; 22 | } 23 | 24 | unsafe ref readonly Guid ITypeDescriptor.Id 25 | { 26 | get 27 | { 28 | fixed (Guid* ptr = &Id) 29 | return ref *ptr; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/Gel.Examples.CSharp/Examples/DumpAndRestore.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | 3 | namespace Gel.ExampleApp.Examples; 4 | 5 | public class DumpAndRestore : IExample 6 | { 7 | public ILogger? Logger { get; set; } 8 | 9 | public async Task ExecuteAsync(GelClientPool clientPool) 10 | { 11 | // dump the database to a stream; 12 | using var dumpStream = await clientPool.DumpDatabaseAsync().ConfigureAwait(false); 13 | 14 | // at this point you can write the stream to a file as a backup, 15 | // for this example we're just going to immediatly restore it. 16 | 17 | // since our database isn't empty we cannot restore it; but lets say it was empty, we could use the following code: 18 | // var result = await client.RestoreDatabaseAsync(dumpStream!).ConfigureAwait(false); 19 | // Logger?.LogInformation("Restore status: {Status}", result.Status); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/Common/Descriptors/CodecMetadata.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Codecs; 2 | 3 | namespace Gel.Binary.Protocol.Common.Descriptors; 4 | 5 | internal sealed class CodecMetadata 6 | { 7 | public CodecMetadata(string? schemaName, bool isSchemaDefined, CodecAncestor[]? ancestors = null) 8 | { 9 | SchemaName = schemaName; 10 | IsSchemaDefined = isSchemaDefined; 11 | Ancestors = ancestors ?? Array.Empty(); 12 | } 13 | 14 | public string? SchemaName { get; } 15 | 16 | public bool IsSchemaDefined { get; } 17 | 18 | public CodecAncestor[] Ancestors { get; } 19 | } 20 | 21 | internal struct CodecAncestor 22 | { 23 | public ICodec? Codec; 24 | public ITypeDescriptor Descriptor; 25 | 26 | public CodecAncestor(ref ICodec? codec, ref ITypeDescriptor descriptor) 27 | { 28 | Codec = codec; 29 | Descriptor = descriptor; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Receivables/ParameterStatus.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Packets; 2 | 3 | /// 4 | /// Represents the 5 | /// Parameter Status packet. 6 | /// 7 | internal readonly struct ParameterStatus : IReceiveable 8 | { 9 | /// 10 | public ServerMessageType Type 11 | => ServerMessageType.ParameterStatus; 12 | 13 | /// 14 | /// The name of the parameter. 15 | /// 16 | public readonly string Name; 17 | 18 | /// 19 | /// The value of the parameter. 20 | /// 21 | public readonly byte[] ValueBuffer; 22 | 23 | internal ParameterStatus(ref PacketReader reader) 24 | { 25 | Name = reader.ReadString(); 26 | ValueBuffer = reader.ReadByteArray(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/Gel.Examples.CSharp/Gel.Examples.CSharp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /examples/Gel.Examples.FSharp/Examples/CancelQueries.fs: -------------------------------------------------------------------------------- 1 | module CancelQueries 2 | 3 | open Examples 4 | open Gel 5 | open Microsoft.Extensions.Logging 6 | open System.Threading 7 | open System 8 | 9 | type CancelQueries() = 10 | interface IExample with 11 | member this.ExecuteAsync(clientPool: GelClientPool, logger: ILogger) = 12 | task { 13 | let tokenSource = new CancellationTokenSource() 14 | tokenSource.CancelAfter(TimeSpan.FromTicks(5)) 15 | 16 | try 17 | let! result = clientPool.QueryRequiredSingleAsync("select 'Hello, .NET'") 18 | result |> ignore 19 | with 20 | | :? OperationCanceledException -> logger.LogInformation("Got task cancelled exception") 21 | | e -> 22 | logger.LogError(e, "Got unexpected exception") 23 | raise e 24 | } 25 | -------------------------------------------------------------------------------- /tests/Gel.Tests.Benchmarks/PacketWritingBenchmark.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Tests.Benchmarks; 2 | 3 | 4 | // commented out because of internalization of sendables. 5 | 6 | //[MemoryDiagnoser] 7 | //public class PacketWritingBenchmark 8 | //{ 9 | // [Benchmark] 10 | // [ArgumentsSource(nameof(Packets))] 11 | // public Memory WritePacket(Sendable packet) 12 | // { 13 | // var p = new PacketWriter(packet.Size + 5); 14 | // packet!.Write(ref p, null!); 15 | // var data = p.GetBytes(); 16 | // p.Dispose(); 17 | // return data; 18 | // } 19 | 20 | // public IEnumerable Packets => new Sendable[] 21 | // { 22 | // new ClientHandshake() 23 | // { 24 | // MajorVersion = 1, 25 | // MinorVersion = 0, 26 | // Extensions = Array.Empty(), 27 | // ConnectionParameters = Array.Empty(), 28 | // } 29 | // }; 30 | //} 31 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | - push 5 | - pull_request 6 | 7 | jobs: 8 | test: 9 | runs-on: ubuntu-latest 10 | name: Run test suite 11 | 12 | steps: 13 | - uses: actions/checkout@v2 14 | with: 15 | submodules: true 16 | 17 | - name: Setup .NET 18 | uses: actions/setup-dotnet@v1 19 | with: 20 | dotnet-version: 8.0.x 21 | 22 | - uses: edgedb/setup-edgedb@v1 23 | with: 24 | server-version: stable 25 | instance-name: edgedb_dotnet_tests 26 | 27 | - run: edgedb instance list 28 | 29 | - name: Restore dependencies 30 | run: dotnet restore 31 | 32 | - name: Build 33 | run: dotnet build --no-restore 34 | 35 | - name: Unit test 36 | run: dotnet test ./tests/Gel.Tests.Unit --no-build --verbosity normal 37 | 38 | # - name: Integration Tests 39 | # run: dotnet test ./tests/Gel.Tests.Integration --no-build --verbosity diag 40 | -------------------------------------------------------------------------------- /examples/Gel.Examples.ExampleTODOApi/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:34550", 8 | "sslPort": 44351 9 | } 10 | }, 11 | "profiles": { 12 | "Gel.Examples.ExampleTODOApi": { 13 | "commandName": "Project", 14 | "launchBrowser": true, 15 | "launchUrl": "swagger", 16 | "applicationUrl": "https://localhost:7155;http://localhost:5155", 17 | "environmentVariables": { 18 | "ASPNETCORE_ENVIRONMENT": "Development" 19 | } 20 | }, 21 | "IIS Express": { 22 | "commandName": "IISExpress", 23 | "launchBrowser": true, 24 | "launchUrl": "swagger", 25 | "environmentVariables": { 26 | "ASPNETCORE_ENVIRONMENT": "Development" 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/Exceptions/ConnectionFailedTemporarilyException.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Sockets; 2 | 3 | namespace Gel; 4 | 5 | /// 6 | /// Represents a temporary connection failiure exception. 7 | /// 8 | public sealed class ConnectionFailedTemporarilyException : GelException 9 | { 10 | /// 11 | /// Constructs a new with the specified socket error. 12 | /// 13 | /// The underlying socket error that caused this exception to be thrown. 14 | public ConnectionFailedTemporarilyException(SocketError error) 15 | : base("The connection could not be established at this time", true, true) 16 | { 17 | SocketError = error; 18 | } 19 | 20 | /// 21 | /// Gets the socket error that caused the connection to fail. 22 | /// 23 | public SocketError SocketError { get; } 24 | } 25 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Descriptors/NamedTupleTypeDescriptor.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Protocol.V1._0.Descriptors; 4 | 5 | internal readonly struct NamedTupleTypeDescriptor : ITypeDescriptor 6 | { 7 | public readonly Guid Id; 8 | 9 | public readonly TupleElement[] Elements; 10 | 11 | public NamedTupleTypeDescriptor(scoped in Guid id, scoped ref PacketReader reader) 12 | { 13 | Id = id; 14 | 15 | var count = reader.ReadUInt16(); 16 | 17 | var elements = new TupleElement[count]; 18 | 19 | for (var i = 0; i != count; i++) 20 | { 21 | elements[i] = new TupleElement(ref reader); 22 | } 23 | 24 | Elements = elements; 25 | } 26 | 27 | unsafe ref readonly Guid ITypeDescriptor.Id 28 | { 29 | get 30 | { 31 | fixed (Guid* ptr = &Id) 32 | return ref *ptr; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Receivables/RestoreReady.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Packets; 2 | 3 | /// 4 | /// Represents the Restore Ready 5 | /// packet. 6 | /// 7 | internal readonly struct RestoreReady : IReceiveable 8 | { 9 | /// 10 | public ServerMessageType Type 11 | => ServerMessageType.RestoreReady; 12 | 13 | /// 14 | /// The number of jobs that the restore will use. 15 | /// 16 | public readonly ushort Jobs; 17 | 18 | /// 19 | /// A collection of annotations that was sent with this packet. 20 | /// 21 | public readonly Annotation[] Annotations; 22 | 23 | internal RestoreReady(ref PacketReader reader) 24 | { 25 | Annotations = reader.ReadAnnotations(); 26 | Jobs = reader.ReadUInt16(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.github/workflows/deploy-prerelease.yml: -------------------------------------------------------------------------------- 1 | name: NuGet Deploy (Prerelease) 2 | 3 | on: 4 | push: 5 | branches: [ dev ] 6 | 7 | env: 8 | BuildNumber: "${{ github.run_number }}" 9 | 10 | jobs: 11 | publish-prerelease: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: Setup .NET Core 16 | uses: actions/setup-dotnet@v1 17 | with: 18 | dotnet-version: '8.0.x' 19 | include-prerelease: true 20 | - name: Install dependencies 21 | run: dotnet restore 22 | - name: Build 23 | run: dotnet build src/Gel.Net.Driver/Gel.Net.Driver.csproj --configuration Release --no-restore 24 | - name: Pack 25 | run: dotnet pack src/Gel.Net.Driver/Gel.Net.Driver.csproj -c Release -o ./artifacts --no-build 26 | - name: Upload 27 | run: dotnet nuget push ./artifacts/Gel.Net.*.nupkg --api-key ${{ secrets.MYGET_GEL_NET }} --source https://www.myget.org/F/gel-net/api/v2/package -------------------------------------------------------------------------------- /.github/workflows/deploy-release.yml: -------------------------------------------------------------------------------- 1 | name: NuGet Deploy (Release) 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | env: 7 | IsTagBuild: 'true' 8 | BuildNumber: "${{ github.run_number }}" 9 | 10 | jobs: 11 | publish-release: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: Setup .NET Core 16 | uses: actions/setup-dotnet@v1 17 | with: 18 | dotnet-version: '8.0.x' 19 | include-prerelease: true 20 | - name: Install dependencies 21 | run: dotnet restore 22 | - name: Build 23 | run: dotnet build src/Gel.Net.Driver/Gel.Net.Driver.csproj --configuration Release --no-restore 24 | - name: Pack 25 | run: dotnet pack src/Gel.Net.Driver/Gel.Net.Driver.csproj -c Release -o ./artifacts --no-build 26 | - name: Upload 27 | run: dotnet nuget push ./artifacts/Gel.Net.*.nupkg --api-key ${{ secrets.MYGET_GEL_NET }} --source https://www.myget.org/F/gel-net/api/v2/package -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Common/KeyValue.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol; 2 | using System.Text; 3 | 4 | namespace Gel.Binary; 5 | 6 | /// 7 | /// Represents a dynamic key-value pair received in a . 8 | /// 9 | internal readonly struct KeyValue 10 | { 11 | /// 12 | /// Gets the key code. 13 | /// 14 | public readonly ushort Code; 15 | 16 | /// 17 | /// Gets the value stored within this keyvalue. 18 | /// 19 | public readonly byte[] Value; 20 | 21 | internal KeyValue(ushort code, byte[] value) 22 | { 23 | Code = code; 24 | Value = value; 25 | } 26 | 27 | /// 28 | /// Converts this headers value to a UTF8 encoded string 29 | /// 30 | public override string ToString() 31 | => Encoding.UTF8.GetString(Value); 32 | 33 | internal int ToInt() 34 | => int.Parse(ToString()); 35 | } 36 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/QueryParameters.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol; 2 | 3 | internal sealed class QueryParameters 4 | { 5 | public QueryParameters( 6 | string query, IDictionary? args, 7 | Capabilities capabilities, Cardinality cardinality, 8 | IOFormat format, bool implicitTypeNames) 9 | { 10 | Query = query; 11 | Arguments = args; 12 | Capabilities = capabilities; 13 | Cardinality = cardinality; 14 | Format = format; 15 | ImplicitTypeNames = implicitTypeNames; 16 | } 17 | 18 | public string Query { get; } 19 | public IDictionary? Arguments { get; } 20 | public Capabilities Capabilities { get; } 21 | public Cardinality Cardinality { get; } 22 | public IOFormat Format { get; } 23 | 24 | public bool ImplicitTypeNames { get; } 25 | 26 | public ulong GetCacheKey() => CodecBuilder.GetCacheHashKey(Query, Cardinality, Format); 27 | } 28 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Common/ProtocolExtension.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace Gel.Binary; 4 | 5 | /// 6 | /// Represents a protocol extension. 7 | /// 8 | internal readonly struct ProtocolExtension 9 | { 10 | internal int Size 11 | => Encoding.UTF8.GetByteCount(Name) + Annotations.Sum(x => x.Size); 12 | 13 | /// 14 | /// The name of the protocol extension. 15 | /// 16 | public readonly string Name; 17 | 18 | /// 19 | /// A collection of headers for this protocol extension. 20 | /// 21 | public readonly Annotation[] Annotations; 22 | 23 | internal ProtocolExtension(ref PacketReader reader) 24 | { 25 | Name = reader.ReadString(); 26 | Annotations = reader.ReadAnnotations(); 27 | } 28 | 29 | internal void Write(ref PacketWriter writer) 30 | { 31 | writer.Write(Name); 32 | writer.Write(Annotations); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Descriptors/ArrayTypeDescriptor.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Descriptors; 2 | 3 | internal readonly struct ArrayTypeDescriptor : ITypeDescriptor 4 | { 5 | public readonly Guid Id; 6 | 7 | public readonly ushort TypePos; 8 | 9 | public readonly uint[] Dimensions; 10 | 11 | public ArrayTypeDescriptor(scoped in Guid id, scoped ref PacketReader reader) 12 | { 13 | Id = id; 14 | 15 | TypePos = reader.ReadUInt16(); 16 | 17 | var count = reader.ReadUInt16(); 18 | 19 | var dimensions = new uint[count]; 20 | 21 | for (var i = 0; i != count; i++) 22 | { 23 | dimensions[i] = reader.ReadUInt32(); 24 | } 25 | 26 | Dimensions = dimensions; 27 | } 28 | 29 | unsafe ref readonly Guid ITypeDescriptor.Id 30 | { 31 | get 32 | { 33 | fixed (Guid* ptr = &Id) 34 | return ref *ptr; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/Gel.Tests.Unit/Gel.Tests.Unit.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | 7 | false 8 | 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | PreserveNewest 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/TextCodec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | using System.Text; 3 | 4 | namespace Gel.Binary.Codecs; 5 | 6 | internal class TextCodec 7 | : BaseScalarCodec 8 | { 9 | public new static readonly Guid Id = Guid.Parse("00000000-0000-0000-0000-000000000101"); 10 | 11 | public TextCodec(CodecMetadata? metadata = null) 12 | : base(in Id, metadata) 13 | { 14 | } 15 | 16 | protected TextCodec(in Guid id, CodecMetadata? metadata = null) 17 | : base(in id, metadata) 18 | { 19 | } 20 | 21 | public override string Deserialize(ref PacketReader reader, CodecContext context) => reader.ConsumeString(); 22 | 23 | public override void Serialize(ref PacketWriter writer, string? value, CodecContext context) 24 | { 25 | if (value is not null) 26 | writer.Write(Encoding.UTF8.GetBytes(value)); 27 | } 28 | 29 | public override string ToString() 30 | => "std::str"; 31 | } 32 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/NullCodec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Codecs; 4 | 5 | internal sealed class NullCodec 6 | : ICodec, IArgumentCodec, ICacheableCodec 7 | { 8 | public NullCodec() { } 9 | 10 | public NullCodec(CodecMetadata? metadata = null) { } // used in generic codec construction 11 | 12 | public void SerializeArguments(ref PacketWriter writer, object? value, ArgumentCodecContext context) { } 13 | 14 | public Guid Id 15 | => Guid.Empty; 16 | 17 | public CodecMetadata? Metadata 18 | => null; 19 | 20 | public Type ConverterType => typeof(object); 21 | 22 | public bool CanConvert(Type t) => true; 23 | 24 | public object? Deserialize(ref PacketReader reader, CodecContext context) => null; 25 | 26 | public void Serialize(ref PacketWriter writer, object? value, CodecContext context) => writer.Write(0); 27 | 28 | public override string ToString() 29 | => "null_codec"; 30 | } 31 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V2.0/Descriptors/InputShapeDescriptor.cs: -------------------------------------------------------------------------------- 1 | using InputShapeElement = Gel.Binary.Protocol.V1._0.Descriptors.ShapeElement; 2 | 3 | namespace Gel.Binary.Protocol.V2._0.Descriptors; 4 | 5 | internal readonly struct InputShapeDescriptor : ITypeDescriptor 6 | { 7 | public readonly Guid Id; 8 | 9 | public readonly InputShapeElement[] Elements; 10 | 11 | public InputShapeDescriptor(ref PacketReader reader, in Guid id) 12 | { 13 | Id = id; 14 | 15 | var elementCount = reader.ReadUInt16(); 16 | var elements = new InputShapeElement[elementCount]; 17 | 18 | for (var i = 0; i != elementCount; i++) 19 | { 20 | elements[i] = new InputShapeElement(ref reader); 21 | } 22 | 23 | Elements = elements; 24 | } 25 | 26 | unsafe ref readonly Guid ITypeDescriptor.Id 27 | { 28 | get 29 | { 30 | fixed (Guid* ptr = &Id) 31 | return ref *ptr; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V2.0/Descriptors/ObjectTypeDescriptor.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Protocol.V2._0.Descriptors; 4 | 5 | internal readonly struct ObjectTypeDescriptor : ITypeDescriptor, IMetadataDescriptor 6 | { 7 | public readonly Guid Id; 8 | 9 | public readonly string Name; 10 | 11 | public readonly bool IsSchemaDefined; 12 | 13 | public ObjectTypeDescriptor(ref PacketReader reader, in Guid id) 14 | { 15 | Id = id; 16 | 17 | Name = reader.ReadString(); 18 | IsSchemaDefined = reader.ReadBoolean(); 19 | } 20 | 21 | unsafe ref readonly Guid ITypeDescriptor.Id 22 | { 23 | get 24 | { 25 | fixed (Guid* ptr = &Id) 26 | return ref *ptr; 27 | } 28 | } 29 | 30 | public CodecMetadata? GetMetadata(RelativeCodecDelegate relativeCodec, 31 | RelativeDescriptorDelegate relativeDescriptor) 32 | => new(Name, IsSchemaDefined); 33 | } 34 | -------------------------------------------------------------------------------- /tests/Gel.Tests.Integration/ClientProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace Gel.Tests.Integration; 5 | 6 | internal class ClientProvider 7 | { 8 | public static GelClientPool ClientPool 9 | => new(new GelClientPoolConfig {SchemaNamingStrategy = INamingStrategy.SnakeCaseNamingStrategy}); 10 | 11 | public static GelClientPool HttpClientPool 12 | => new(new GelClientPoolConfig 13 | { 14 | SchemaNamingStrategy = INamingStrategy.SnakeCaseNamingStrategy, ClientType = GelClientType.Http 15 | }); 16 | 17 | public static GelClientPool ConfigureClient(Action conf) 18 | { 19 | var config = new GelClientPoolConfig(); 20 | conf(config); 21 | return new GelClientPool(config); 22 | } 23 | 24 | public static CancellationToken GetTimeoutToken() 25 | { 26 | var source = new CancellationTokenSource(); 27 | source.CancelAfter(10000); 28 | return source.Token; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/Sendable.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol; 2 | 3 | internal abstract class Sendable 4 | { 5 | public abstract int Size { get; } 6 | 7 | public abstract ClientMessageTypes Type { get; } 8 | 9 | protected abstract void BuildPacket(ref PacketWriter writer); 10 | 11 | public void Write(ref PacketWriter writer) 12 | { 13 | // advance 5 bytes 14 | var start = writer.Index; 15 | writer.Advance(5); 16 | 17 | // write the body of the packet 18 | BuildPacket(ref writer); 19 | 20 | // store the index after writing the body 21 | var eofPosition = writer.Index; 22 | 23 | // seek back to the beginning. 24 | writer.SeekToIndex(start); 25 | 26 | // write the type and size 27 | writer.Write((sbyte)Type); 28 | writer.Write((uint)Size + 4); 29 | 30 | // go back to eof 31 | writer.SeekToIndex(eofPosition); 32 | } 33 | 34 | public int GetSize() 35 | => Size + 5; 36 | } 37 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Descriptors/TupleTypeDescriptor.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Descriptors; 2 | 3 | internal readonly struct TupleTypeDescriptor : ITypeDescriptor 4 | { 5 | public readonly Guid Id; 6 | 7 | public bool IsEmpty 8 | => Id.ToString() == "00000000-0000-0000-0000-0000000000FF"; 9 | 10 | public readonly ushort[] ElementTypeDescriptorsIndex; 11 | 12 | public TupleTypeDescriptor(scoped in Guid id, scoped ref PacketReader reader) 13 | { 14 | Id = id; 15 | var count = reader.ReadUInt16(); 16 | 17 | var elements = new ushort[count]; 18 | 19 | for (var i = 0; i != count; i++) 20 | { 21 | elements[i] = reader.ReadUInt16(); 22 | } 23 | 24 | ElementTypeDescriptorsIndex = elements; 25 | } 26 | 27 | unsafe ref readonly Guid ITypeDescriptor.Id 28 | { 29 | get 30 | { 31 | fixed (Guid* ptr = &Id) 32 | return ref *ptr; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Impl/BaseCodec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Codecs; 4 | 5 | internal abstract class BaseCodec : ICodec 6 | { 7 | protected BaseCodec(in Guid id, CodecMetadata? metadata) 8 | { 9 | Metadata = metadata; 10 | Id = id; 11 | } 12 | 13 | public virtual Guid Id { get; } 14 | public virtual Type ConverterType => typeof(T); 15 | public virtual CodecMetadata? Metadata { get; } 16 | 17 | public abstract void Serialize(ref PacketWriter writer, T? value, CodecContext context); 18 | public abstract T? Deserialize(ref PacketReader reader, CodecContext context); 19 | 20 | public virtual bool CanConvert(Type t) => typeof(T) == t; 21 | 22 | void ICodec.Serialize(ref PacketWriter writer, object? value, CodecContext context) => 23 | Serialize(ref writer, (T?)value, context); 24 | 25 | object? ICodec.Deserialize(ref PacketReader reader, CodecContext context) => Deserialize(ref reader, context); 26 | } 27 | -------------------------------------------------------------------------------- /tools/Gel.DotnetTool/Gel.DotnetTool.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | True 12 | 5 13 | 14 | 15 | 16 | True 17 | 5 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/DumpRestore/V1.0/DumpState.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.V1._0.Packets; 2 | 3 | namespace Gel.Binary.Protocol.DumpRestore.V1._0; 4 | 5 | internal sealed class DumpState 6 | { 7 | private readonly Stream _stream; 8 | 9 | public DumpState(Stream stream) 10 | { 11 | _stream = stream; 12 | } 13 | 14 | public ValueTask WriteHeaderAsync(in DumpHeader header) 15 | { 16 | var writer = new PacketWriter(); 17 | writer.Write('H'); 18 | writer.Write(header.Hash.ToArray()); 19 | writer.Write(header.Length); 20 | writer.Write(header.Raw); 21 | return _stream.WriteAsync(writer.GetBytes()); 22 | } 23 | 24 | public ValueTask WriteBlockAsync(in DumpBlock block) 25 | { 26 | var writer = new PacketWriter(); 27 | writer.Write('D'); 28 | writer.Write(block.HashBuffer); 29 | writer.Write(block.Length); 30 | writer.Write(block.Raw); 31 | return _stream.WriteAsync(writer.GetBytes()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Receivables/ReadyForCommand.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Packets; 2 | 3 | /// 4 | /// Represents the 5 | /// Ready for Command packet. 6 | /// 7 | internal readonly struct ReadyForCommand : IReceiveable 8 | { 9 | /// 10 | public ServerMessageType Type 11 | => ServerMessageType.ReadyForCommand; 12 | 13 | /// 14 | /// The transaction state of the next command. 15 | /// 16 | public readonly TransactionState TransactionState; 17 | 18 | /// 19 | /// A collection of annotations sent with this prepare packet. 20 | /// 21 | public readonly Annotation[] Annotations; 22 | 23 | internal ReadyForCommand(ref PacketReader reader) 24 | { 25 | Annotations = reader.ReadAnnotations(); 26 | TransactionState = (TransactionState)reader.ReadByte(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Sendables/AuthenticationSASLInitialResponse.cs: -------------------------------------------------------------------------------- 1 | using Gel.Utils; 2 | using System.Text; 3 | 4 | namespace Gel.Binary.Protocol.V1._0.Packets; 5 | 6 | internal sealed class AuthenticationSASLInitialResponse : Sendable 7 | { 8 | public AuthenticationSASLInitialResponse(ReadOnlyMemory payload, string method) 9 | { 10 | Method = method; 11 | Payload = payload; 12 | } 13 | 14 | public override ClientMessageTypes Type 15 | => ClientMessageTypes.AuthenticationSASLInitialResponse; 16 | 17 | public override int Size 18 | => BinaryUtils.SizeOfString(Method) + BinaryUtils.SizeOfByteArray(Payload); 19 | 20 | public string Method { get; set; } 21 | 22 | public ReadOnlyMemory Payload { get; set; } 23 | 24 | protected override void BuildPacket(ref PacketWriter writer) 25 | { 26 | writer.Write(Method); 27 | writer.WriteArray(Payload); 28 | } 29 | 30 | public override string ToString() => $"{Method} {Encoding.UTF8.GetString(Payload.Span)}"; 31 | } 32 | -------------------------------------------------------------------------------- /examples/Gel.Examples.FSharp/Program.fs: -------------------------------------------------------------------------------- 1 | open ExampleRunner 2 | open Serilog 3 | open Microsoft.Extensions.Hosting 4 | open Microsoft.Extensions.DependencyInjection 5 | open Microsoft.Extensions.Logging 6 | open Gel 7 | 8 | Log.Logger <- 9 | LoggerConfiguration() 10 | .Enrich.FromLogContext() 11 | .MinimumLevel.Debug() 12 | .WriteTo.Console(outputTemplate = "{Timestamp:HH:mm:ss} - {Level}: {Message:lj}{NewLine}{Exception}") 13 | .CreateLogger() 14 | 15 | let host = 16 | Host 17 | .CreateDefaultBuilder() 18 | .ConfigureServices(fun services -> 19 | services 20 | .AddLogging(fun logBuilder -> logBuilder.ClearProviders().AddSerilog(dispose = true) |> ignore) 21 | .AddGel(clientPoolConfig = fun c -> c.SchemaNamingStrategy <- INamingStrategy.SnakeCaseNamingStrategy) 22 | .AddSingleton() 23 | |> ignore) 24 | .Build() 25 | 26 | host.Services.GetRequiredService().RunAsync() 27 | |> Async.AwaitTask 28 | |> Async.RunSynchronously 29 | -------------------------------------------------------------------------------- /dbschema/migrations/00013.edgeql: -------------------------------------------------------------------------------- 1 | CREATE MIGRATION m1xgcfneyhgejgvqtk3e46njjnngnxdwqeq3jh5idjfjhjxppfv5ya 2 | ONTO m1qobo3k5z5dg56j3vymsaktqjnff5uv4ndpytjpqfwkda7lxinllq 3 | { 4 | CREATE MODULE tests IF NOT EXISTS; 5 | CREATE TYPE tests::ScalarContainer { 6 | CREATE PROPERTY a: std::int16; 7 | CREATE PROPERTY b: std::int32; 8 | CREATE PROPERTY c: std::int64; 9 | CREATE PROPERTY d: std::str; 10 | CREATE PROPERTY e: std::bool; 11 | CREATE PROPERTY f: std::float32; 12 | CREATE PROPERTY g: std::float64; 13 | CREATE PROPERTY h: std::bigint; 14 | CREATE PROPERTY i: std::decimal; 15 | CREATE PROPERTY j: std::uuid; 16 | CREATE PROPERTY k: std::json; 17 | CREATE PROPERTY l: std::datetime; 18 | CREATE PROPERTY m: cal::local_datetime; 19 | CREATE PROPERTY n: cal::local_date; 20 | CREATE PROPERTY o: cal::local_time; 21 | CREATE PROPERTY p: std::duration; 22 | CREATE PROPERTY q: cal::relative_duration; 23 | CREATE PROPERTY r: cal::date_duration; 24 | CREATE PROPERTY s: std::bytes; 25 | }; 26 | }; 27 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Temporal/LocalDateCodec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | using Gel.DataTypes; 3 | 4 | namespace Gel.Binary.Codecs; 5 | 6 | internal sealed class LocalDateCodec : BaseTemporalCodec 7 | { 8 | public new static Guid Id = Guid.Parse("00000000-0000-0000-0000-000000000112"); 9 | 10 | public LocalDateCodec(CodecMetadata? metadata = null) 11 | : base(in Id, metadata) 12 | { 13 | AddConverter(From, To); 14 | } 15 | 16 | public override LocalDate Deserialize(ref PacketReader reader, CodecContext context) 17 | { 18 | var days = reader.ReadInt32(); 19 | 20 | return new LocalDate(days); 21 | } 22 | 23 | public override void Serialize(ref PacketWriter writer, LocalDate value, CodecContext context) => 24 | writer.Write(value.Days); 25 | 26 | private LocalDate From(ref DateOnly value) 27 | => new(value); 28 | 29 | private DateOnly To(ref LocalDate value) 30 | => value.DateOnly; 31 | 32 | public override string ToString() 33 | => "cal::local_date"; 34 | } 35 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/JsonCodec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | using Gel.DataTypes; 3 | using System.Text; 4 | 5 | namespace Gel.Binary.Codecs; 6 | 7 | internal sealed class JsonCodec 8 | : BaseScalarCodec 9 | { 10 | public new static readonly Guid Id = Guid.Parse("00000000-0000-0000-0000-00000000010F"); 11 | 12 | public JsonCodec(CodecMetadata? metadata = null) 13 | : base(in Id, metadata) 14 | { 15 | } 16 | 17 | public override Json Deserialize(ref PacketReader reader, CodecContext context) 18 | { 19 | // format (unused) 20 | reader.Skip(1); 21 | 22 | var data = Encoding.UTF8.GetString(reader.ConsumeByteArray()); 23 | 24 | return new Json(data); 25 | } 26 | 27 | public override void Serialize(ref PacketWriter writer, Json value, CodecContext context) 28 | { 29 | var jsonData = Encoding.UTF8.GetBytes(value.Value ?? ""); 30 | 31 | writer.Write((byte)0x01); 32 | writer.Write(jsonData); 33 | } 34 | 35 | public override string ToString() 36 | => "std::json"; 37 | } 38 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Utils/JsonUtils.cs: -------------------------------------------------------------------------------- 1 | using Gel.DataTypes; 2 | using Newtonsoft.Json; 3 | 4 | namespace Gel.Utils; 5 | 6 | internal class AsStringConverter : JsonConverter 7 | { 8 | // Always reads numbers as strings 9 | 10 | public override string? ReadJson( 11 | JsonReader reader, 12 | Type objectType, 13 | string? existingValue, 14 | bool hasExistingValue, 15 | JsonSerializer serializer) 16 | { 17 | if (reader.TokenType == JsonToken.Integer) 18 | { 19 | return reader.Value!.ToString(); 20 | } 21 | else if (reader.TokenType == JsonToken.Float) 22 | { 23 | return reader.Value!.ToString(); 24 | } 25 | else if (reader.TokenType == JsonToken.String) 26 | { 27 | return (string)reader.Value!; 28 | } 29 | throw new JsonException("Expected Number or String."); 30 | } 31 | 32 | public override void WriteJson( 33 | JsonWriter writer, string? value, JsonSerializer serializer) 34 | { 35 | throw new NotImplementedException(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/Gel.Tests.Benchmarks/ClientPoolBenchmarks.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | 3 | namespace Gel.Tests.Benchmarks; 4 | 5 | public class ClientPoolBenchmarks 6 | { 7 | internal static MockedGelClient SingleClient; 8 | internal static GelClientPool ClientPool; 9 | 10 | static ClientPoolBenchmarks() 11 | { 12 | SingleClient = new MockedGelClient(0); 13 | ClientPool = new GelClientPool(new GelClientPoolConfig 14 | { 15 | ClientType = GelClientType.Custom, 16 | ClientFactory = (id, _, _) => ValueTask.FromResult(new MockedGelClient(id)), 17 | DefaultPoolSize = 100 18 | }); 19 | } 20 | 21 | // benchmark our default client as overhead 22 | [Benchmark] 23 | public async Task BenchmarkQueryOverhead() => 24 | await SingleClient.QueryAsync("select \"Hello, World!\"").ConfigureAwait(false); 25 | 26 | // define our main benchmark 27 | [Benchmark] 28 | public async Task BenchmarkQuery() => 29 | await ClientPool!.QueryAsync("select \"Hello, World!\"").ConfigureAwait(false); 30 | } 31 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V2.0/Descriptors/ObjectOutputShapeDescriptor.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V2._0.Descriptors; 2 | 3 | internal readonly struct ObjectOutputShapeDescriptor : ITypeDescriptor 4 | { 5 | public readonly Guid Id; 6 | 7 | public readonly bool IsEphemeralFreeShape; 8 | 9 | public readonly ushort Type; 10 | 11 | public readonly ShapeElement[] Elements; 12 | 13 | public ObjectOutputShapeDescriptor(ref PacketReader reader, in Guid id) 14 | { 15 | Id = id; 16 | IsEphemeralFreeShape = reader.ReadBoolean(); 17 | Type = reader.ReadUInt16(); 18 | 19 | var elementCount = reader.ReadUInt16(); 20 | var elements = new ShapeElement[elementCount]; 21 | 22 | for (var i = 0; i != elementCount; i++) 23 | { 24 | elements[i] = new ShapeElement(ref reader); 25 | } 26 | 27 | Elements = elements; 28 | } 29 | 30 | unsafe ref readonly Guid ITypeDescriptor.Id 31 | { 32 | get 33 | { 34 | fixed (Guid* ptr = &Id) 35 | return ref *ptr; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tests/Gel.Tests.Integration/Extensions/TemporalExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Gel.Tests.Integration; 4 | 5 | internal static class TemporalExtensions 6 | { 7 | public static TimeSpan RoundToMicroseconds(this TimeSpan t) => 8 | TimeSpan.FromMicroseconds(Math.Round(t.TotalMicroseconds)); 9 | 10 | public static DateTime RoundToMicroseconds(this DateTime t) 11 | { 12 | // divide by 10 to cut off 100-nanosecond component 13 | var microseconds = Math.Round(t.Ticks / 10d); 14 | 15 | var a = t.AddMicroseconds(Math.Round(microseconds) != microseconds ? 1 : 0); 16 | 17 | var r = new DateTime(a.Year, a.Month, a.Day, a.Hour, a.Minute, a.Second, a.Millisecond, a.Microsecond); 18 | 19 | return r; 20 | } 21 | 22 | public static DateTimeOffset RoundToMicroseconds(this DateTimeOffset t) => 23 | // divide by 10 to cut off 100-nanosecond component 24 | new(t.Ticks / 10, t.Offset); 25 | 26 | public static TimeOnly RoundToMicroseconds(this TimeOnly t) => 27 | // divide by 10 to cut off 100-nanosecond component 28 | new(t.Ticks / 10); 29 | } 30 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/Isolation.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | /// 4 | /// An enum representing the transaction mode within a . 5 | /// 6 | public enum Isolation 7 | { 8 | /// 9 | /// All statements of the current transaction can only see data changes 10 | /// committed before the first query or data-modification statement was 11 | /// executed in this transaction. If a pattern of reads and writes among 12 | /// concurrent serializable transactions would create a situation which 13 | /// could not have occurred for any serial (one-at-a-time) execution of 14 | /// those transactions, one of them will be rolled back with a serialization_failure error. 15 | /// 16 | Serializable, 17 | 18 | /// 19 | /// All statements of the current transaction can only see data committed 20 | /// before the first query or data-modification statement was executed in 21 | /// this transaction. 22 | /// 23 | [Obsolete("Gel 1.3>= no longer supports this", true)] 24 | RepeatableRead 25 | } 26 | -------------------------------------------------------------------------------- /tools/Gel.DotnetTool/Schemas/Models/Property.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.DotnetTool; 2 | 3 | internal class Property 4 | { 5 | public Type? Parent { get; set; } 6 | 7 | public string? Name { get; set; } 8 | 9 | public string? Type { get; set; } 10 | 11 | public bool Required { get; set; } 12 | 13 | public PropertyCardinality Cardinality { get; set; } 14 | 15 | public string? DefaultValue { get; set; } 16 | 17 | public bool ReadOnly { get; set; } 18 | 19 | public List Constraints { get; set; } = new(); 20 | 21 | public Annotation? Annotation { get; set; } 22 | 23 | public List LinkProperties { get; set; } = new(); 24 | 25 | public bool IsStrictlyConstraint { get; set; } 26 | 27 | public bool IsAbstract { get; set; } 28 | 29 | public bool IsLink { get; set; } 30 | 31 | public bool IsComputed { get; set; } 32 | 33 | public string? ComputedValue { get; set; } 34 | 35 | public string? Extending { get; set; } 36 | 37 | // used for builder 38 | public string? BuiltName { get; set; } 39 | } 40 | 41 | public enum PropertyCardinality 42 | { 43 | One, 44 | Multi 45 | } 46 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/EnumerationCodec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Codecs; 4 | 5 | internal sealed class EnumerationCodec : TextCodec 6 | { 7 | public readonly string[] Members; 8 | 9 | public EnumerationCodec(in Guid id, string[] members, CodecMetadata? metadata = null) 10 | : base(in id, metadata) 11 | { 12 | Members = members; 13 | } 14 | 15 | public override void Serialize(ref PacketWriter writer, string? value, CodecContext context) 16 | { 17 | if (!Members.Contains(value)) 18 | throw new ArgumentException("Value is not a member of this enumeration"); 19 | 20 | base.Serialize(ref writer, value, context); 21 | } 22 | 23 | public override string Deserialize(ref PacketReader reader, CodecContext context) 24 | { 25 | var value = base.Deserialize(ref reader, context); 26 | 27 | if (!Members.Contains(value)) 28 | throw new ArgumentException("Value is not a member of this enumeration"); 29 | 30 | return value; 31 | } 32 | 33 | public override string ToString() 34 | => "std::enum"; 35 | } 36 | -------------------------------------------------------------------------------- /tools/Gel.DocGenerator/Extensions/TypeExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | 3 | namespace Gel.DocGenerator; 4 | 5 | public static class TypeExtensions 6 | { 7 | public static string ToFormattedString(this Type type, bool includeParents = false) 8 | { 9 | var name = type.Name switch 10 | { 11 | "String" => "string", 12 | "Int16" => "short", 13 | "Int32" => "int", 14 | "Int64" => "long", 15 | "Boolean" => "bool", 16 | "Object" => "object", 17 | "Void" => "void", 18 | "Byte" => "byte", 19 | "SByte" => "sbyte", 20 | "UInt16" => "ushort", 21 | "UInt32" => "uint", 22 | "UInt64" => "ulong", 23 | "Char" => "char", 24 | "Decimal" => "decimal", 25 | "Double" => "double", 26 | "Single" => "float", 27 | _ => includeParents ? type.FullName ?? type.Name : type.Name 28 | }; 29 | 30 | return Regex.Replace(name, @"`\d+", 31 | m => $"<{string.Join(", ", type.GetGenericArguments().Select(t => t.ToFormattedString()))}>"); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/Capabilities.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | /// 4 | /// Represents a bitfield of capabilities used when executing queries. 5 | /// 6 | [Flags] 7 | public enum Capabilities : ulong 8 | { 9 | /// 10 | /// The default value for capabilities. 11 | /// 12 | ReadOnly = 0, 13 | 14 | /// 15 | /// The query is not read only. 16 | /// 17 | Modifications = 1 << 0, 18 | 19 | /// 20 | /// The query contains session config changes. 21 | /// 22 | SessionConfig = 1 << 1, 23 | 24 | /// 25 | /// The query contains transaction manipulations. 26 | /// 27 | Transaction = 1 << 2, 28 | 29 | /// 30 | /// The query contains DDL. 31 | /// 32 | DDL = 1 << 3, 33 | 34 | /// 35 | /// The command changes server or database configs. 36 | /// 37 | PersistantConfig = 1 << 4, 38 | 39 | /// 40 | /// Represents all capabilities except 41 | /// 42 | All = 0xffffffffffffffff 43 | } 44 | -------------------------------------------------------------------------------- /tests/Gel.Tests.Integration/ErrorFormatTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using System; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | 6 | namespace Gel.Tests.Integration; 7 | 8 | [TestClass] 9 | public class ErrorFormatTests 10 | { 11 | private readonly GelClientPool _clientPool; 12 | private readonly Func _getToken; 13 | 14 | public ErrorFormatTests() 15 | { 16 | _clientPool = ClientProvider.ClientPool; 17 | _getToken = () => ClientProvider.GetTimeoutToken(); 18 | } 19 | 20 | [TestMethod] 21 | public async Task TestErrorFormat() 22 | { 23 | var exception = await Assert.ThrowsExceptionAsync(async () => 24 | { 25 | await _clientPool.QueryAsync("select {\n ver := sys::get_version(),\n unknown := .abc,\n};", 26 | token: _getToken()); 27 | }); 28 | 29 | Assert.AreEqual( 30 | "InvalidReferenceError: object type 'std::FreeObject' has no link or property 'abc'\n |\n 3 | unknown := .abc,\n | ^^^^\n", 31 | exception.ToString()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/Gel.Examples.CSharp/Program.cs: -------------------------------------------------------------------------------- 1 | using Gel; 2 | using Gel.ExampleApp; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.Extensions.Hosting; 5 | using Microsoft.Extensions.Logging; 6 | using Serilog; 7 | 8 | Log.Logger = new LoggerConfiguration() 9 | .Enrich.FromLogContext() 10 | .MinimumLevel.Verbose() 11 | .WriteTo.Console(outputTemplate: "{Timestamp:HH:mm:ss} - {Level}: {Message:lj}{NewLine}{Exception}") 12 | .CreateLogger(); 13 | 14 | using var host = Host.CreateDefaultBuilder() 15 | .ConfigureServices(services => 16 | { 17 | services.AddLogging(loggingBuilder => 18 | { 19 | loggingBuilder.ClearProviders(); 20 | loggingBuilder.AddSerilog(dispose: true); 21 | }); 22 | 23 | services.AddGel(clientPoolConfig: clientConfig => 24 | { 25 | clientConfig.SchemaNamingStrategy = INamingStrategy.SnakeCaseNamingStrategy; 26 | clientConfig.ClientType = GelClientType.Tcp; 27 | }); 28 | 29 | services.AddSingleton(); 30 | }).Build(); 31 | 32 | await host.Services.GetRequiredService().StartAsync(); 33 | 34 | // hault the program 35 | await Task.Delay(-1); 36 | -------------------------------------------------------------------------------- /tests/Gel.Tests.Integration/Extensions/IEnumerableExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | 6 | namespace Gel.Tests.Integration; 7 | 8 | internal static class IEnumerableExtensions 9 | { 10 | public static bool ReflectionSequenceEqual(this IEnumerable left, IEnumerable right) 11 | { 12 | var gLeft = left.GetType() 13 | .GetInterfaces() 14 | .FirstOrDefault(x => x.Name == "IEnumerable`1") 15 | ?.GenericTypeArguments[0]; 16 | 17 | var gRight = right.GetType() 18 | .GetInterfaces() 19 | .FirstOrDefault(x => x.Name == "IEnumerable`1") 20 | ?.GenericTypeArguments[0]; 21 | 22 | if (gLeft is null || gRight is null || gLeft != gRight) 23 | return false; 24 | 25 | return (bool)typeof(IEnumerableExtensions) 26 | .GetMethod("Compare", BindingFlags.Static | BindingFlags.NonPublic)! 27 | .MakeGenericMethod(gLeft) 28 | .Invoke(null, new object[] {left, right})!; 29 | } 30 | 31 | private static bool Compare(IEnumerable l, IEnumerable r) 32 | => l.SequenceEqual(r); 33 | } 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report a bug in the client library API 4 | title: "" 5 | labels: "" 6 | assignees: "" 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **Reproduction** 13 | Include the code that is causing the error: 14 | 15 | ```csharp 16 | // code here 17 | ``` 18 | 19 | **Expected behavior** 20 | A clear and concise description of what you expected to happen. If applicable, add screenshots to help explain your problem. 21 | 22 | **Versions (please complete the following information):** 23 | 24 | 30 | 31 | - OS: 32 | - Gel version: 33 | - Gel CLI version: 34 | - `gel-net` version: 35 | - .NET version: 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Sendables/ClientHandshake.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Packets; 2 | 3 | internal sealed class ClientHandshake : Sendable 4 | { 5 | public override ClientMessageTypes Type => ClientMessageTypes.ClientHandshake; 6 | 7 | public override int Size => 8 | (sizeof(short) << 2) + ConnectionParameters.Sum(x => x.Size) + Extensions.Sum(x => x.Size); 9 | 10 | 11 | public ushort MajorVersion { get; set; } 12 | public ushort MinorVersion { get; set; } 13 | public ConnectionParam[] ConnectionParameters { get; set; } = Array.Empty(); 14 | public ProtocolExtension[] Extensions { get; set; } = Array.Empty(); 15 | 16 | protected override void BuildPacket(ref PacketWriter writer) 17 | { 18 | writer.Write(MajorVersion); 19 | writer.Write(MinorVersion); 20 | 21 | writer.Write((ushort)ConnectionParameters.Length); 22 | foreach (var param in ConnectionParameters) 23 | { 24 | param.Write(ref writer); 25 | } 26 | 27 | writer.Write((ushort)Extensions.Length); 28 | foreach (var extension in Extensions) 29 | { 30 | extension.Write(ref writer); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/Gel.Examples.CSharp/IExample.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | 3 | namespace Gel.ExampleApp; 4 | 5 | public interface IExample 6 | { 7 | ILogger? Logger { get; set; } 8 | 9 | Task ExecuteAsync(GelClientPool clientPool); 10 | 11 | static async Task ExecuteAllAsync(GelClientPool clientPool, ILogger logger, ILoggerFactory factory) 12 | { 13 | var examples = typeof(IExample).Assembly.GetTypes() 14 | .Where(x => x.IsAssignableTo(typeof(IExample)) && x != typeof(IExample)); 15 | 16 | foreach (var example in examples) 17 | { 18 | logger.LogInformation("Running {example}..", $"{example.Name}.cs"); 19 | try 20 | { 21 | var inst = (IExample)Activator.CreateInstance(example)!; 22 | inst.Logger = factory.CreateLogger(example.Name); 23 | await inst.ExecuteAsync(clientPool).ConfigureAwait(false); 24 | logger.LogInformation("{example} complete!", $"{example.Name}.cs"); 25 | } 26 | catch (Exception x) 27 | { 28 | logger.LogError(x, "Example {example} failed", $"{example.Name}.cs"); 29 | } 30 | } 31 | 32 | logger.LogInformation("Examples complete!"); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Temporal/DurationCodec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | using Gel.DataTypes; 3 | 4 | namespace Gel.Binary.Codecs; 5 | 6 | internal sealed class DurationCodec : BaseTemporalCodec 7 | { 8 | public new static Guid Id = Guid.Parse("00000000-0000-0000-0000-000000000112"); 9 | 10 | public DurationCodec(CodecMetadata? metadata = null) 11 | : base(in Id, metadata) 12 | { 13 | AddConverter(From, To); 14 | } 15 | 16 | public override Duration Deserialize(ref PacketReader reader, CodecContext context) 17 | { 18 | var microseconds = reader.ReadInt64(); 19 | 20 | // skip days and months 21 | reader.Skip(sizeof(int) + sizeof(int)); 22 | 23 | return new Duration(microseconds); 24 | } 25 | 26 | public override void Serialize(ref PacketWriter writer, Duration value, CodecContext context) 27 | { 28 | writer.Write(value.Microseconds); 29 | writer.Write(0); // days 30 | writer.Write(0); // months 31 | } 32 | 33 | private Duration From(ref TimeSpan value) 34 | => new(value); 35 | 36 | private TimeSpan To(ref Duration value) 37 | => value.TimeSpan; 38 | 39 | public override string ToString() 40 | => "std::duration"; 41 | } 42 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Temporal/DateDurationCodec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | using Gel.DataTypes; 3 | 4 | namespace Gel.Binary.Codecs; 5 | 6 | internal sealed class DateDurationCodec : BaseTemporalCodec 7 | { 8 | public new static Guid Id = Guid.Parse("00000000-0000-0000-0000-000000000112"); 9 | 10 | public DateDurationCodec(CodecMetadata? metadata = null) 11 | : base(in Id, metadata) 12 | { 13 | AddConverter(From, To); 14 | } 15 | 16 | public override DateDuration Deserialize(ref PacketReader reader, CodecContext context) 17 | { 18 | reader.Skip(sizeof(long)); 19 | var days = reader.ReadInt32(); 20 | var months = reader.ReadInt32(); 21 | 22 | return new DateDuration(days, months); 23 | } 24 | 25 | public override void Serialize(ref PacketWriter writer, DateDuration value, CodecContext context) 26 | { 27 | writer.Write(0L); 28 | writer.Write(value.Days); 29 | writer.Write(value.Months); 30 | } 31 | 32 | private DateDuration From(ref TimeSpan value) 33 | => new(value); 34 | 35 | private TimeSpan To(ref DateDuration value) 36 | => value.TimeSpan; 37 | 38 | public override string ToString() 39 | => "cal::date_duration"; 40 | } 41 | -------------------------------------------------------------------------------- /examples/Gel.Examples.FSharp/Gel.Examples.FSharp.fsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 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 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Receivables/Data.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Packets; 2 | 3 | /// 4 | /// Represents the Data packet 5 | /// 6 | internal readonly struct Data : IReceiveable 7 | { 8 | /// 9 | public ServerMessageType Type 10 | => ServerMessageType.Data; 11 | 12 | /// 13 | /// The payload of this data packet 14 | /// 15 | public readonly byte[] PayloadBuffer; 16 | 17 | internal Data(byte[] buff) 18 | { 19 | PayloadBuffer = buff; 20 | } 21 | 22 | public Data() 23 | { 24 | PayloadBuffer = Array.Empty(); 25 | } 26 | 27 | internal Data(ref PacketReader reader) 28 | { 29 | // skip arary since its always one, errr should be one 30 | var numElements = reader.ReadUInt16(); 31 | if (numElements != 1) 32 | { 33 | throw new ArgumentOutOfRangeException(nameof(reader), 34 | $"Expected one element array for data, got {numElements}"); 35 | } 36 | 37 | var payloadLength = reader.ReadUInt32(); 38 | reader.ReadBytes((int)payloadLength, out var buff); 39 | PayloadBuffer = buff.ToArray(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/Exceptions/UnexpectedMessageException.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary; 2 | 3 | namespace Gel; 4 | 5 | /// 6 | /// Represents an exception that occurs when the client receives an unexpected message. 7 | /// 8 | public class UnexpectedMessageException : GelException 9 | { 10 | /// 11 | /// Constructs a new with the message type the client wasn't 12 | /// expecting. 13 | /// 14 | /// The unexcepted message type. 15 | internal UnexpectedMessageException(ServerMessageType unexpected) 16 | : base($"Got unexpected message type {unexpected}") 17 | { 18 | } 19 | 20 | /// 21 | /// Constructs a new with the expected and actual message types. 22 | /// 23 | /// The expected message type. 24 | /// The actual message type. 25 | internal UnexpectedMessageException(ServerMessageType expected, ServerMessageType actual) 26 | : base($"Expected message type {expected} but got {actual}") 27 | { 28 | } 29 | 30 | internal UnexpectedMessageException(string msg) 31 | : base(msg) 32 | { 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Receivables/LogMessage.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Packets; 2 | 3 | /// 4 | /// Represents the Log Message 5 | /// packet. 6 | /// 7 | internal readonly struct LogMessage : IReceiveable 8 | { 9 | /// 10 | public ServerMessageType Type => ServerMessageType.LogMessage; 11 | 12 | /// 13 | /// The severity of the log message. 14 | /// 15 | public readonly MessageSeverity Severity; 16 | 17 | /// 18 | /// The error code related to the log message. 19 | /// 20 | public readonly ServerErrorCodes Code; 21 | 22 | /// 23 | /// The content of the log message. 24 | /// 25 | public readonly string Content; 26 | 27 | /// 28 | /// A collection of annotations. 29 | /// 30 | public readonly Annotation[] Annotations; 31 | 32 | internal LogMessage(ref PacketReader reader) 33 | { 34 | Severity = (MessageSeverity)reader.ReadByte(); 35 | Code = (ServerErrorCodes)reader.ReadUInt32(); 36 | Content = reader.ReadString(); 37 | Annotations = reader.ReadAnnotations(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Temporal/LocalTimeCodec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | using Gel.DataTypes; 3 | 4 | namespace Gel.Binary.Codecs; 5 | 6 | internal sealed class LocalTimeCodec : BaseTemporalCodec 7 | { 8 | public new static Guid Id = Guid.Parse("00000000-0000-0000-0000-000000000112"); 9 | 10 | public LocalTimeCodec(CodecMetadata? metadata = null) 11 | : base(in Id, metadata) 12 | { 13 | AddConverter(FromTS, ToTS); 14 | AddConverter(FromTO, ToTO); 15 | } 16 | 17 | public override LocalTime Deserialize(ref PacketReader reader, CodecContext context) 18 | { 19 | var microseconds = reader.ReadInt64(); 20 | 21 | return new LocalTime(microseconds); 22 | } 23 | 24 | public override void Serialize(ref PacketWriter writer, LocalTime value, CodecContext context) => 25 | writer.Write(value.Microseconds); 26 | 27 | private LocalTime FromTS(ref TimeSpan value) 28 | => new(value); 29 | 30 | private TimeSpan ToTS(ref LocalTime value) 31 | => value.TimeSpan; 32 | 33 | private LocalTime FromTO(ref TimeOnly value) 34 | => new(value); 35 | 36 | private TimeOnly ToTO(ref LocalTime value) 37 | => value.TimeOnly; 38 | 39 | public override string ToString() 40 | => "cal::local_time"; 41 | } 42 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Receivables/CommandComplete.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Packets; 2 | 3 | /// 4 | /// Represents the 5 | /// Command Complete packet 6 | /// 7 | internal readonly struct CommandComplete : IReceiveable 8 | { 9 | public const int CAPBILITIES_HEADER = 0x1001; 10 | 11 | /// 12 | public ServerMessageType Type 13 | => ServerMessageType.CommandComplete; 14 | 15 | /// 16 | /// The used capabilities within the completed command. 17 | /// 18 | public readonly Capabilities UsedCapabilities; 19 | 20 | public readonly Guid StateTypeDescriptorId; 21 | 22 | /// 23 | /// The status of the completed command. 24 | /// 25 | public readonly string Status; 26 | 27 | public readonly Annotation[] Annotations; 28 | public readonly byte[] StateData; 29 | 30 | internal CommandComplete(ref PacketReader reader) 31 | { 32 | Annotations = reader.ReadAnnotations(); 33 | UsedCapabilities = (Capabilities)reader.ReadUInt64(); 34 | Status = reader.ReadString(); 35 | StateTypeDescriptorId = reader.ReadGuid(); 36 | StateData = reader.ReadByteArray(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Attributes/GelPropertyAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | /// 4 | /// Marks the current field or property as a valid target for serializing/deserializing. 5 | /// 6 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] 7 | public class GelPropertyAttribute : Attribute 8 | { 9 | internal readonly string? Name; 10 | 11 | /// 12 | /// Marks this member to be used when serializing/deserializing. 13 | /// 14 | /// The name of the member in the gel schema. 15 | public GelPropertyAttribute(string? propertyName = null) 16 | { 17 | Name = propertyName; 18 | } 19 | 20 | /// 21 | /// Gets or sets whether or not this member is a link. 22 | /// 23 | internal bool IsLink { get; set; } 24 | 25 | /// 26 | /// Gets or sets whether or not this member is required. 27 | /// 28 | internal bool IsRequired { get; set; } 29 | 30 | /// 31 | /// Gets or sets whether or not this member is a computed value. 32 | /// 33 | internal bool IsComputed { get; set; } 34 | 35 | /// 36 | /// Gets or sets whether or not this member is read-only. 37 | /// 38 | internal bool IsReadOnly { get; set; } 39 | } 40 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Temporal/RelativeDurationCodec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | using Gel.DataTypes; 3 | 4 | namespace Gel.Binary.Codecs; 5 | 6 | internal sealed class RelativeDurationCodec : BaseTemporalCodec 7 | { 8 | public new static Guid Id = Guid.Parse("00000000-0000-0000-0000-000000000112"); 9 | 10 | public RelativeDurationCodec(CodecMetadata? metadata = null) 11 | : base(in Id, metadata) 12 | { 13 | AddConverter(From, To); 14 | } 15 | 16 | public override RelativeDuration Deserialize(ref PacketReader reader, CodecContext context) 17 | { 18 | var microseconds = reader.ReadInt64(); 19 | var days = reader.ReadInt32(); 20 | var months = reader.ReadInt32(); 21 | 22 | return new RelativeDuration(microseconds, days, months); 23 | } 24 | 25 | public override void Serialize(ref PacketWriter writer, RelativeDuration value, CodecContext context) 26 | { 27 | writer.Write(value.Microseconds); 28 | writer.Write(value.Days); 29 | writer.Write(value.Months); 30 | } 31 | 32 | private RelativeDuration From(ref TimeSpan value) 33 | => new(value); 34 | 35 | private TimeSpan To(ref RelativeDuration value) 36 | => value.TimeSpan; 37 | 38 | public override string ToString() 39 | => "cal::relative_duration"; 40 | } 41 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Temporal/DateTimeCodec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | using DateTime = Gel.DataTypes.DateTime; 3 | 4 | namespace Gel.Binary.Codecs; 5 | 6 | internal sealed class DateTimeCodec : BaseTemporalCodec 7 | { 8 | public new static Guid Id = Guid.Parse("00000000-0000-0000-0000-000000000112"); 9 | 10 | public DateTimeCodec(CodecMetadata? metadata = null) 11 | : base(in Id, metadata) 12 | { 13 | AddConverter(FromDT, ToDT); 14 | AddConverter(FromDTO, ToDTO); 15 | } 16 | 17 | public override DateTime Deserialize(ref PacketReader reader, CodecContext context) 18 | { 19 | var microseconds = reader.ReadInt64(); 20 | 21 | return new DateTime(microseconds); 22 | } 23 | 24 | public override void Serialize(ref PacketWriter writer, DateTime value, CodecContext context) => 25 | writer.Write(value.Microseconds); 26 | 27 | private DateTime FromDT(ref System.DateTime value) 28 | => new(value); 29 | 30 | private System.DateTime ToDT(ref DateTime value) 31 | => value.DateTimeOffset.DateTime; 32 | 33 | private DateTime FromDTO(ref DateTimeOffset value) 34 | => new(value); 35 | 36 | private DateTimeOffset ToDTO(ref DateTime value) 37 | => value.DateTimeOffset; 38 | 39 | public override string ToString() 40 | => "std::datetime"; 41 | } 42 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/ContractResolvers/JsonContractResolver.cs: -------------------------------------------------------------------------------- 1 | using Gel.DataTypes; 2 | using Newtonsoft.Json; 3 | using Newtonsoft.Json.Serialization; 4 | using System.Reflection; 5 | 6 | namespace Gel.ContractResolvers; 7 | 8 | internal sealed class JsonContractResolver : DefaultContractResolver 9 | { 10 | protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) 11 | { 12 | var property = base.CreateProperty(member, memberSerialization); 13 | 14 | if (property.Ignored) 15 | return property; 16 | 17 | if (member is PropertyInfo propInfo) 18 | { 19 | var converter = GetConverter(property, propInfo, propInfo.PropertyType, 0); 20 | if (converter is not null) 21 | { 22 | property.Converter = converter; 23 | } 24 | } 25 | else 26 | throw new InvalidOperationException( 27 | $"{member.DeclaringType?.FullName ?? "Unknown"}.{member.Name} is not a property."); 28 | 29 | return property; 30 | } 31 | 32 | private static JsonConverter? GetConverter(JsonProperty property, PropertyInfo propInfo, Type type, int depth) 33 | { 34 | // range type 35 | if (ReflectionUtils.IsSubclassOfRawGeneric(typeof(Range<>), type)) 36 | return RangeConverter.Instance; 37 | 38 | return null; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/Gel.Examples.FSharp/ExampleRunner.fs: -------------------------------------------------------------------------------- 1 | module ExampleRunner 2 | 3 | open Gel 4 | open Examples 5 | open System.Linq 6 | open Microsoft.Extensions.Logging 7 | open System 8 | 9 | type ExampleRunner(clientPool: GelClientPool, logger: ILogger, factory: ILoggerFactory) = 10 | member this.ClientPool = clientPool 11 | member this.Logger = logger 12 | member this.Factory = factory 13 | 14 | member this.RunAsync() = 15 | task { 16 | // get all classes that implement IExample 17 | let examples = 18 | typeof.Assembly 19 | .GetTypes() 20 | .Where(fun x -> x.IsAssignableTo(typeof) && x <> typeof) 21 | .ToArray() 22 | 23 | for i = 0 to examples.Length - 1 do 24 | let example = examples[i] 25 | this.Logger.LogInformation("Running {example}..", $"{example.Name}.fs") 26 | 27 | try 28 | let inst = Activator.CreateInstance(example) :?> IExample 29 | 30 | let! _ = inst.ExecuteAsync(this.ClientPool, this.Factory.CreateLogger(example.Name)) 31 | 32 | this.Logger.LogInformation("{example} complete!", $"{example.Name}.fs") 33 | 34 | with ex -> 35 | this.Logger.LogError(ex, "Failed to run {example}", $"{example.Name}.fs") 36 | } 37 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V2.0/Descriptors/ScalarTypeDescriptor.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Protocol.V2._0.Descriptors; 4 | 5 | internal readonly struct ScalarTypeDescriptor : ITypeDescriptor, IMetadataDescriptor 6 | { 7 | public readonly Guid Id; 8 | 9 | public readonly string Name; 10 | 11 | public readonly bool IsSchemaDefined; 12 | 13 | public readonly ushort[] Ancestors; 14 | 15 | public ScalarTypeDescriptor(ref PacketReader reader, in Guid id) 16 | { 17 | Id = id; 18 | Name = reader.ReadString(); 19 | IsSchemaDefined = reader.ReadBoolean(); 20 | 21 | var ancestorsCount = reader.ReadUInt16(); 22 | var ancestors = new ushort[ancestorsCount]; 23 | 24 | for (var i = 0; i != ancestorsCount; i++) 25 | { 26 | ancestors[i] = reader.ReadUInt16(); 27 | } 28 | 29 | Ancestors = ancestors; 30 | } 31 | 32 | unsafe ref readonly Guid ITypeDescriptor.Id 33 | { 34 | get 35 | { 36 | fixed (Guid* ptr = &Id) 37 | return ref *ptr; 38 | } 39 | } 40 | 41 | public CodecMetadata? GetMetadata(RelativeCodecDelegate relativeCodec, 42 | RelativeDescriptorDelegate relativeDescriptor) 43 | => new(Name, IsSchemaDefined, 44 | IMetadataDescriptor.ConstructAncestors(Ancestors, relativeCodec, relativeDescriptor)); 45 | } 46 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Temporal/LocalDateTimeCodec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | using Gel.DataTypes; 3 | using DateTime = System.DateTime; 4 | 5 | namespace Gel.Binary.Codecs; 6 | 7 | internal sealed class LocalDateTimeCodec : BaseTemporalCodec 8 | { 9 | public new static Guid Id = Guid.Parse("00000000-0000-0000-0000-000000000112"); 10 | 11 | public LocalDateTimeCodec(CodecMetadata? metadata = null) 12 | : base(in Id, metadata) 13 | { 14 | AddConverter(FromDT, ToDT); 15 | AddConverter(FromDTO, ToDTO); 16 | } 17 | 18 | public override LocalDateTime Deserialize(ref PacketReader reader, CodecContext context) 19 | { 20 | var microseconds = reader.ReadInt64(); 21 | 22 | return new LocalDateTime(microseconds); 23 | } 24 | 25 | public override void Serialize(ref PacketWriter writer, LocalDateTime value, CodecContext context) => 26 | writer.Write(value.Microseconds); 27 | 28 | private LocalDateTime FromDT(ref DateTime value) 29 | => new(value); 30 | 31 | private DateTime ToDT(ref LocalDateTime value) 32 | => value.DateTime; 33 | 34 | private LocalDateTime FromDTO(ref DateTimeOffset value) 35 | => new(value); 36 | 37 | private DateTimeOffset ToDTO(ref LocalDateTime value) 38 | => value.DateTimeOffset; 39 | 40 | public override string ToString() 41 | => "cal::local_datetime"; 42 | } 43 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/NamingStrategies/SnakeCaseNamingStrategy.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace Gel; 4 | 5 | internal sealed class SnakeCaseNamingStrategy : INamingStrategy 6 | { 7 | public string Convert(PropertyInfo property) 8 | => Convert(property.Name); 9 | 10 | public string Convert(string name) 11 | { 12 | if (string.IsNullOrWhiteSpace(name)) 13 | { 14 | return name; 15 | } 16 | 17 | var upperCaseLength = name.Where((c, i) => c is >= 'A' and <= 'Z' && i != 0).Count(); 18 | 19 | if (upperCaseLength == 0) 20 | return name.ToLower(); 21 | 22 | var bufferSize = name.Length + upperCaseLength; 23 | Span buffer = stackalloc char[bufferSize]; 24 | var bufferPosition = 0; 25 | var namePosition = 0; 26 | while (bufferPosition < buffer.Length) 27 | { 28 | if (namePosition > 0 && name[namePosition] >= 'A' && name[namePosition] <= 'Z') 29 | { 30 | buffer[bufferPosition] = '_'; 31 | buffer[bufferPosition + 1] = name[namePosition]; 32 | bufferPosition += 2; 33 | namePosition++; 34 | continue; 35 | } 36 | 37 | buffer[bufferPosition] = name[namePosition]; 38 | bufferPosition++; 39 | namePosition++; 40 | } 41 | 42 | return new string(buffer).ToLower(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /dbschema/default.esdl: -------------------------------------------------------------------------------- 1 | module default { 2 | global current_user_id -> uuid; 3 | global abc -> tuple; 4 | 5 | type Movie { 6 | required property title -> str { 7 | constraint exclusive; 8 | } 9 | required property year -> int32; 10 | required link director -> Person; 11 | required multi link actors -> Person; 12 | } 13 | type Person { 14 | required property name -> str; 15 | required property email -> str { 16 | constraint exclusive; 17 | } 18 | } 19 | 20 | # for example todo app 21 | scalar type State extending enum; 22 | type TODO { 23 | required property title -> str; 24 | required property description -> str; 25 | required property date_created -> std::datetime { 26 | default := std::datetime_current(); 27 | } 28 | required property state -> State; 29 | } 30 | 31 | # for integration tests & examples 32 | abstract type AbstractThing { 33 | required property name -> str { 34 | constraint exclusive; 35 | } 36 | } 37 | type Thing extending AbstractThing { 38 | required property description -> str; 39 | } 40 | type OtherThing extending AbstractThing { 41 | required property attribute -> str; 42 | } 43 | 44 | # for type converter example 45 | type UserWithSnowflakeId { 46 | required property user_id -> str { 47 | constraint exclusive; 48 | } 49 | required property username -> str; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Receivables/ServerHandshake.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Protocol.V1._0.Packets; 2 | 3 | /// 4 | /// Represents the 5 | /// Server Handshake packet. 6 | /// 7 | internal readonly struct ServerHandshake : IReceiveable 8 | { 9 | /// 10 | public ServerMessageType Type 11 | => ServerMessageType.ServerHandshake; 12 | 13 | /// 14 | /// The major version of the server. 15 | /// 16 | public readonly ushort MajorVersion; 17 | 18 | /// 19 | /// The minor version of the server. 20 | /// 21 | public readonly ushort MinorVersion; 22 | 23 | /// 24 | /// A collection of s used by the server. 25 | /// 26 | public readonly ProtocolExtension[] Extensions; 27 | 28 | internal ServerHandshake(ref PacketReader reader) 29 | { 30 | MajorVersion = reader.ReadUInt16(); 31 | MinorVersion = reader.ReadUInt16(); 32 | 33 | var numExtensions = reader.ReadUInt16(); 34 | var extensions = new ProtocolExtension[numExtensions]; 35 | 36 | for (var i = 0; i != numExtensions; i++) 37 | { 38 | extensions[i] = new ProtocolExtension(ref reader); 39 | } 40 | 41 | Extensions = extensions; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V2.0/Descriptors/CompoundTypeDescriptor.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Protocol.V2._0.Descriptors; 4 | 5 | internal readonly struct CompoundTypeDescriptor : ITypeDescriptor, IMetadataDescriptor 6 | { 7 | public readonly Guid Id; 8 | 9 | public readonly string Name; 10 | 11 | public readonly bool IsSchmeaDefined; 12 | 13 | public readonly TypeOperation Operation; 14 | 15 | public readonly ushort[] Components; 16 | 17 | public CompoundTypeDescriptor(ref PacketReader reader, in Guid id) 18 | { 19 | Id = id; 20 | Name = reader.ReadString(); 21 | IsSchmeaDefined = reader.ReadBoolean(); 22 | Operation = (TypeOperation)reader.ReadByte(); 23 | 24 | var componentCount = reader.ReadUInt16(); 25 | var components = new ushort[componentCount]; 26 | 27 | for (var i = 0; i != componentCount; i++) 28 | { 29 | components[i] = reader.ReadUInt16(); 30 | } 31 | 32 | Components = components; 33 | } 34 | 35 | unsafe ref readonly Guid ITypeDescriptor.Id 36 | { 37 | get 38 | { 39 | fixed (Guid* ptr = &Id) 40 | return ref *ptr; 41 | } 42 | } 43 | 44 | public CodecMetadata? GetMetadata(RelativeCodecDelegate relativeCodec, 45 | RelativeDescriptorDelegate relativeDescriptor) 46 | => new(Name, IsSchmeaDefined); 47 | } 48 | -------------------------------------------------------------------------------- /.github/workflows/build-docs.yml: -------------------------------------------------------------------------------- 1 | name: Docs Build 2 | 3 | on: 4 | release: 5 | types: [released] 6 | env: 7 | BuildNumber: "${{ github.run_number }}" 8 | 9 | jobs: 10 | build-api-docs: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | 15 | - name: Setup .NET 16 | uses: actions/setup-dotnet@v1 17 | with: 18 | dotnet-version: 8.0.x 19 | 20 | - name: Restore dependencies 21 | run: dotnet restore 22 | 23 | - name: Build 24 | run: dotnet build --no-restore 25 | 26 | - name: Doc generation 27 | run: dotnet run --project ./tools/Gel.DocGenerator/ -- $GITHUB_WORKSPACE 28 | 29 | - name: Set git status Env 30 | id: gh-status-check 31 | run: | 32 | echo "GITHUB_COMMIT_STATUS<> $GITHUB_ENV 33 | git status >> $GITHUB_ENV 34 | echo 'EOF' >> $GITHUB_ENV 35 | 36 | - name: Commit files 37 | if: ${{ !contains(env.GITHUB_COMMIT_STATUS, 'nothing to commit') }} 38 | run: | 39 | git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" 40 | git config --local user.name "github-actions[bot]" 41 | git commit -m "Generate docs" -a 42 | 43 | - name: Push changes 44 | if: ${{ !contains(env.GITHUB_COMMIT_STATUS, 'nothing to commit') }} 45 | uses: ad-m/github-push-action@master 46 | with: 47 | github_token: ${{ secrets.GITHUB_TOKEN }} 48 | branch: ${{ github.ref }} 49 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Attributes/GelTypeConverterAttribute.cs: -------------------------------------------------------------------------------- 1 | using Gel.TypeConverters; 2 | 3 | namespace Gel; 4 | 5 | /// 6 | /// Marks the current property to be deserialized/serialized with a specific 7 | /// . 8 | /// 9 | [AttributeUsage(AttributeTargets.Property)] 10 | public class GelTypeConverterAttribute : Attribute 11 | { 12 | internal IGelTypeConverter Converter; 13 | 14 | /// 15 | /// Initializes the with the 16 | /// specified . 17 | /// 18 | /// The type of the converter. 19 | /// 20 | /// is not a valid 21 | /// . 22 | /// 23 | public GelTypeConverterAttribute(Type converterType) 24 | { 25 | if (converterType.GetInterface(nameof(IGelTypeConverter)) is null) 26 | { 27 | throw new ArgumentException("Converter type must implement IGelTypeConverter"); 28 | } 29 | 30 | if (converterType.IsAbstract || converterType.IsInterface) 31 | { 32 | throw new ArgumentException("Converter type must be a concrete type"); 33 | } 34 | 35 | Converter = (IGelTypeConverter)Activator.CreateInstance(converterType)!; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/Gel.Tests.Unit/SCRAMTests.cs: -------------------------------------------------------------------------------- 1 | using Gel.Utils; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using System; 4 | 5 | namespace Gel.Tests.Unit; 6 | 7 | [TestClass] 8 | public class SCRAMTests 9 | { 10 | public const string SCRAM_METHOD = "SCRAM-SHA-256"; 11 | public const string SCRAM_USERNAME = "user"; 12 | public const string SCRAM_PASSWORD = "pencil"; 13 | public const string SCRAM_CLIENT_NONCE = "rOprNGfwEbeRWgbNEkqO"; 14 | public const string SCRAM_SERVER_NONCE = "rOprNGfwEbeRWgbNEkqO%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0"; 15 | public const string SCRAM_SALT = "W22ZaJ0SNY7soEsUEjb6gQ=="; 16 | 17 | private static readonly GelBinaryClient _client = 18 | new GelTcpClient(new GelConnection(), new GelClientConfig(), null!); 19 | 20 | [TestMethod] 21 | public void TestSCRAM() 22 | { 23 | var scram = new Scram(Convert.FromBase64String(SCRAM_CLIENT_NONCE)); 24 | 25 | var clientFirst = scram.BuildInitialMessage(SCRAM_USERNAME); 26 | Assert.AreEqual($"n,,n={SCRAM_USERNAME},r={SCRAM_CLIENT_NONCE}", clientFirst); 27 | 28 | var serverFirst = CreateServerFirstMessage(); 29 | var clientFinal = scram.BuildFinalMessage(serverFirst, SCRAM_PASSWORD); 30 | 31 | Assert.AreEqual($"c=biws,r={SCRAM_SERVER_NONCE},p=dHzbZapWIk4jUhN+Ute9ytag9zjfMHgsqmmiz7AndVQ=", 32 | clientFinal.final); 33 | } 34 | 35 | private static string CreateServerFirstMessage() => $"r={SCRAM_SERVER_NONCE},s={SCRAM_SALT},i=4096"; 36 | } 37 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Builders/Wrappers/FSharpOptionWrapper.cs: -------------------------------------------------------------------------------- 1 | namespace Gel.Binary.Builders.Wrappers; 2 | 3 | internal sealed class FSharpOptionWrapper : IWrapper 4 | { 5 | public Type GetInnerType(Type wrapperType) 6 | => wrapperType.GenericTypeArguments[0]; 7 | 8 | public bool IsWrapping(Type t) 9 | => t.IsFSharpOption() || t.IsFSharpValueOption(); 10 | 11 | public object? Wrap(Type target, object? value) 12 | { 13 | if (target.IsFSharpValueOption()) 14 | return WrapValueOption(target, value); 15 | if (target.IsFSharpOption()) 16 | return WrapReferenceOption(target, value); 17 | throw new NotSupportedException($"Unsupported wrapping type: {target}"); 18 | } 19 | 20 | private static object? WrapReferenceOption(Type target, object? value) 21 | { 22 | if (value is null) 23 | return null; 24 | 25 | return ( 26 | target.GetConstructor(new[] {value.GetType()}) 27 | ?? throw new GelException($"Failed to find constructor for {target}") 28 | ).Invoke(new[] {value}); 29 | } 30 | 31 | private static object? WrapValueOption(Type target, object? value) 32 | { 33 | if (value is null) 34 | return ReflectionUtils.GetDefault(target); 35 | 36 | return ( 37 | target.GetConstructor(new[] {value.GetType()}) 38 | ?? throw new GelException($"Failed to find constructor for {target}") 39 | ).Invoke(new[] {value}); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Codecs/Impl/BaseComplexScalarCodec.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Codecs; 4 | 5 | internal abstract class BaseComplexScalarCodec 6 | : BaseComplexCodec, IScalarCodec 7 | { 8 | public BaseComplexScalarCodec(in Guid id, CodecMetadata? metadata) 9 | : base(in id, metadata, typeof(RuntimeScalarCodec<>)) 10 | { 11 | } 12 | 13 | private sealed class RuntimeScalarCodec 14 | : BaseScalarCodec, IRuntimeCodec 15 | { 16 | private readonly BaseComplexScalarCodec _codec; 17 | private readonly Converter _converter; 18 | 19 | public RuntimeScalarCodec( 20 | BaseComplexScalarCodec codec, 21 | Converter converter) 22 | : base(codec.Id, codec.Metadata) 23 | { 24 | _codec = codec; 25 | _converter = converter; 26 | } 27 | 28 | IComplexCodec IRuntimeCodec.Broker 29 | => _codec; 30 | 31 | public override U? Deserialize(ref PacketReader reader, CodecContext context) 32 | { 33 | var model = _codec.Deserialize(ref reader, context); 34 | 35 | return _converter.To(ref model); 36 | } 37 | 38 | public override void Serialize(ref PacketWriter writer, U? value, CodecContext context) 39 | { 40 | var model = _converter.From(ref value); 41 | 42 | _codec.Serialize(ref writer, model, context); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V2.0/Descriptors/MultiRangeDescriptor.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Protocol.V2._0.Descriptors; 4 | 5 | internal readonly struct MultiRangeDescriptor : ITypeDescriptor, IMetadataDescriptor 6 | { 7 | public readonly Guid Id; 8 | 9 | public readonly string Name; 10 | 11 | public readonly bool IsSchemaDefined; 12 | 13 | public readonly ushort[] Ancestors; 14 | 15 | public readonly ushort Type; 16 | public MultiRangeDescriptor(ref PacketReader reader, in Guid id) 17 | { 18 | Id = id; 19 | 20 | Name = reader.ReadString(); 21 | IsSchemaDefined = reader.ReadBoolean(); 22 | 23 | var ancestorsCount = reader.ReadUInt16(); 24 | var ancestors = new ushort[ancestorsCount]; 25 | 26 | for (var i = 0; i != ancestorsCount; i++) 27 | { 28 | ancestors[i] = reader.ReadUInt16(); 29 | } 30 | 31 | Ancestors = ancestors; 32 | 33 | Type = reader.ReadUInt16(); 34 | } 35 | 36 | 37 | public CodecMetadata? GetMetadata(RelativeCodecDelegate relativeCodec, 38 | RelativeDescriptorDelegate relativeDescriptor) 39 | => new(Name, IsSchemaDefined, 40 | IMetadataDescriptor.ConstructAncestors(Ancestors, relativeCodec, relativeDescriptor)); 41 | 42 | unsafe ref readonly Guid ITypeDescriptor.Id 43 | { 44 | get 45 | { 46 | fixed (Guid* ptr = &Id) 47 | return ref *ptr; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V2.0/Descriptors/RangeTypeDescriptor.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Protocol.V2._0.Descriptors; 4 | 5 | internal readonly struct RangeTypeDescriptor : ITypeDescriptor, IMetadataDescriptor 6 | { 7 | public readonly Guid Id; 8 | 9 | public readonly string Name; 10 | 11 | public readonly bool IsSchemaDefined; 12 | 13 | public readonly ushort[] Ancestors; 14 | 15 | public readonly ushort Type; 16 | 17 | public RangeTypeDescriptor(ref PacketReader reader, in Guid id) 18 | { 19 | Id = id; 20 | 21 | Name = reader.ReadString(); 22 | IsSchemaDefined = reader.ReadBoolean(); 23 | 24 | var ancestorsCount = reader.ReadUInt16(); 25 | var ancestors = new ushort[ancestorsCount]; 26 | 27 | for (var i = 0; i != ancestorsCount; i++) 28 | { 29 | ancestors[i] = reader.ReadUInt16(); 30 | } 31 | 32 | Ancestors = ancestors; 33 | 34 | Type = reader.ReadUInt16(); 35 | } 36 | 37 | unsafe ref readonly Guid ITypeDescriptor.Id 38 | { 39 | get 40 | { 41 | fixed (Guid* ptr = &Id) 42 | return ref *ptr; 43 | } 44 | } 45 | 46 | public CodecMetadata? GetMetadata(RelativeCodecDelegate relativeCodec, 47 | RelativeDescriptorDelegate relativeDescriptor) 48 | => new(Name, IsSchemaDefined, 49 | IMetadataDescriptor.ConstructAncestors(Ancestors, relativeCodec, relativeDescriptor)); 50 | } 51 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Gel.Net.Driver.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Gel.Net.Driver 5 | Gel 6 | A core driver to interface with Gel 7 | net8.0 8 | enable 9 | enable 10 | True 11 | CS1591 12 | True 13 | 5 14 | true 15 | True 16 | preview 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V1.0/Receivables/DumpBlock.cs: -------------------------------------------------------------------------------- 1 | using Gel.Utils; 2 | using System.Security.Cryptography; 3 | 4 | namespace Gel.Binary.Protocol.V1._0.Packets; 5 | 6 | /// 7 | /// Represents the Dump Block 8 | /// packet. 9 | /// 10 | internal readonly struct DumpBlock : IReceiveable 11 | { 12 | internal int Size 13 | => sizeof(int) + BinaryUtils.SizeOfByteArray(Raw) + BinaryUtils.SizeOfByteArray(HashBuffer); 14 | 15 | /// 16 | public ServerMessageType Type 17 | => ServerMessageType.DumpBlock; 18 | 19 | /// 20 | /// Gets the length of this packets data, used when writing a dump file. 21 | /// 22 | public readonly int Length; 23 | 24 | public readonly byte[] Raw; 25 | 26 | /// 27 | /// Gets the sha1 hash of this packets data, used when writing a dump file. 28 | /// 29 | public readonly byte[] HashBuffer; 30 | 31 | /// 32 | /// Gets a collection of attributes for this packet. 33 | /// 34 | public readonly KeyValue[] Attributes; 35 | 36 | internal DumpBlock(ref PacketReader reader, in int length) 37 | { 38 | Length = length; 39 | 40 | reader.ReadBytes(length, out var rawBuff); 41 | Raw = rawBuff.ToArray(); 42 | 43 | HashBuffer = SHA1.Create().ComputeHash(Raw); 44 | 45 | var r = new PacketReader(rawBuff); 46 | Attributes = r.ReadKeyValues(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Builders/Info/GelPropertyMapInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | using System.Reflection; 3 | 4 | namespace Gel; 5 | 6 | internal readonly struct GelPropertyMapInfo 7 | { 8 | public readonly GelPropertyInfo[] Properties { get; init; } 9 | public readonly Dictionary Map { get; init; } 10 | public readonly Dictionary IndexMap { get; init; } 11 | 12 | 13 | private static readonly ConcurrentDictionary _cache = new(); 14 | 15 | public static GelPropertyMapInfo Create(Type type) 16 | { 17 | if (_cache.TryGetValue(type, out var cached)) 18 | return cached; 19 | 20 | var props = type.GetProperties(); 21 | var gelProps = new GelPropertyInfo[props.Length]; 22 | var indexMap = new Dictionary(props.Length); 23 | var map = new Dictionary(props.Length); 24 | 25 | for (var i = 0; i != props.Length; i++) 26 | { 27 | var prop = props[i]; 28 | var edbProp = new GelPropertyInfo(prop); 29 | gelProps[i] = edbProp; 30 | 31 | indexMap.Add(edbProp, i); 32 | 33 | if (prop.GetCustomAttribute() is null) 34 | { 35 | map.Add(edbProp.GelName, edbProp); 36 | } 37 | } 38 | 39 | var info = new GelPropertyMapInfo {IndexMap = indexMap, Map = map, Properties = gelProps}; 40 | 41 | _cache.TryAdd(type, info); 42 | 43 | return info; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Gel.Net.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 3.0.0 4 | latest 5 | Gel.Net Contributors 6 | edgedb;gel;db;database 7 | https://github.com/geldata/gel-net 8 | MIT 9 | PackageLogo.png 10 | git 11 | git://github.com/geldata/gel-net 12 | 13 | 14 | $(VersionSuffix)-dev 15 | dev 16 | 17 | 18 | $(VersionSuffix)-$(BuildNumber) 19 | build-$(BuildNumber) 20 | 21 | 22 | $(NoWarn);CS1573;CS1591 23 | true 24 | true 25 | 26 | 27 | 28 | True 29 | \ 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /examples/Gel.Examples.FSharp/Examples/AbstractTypes.fs: -------------------------------------------------------------------------------- 1 | namespace Examples 2 | 3 | open Gel 4 | open Microsoft.Extensions.Logging 5 | open System.Linq 6 | 7 | type Thing = { Name: string; Description: string } 8 | 9 | type OtherThing = { Name: string; Attribute: string } 10 | 11 | type AbstractThing = 12 | | Thing of Thing 13 | | OtherThing of OtherThing 14 | 15 | type AbstractTypesExample() = 16 | interface IExample with 17 | member this.ExecuteAsync(clientPool: GelClientPool, logger: ILogger) = 18 | task { 19 | // select the abstract type from the schema. 20 | // Note that the type builder will 'discover' the types that inherit 21 | // our F# union type. 22 | let! result = 23 | clientPool.QueryAsync("select AbstractThing { name }") 24 | |> Async.AwaitTask 25 | 26 | // select only 'Thing' types 27 | let things = 28 | result.Where(fun x -> 29 | match x with 30 | | Thing _ -> true 31 | | _ -> false) 32 | 33 | // select only 'OtherThing' types 34 | let otherThings = 35 | result.Where(fun x -> 36 | match x with 37 | | OtherThing _ -> true 38 | | _ -> false) 39 | 40 | let isResult = 41 | clientPool.QueryAsync( 42 | "select AbstractThing { name, [is Thing].description, [is OtherThing].attribute }" 43 | ) 44 | 45 | isResult |> ignore 46 | } 47 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V2.0/Descriptors/TupleTypeDescriptor.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Protocol.V2._0.Descriptors; 4 | 5 | internal readonly struct TupleTypeDescriptor : ITypeDescriptor, IMetadataDescriptor 6 | { 7 | public readonly Guid Id; 8 | 9 | public readonly string Name; 10 | 11 | public readonly bool IsSchemaDefined; 12 | 13 | public readonly ushort[] Ancestors; 14 | 15 | public readonly ushort[] Elements; 16 | 17 | public TupleTypeDescriptor(ref PacketReader reader, in Guid id) 18 | { 19 | Id = id; 20 | Name = reader.ReadString(); 21 | IsSchemaDefined = reader.ReadBoolean(); 22 | 23 | var ancestorsCount = reader.ReadUInt16(); 24 | var ancestors = new ushort[ancestorsCount]; 25 | 26 | for (var i = 0; i != ancestorsCount; i++) 27 | { 28 | ancestors[i] = reader.ReadUInt16(); 29 | } 30 | 31 | Ancestors = ancestors; 32 | 33 | var elementCount = reader.ReadUInt16(); 34 | var elements = new ushort[elementCount]; 35 | 36 | for (var i = 0; i != elementCount; i++) 37 | { 38 | elements[i] = reader.ReadUInt16(); 39 | } 40 | 41 | Elements = elements; 42 | } 43 | 44 | unsafe ref readonly Guid ITypeDescriptor.Id 45 | { 46 | get 47 | { 48 | fixed (Guid* ptr = &Id) 49 | return ref *ptr; 50 | } 51 | } 52 | 53 | public CodecMetadata? GetMetadata(RelativeCodecDelegate relativeCodec, 54 | RelativeDescriptorDelegate relativeDescriptor) 55 | => new(Name, IsSchemaDefined, 56 | IMetadataDescriptor.ConstructAncestors(Ancestors, relativeCodec, relativeDescriptor)); 57 | } 58 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V2.0/Descriptors/EnumerationTypeDescriptor.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Protocol.V2._0.Descriptors; 4 | 5 | internal readonly struct EnumerationTypeDescriptor : ITypeDescriptor, IMetadataDescriptor 6 | { 7 | public readonly Guid Id; 8 | 9 | public readonly string Name; 10 | 11 | public readonly bool IsSchemaDefined; 12 | 13 | public readonly ushort[] Ancestors; 14 | 15 | public readonly string[] Members; 16 | 17 | public EnumerationTypeDescriptor(ref PacketReader reader, in Guid id) 18 | { 19 | Id = id; 20 | Name = reader.ReadString(); 21 | IsSchemaDefined = reader.ReadBoolean(); 22 | 23 | var ancestorsCount = reader.ReadUInt16(); 24 | var ancestors = new ushort[ancestorsCount]; 25 | 26 | for (var i = 0; i != ancestorsCount; i++) 27 | { 28 | ancestors[i] = reader.ReadUInt16(); 29 | } 30 | 31 | Ancestors = ancestors; 32 | 33 | var memberCount = reader.ReadInt16(); 34 | var members = new string[memberCount]; 35 | 36 | for (var i = 0; i != memberCount; i++) 37 | { 38 | members[i] = reader.ReadString(); 39 | } 40 | 41 | Members = members; 42 | } 43 | 44 | unsafe ref readonly Guid ITypeDescriptor.Id 45 | { 46 | get 47 | { 48 | fixed (Guid* ptr = &Id) 49 | return ref *ptr; 50 | } 51 | } 52 | 53 | public CodecMetadata? GetMetadata(RelativeCodecDelegate relativeCodec, 54 | RelativeDescriptorDelegate relativeDescriptor) 55 | => new(Name, IsSchemaDefined, 56 | IMetadataDescriptor.ConstructAncestors(Ancestors, relativeCodec, relativeDescriptor)); 57 | } 58 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Builders/Wrappers/IWrapper.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | using System.Diagnostics.CodeAnalysis; 3 | 4 | namespace Gel.Binary.Builders.Wrappers; 5 | 6 | internal interface IWrapper 7 | { 8 | static readonly ConcurrentBag _wrappers = new() {new FSharpOptionWrapper(), new NullableWrapper()}; 9 | 10 | static bool TryGetWrapper(Type t, [NotNullWhen(true)] out IWrapper? wrapper) 11 | => (wrapper = _wrappers.FirstOrDefault(x => x.IsWrapping(t))) is not null; 12 | 13 | /// 14 | /// Returns the inner (real) type that the wrapper wraps. For example: 15 | /// <> would return ; 16 | /// 17 | /// The wrapper type to extract the inner type from. 18 | /// The inner type. 19 | Type GetInnerType(Type wrapperType); 20 | 21 | /// 22 | /// Determines whether or not this wrapper can work with the provided 23 | /// wrapping type. 24 | /// 25 | /// 26 | /// The type that is checked for a wrapper that this instance can work with. 27 | /// 28 | /// 29 | /// if the provided type matches the type this wrapper 30 | /// can work with; otherwise . 31 | /// 32 | bool IsWrapping(Type t); 33 | 34 | /// 35 | /// Wraps a given value into the target type. 36 | /// 37 | /// The target type of the wrap. 38 | /// The value to wrap. 39 | /// The wrapped value. 40 | object? Wrap(Type target, object? value); 41 | } 42 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Extensions/GelHostingExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.Extensions.Logging; 3 | 4 | namespace Gel; 5 | 6 | /// 7 | /// A class containing extension methods for DI. 8 | /// 9 | public static class GelHostingExtensions 10 | { 11 | /// 12 | /// Adds a singleton to a . 13 | /// 14 | /// The source collection to add a to. 15 | /// An optional connection arguments for the client. 16 | /// 17 | /// An optional configuration delegate for configuring the . 18 | /// 19 | /// 20 | /// The source with added as a singleton. 21 | /// 22 | public static IServiceCollection AddGel(this IServiceCollection collection, GelConnection? connection = null, 23 | Action? clientPoolConfig = null) 24 | { 25 | var conn = connection ?? GelConnection.Create(); 26 | 27 | collection.AddSingleton(conn); 28 | collection.AddSingleton(provider => 29 | { 30 | var config = new GelClientPoolConfig(); 31 | clientPoolConfig?.Invoke(config); 32 | 33 | if (config.Logger is null) 34 | { 35 | config.Logger = provider.GetService()?.CreateLogger("Gel"); 36 | } 37 | 38 | return config; 39 | }); 40 | collection.AddSingleton(); 41 | 42 | return collection; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Binary/Protocol/V2.0/Descriptors/NamedTupleTypeDescriptor.cs: -------------------------------------------------------------------------------- 1 | using Gel.Binary.Protocol.Common.Descriptors; 2 | 3 | namespace Gel.Binary.Protocol.V2._0.Descriptors; 4 | 5 | internal readonly struct NamedTupleTypeDescriptor : ITypeDescriptor, IMetadataDescriptor 6 | { 7 | public readonly Guid Id; 8 | 9 | public readonly string Name; 10 | 11 | public readonly bool IsSchemaDefined; 12 | 13 | public readonly ushort[] Ancestors; 14 | 15 | public readonly TupleElement[] Elements; 16 | 17 | public NamedTupleTypeDescriptor(ref PacketReader reader, in Guid id) 18 | { 19 | Id = id; 20 | Name = reader.ReadString(); 21 | IsSchemaDefined = reader.ReadBoolean(); 22 | 23 | var ancestorsCount = reader.ReadUInt16(); 24 | var ancestors = new ushort[ancestorsCount]; 25 | 26 | for (var i = 0; i != ancestorsCount; i++) 27 | { 28 | ancestors[i] = reader.ReadUInt16(); 29 | } 30 | 31 | Ancestors = ancestors; 32 | 33 | var elementCount = reader.ReadUInt16(); 34 | var elements = new TupleElement[elementCount]; 35 | 36 | for (var i = 0; i != elementCount; i++) 37 | { 38 | elements[i] = new TupleElement(ref reader); 39 | } 40 | 41 | Elements = elements; 42 | } 43 | 44 | unsafe ref readonly Guid ITypeDescriptor.Id 45 | { 46 | get 47 | { 48 | fixed (Guid* ptr = &Id) 49 | return ref *ptr; 50 | } 51 | } 52 | 53 | public CodecMetadata? GetMetadata(RelativeCodecDelegate relativeCodec, 54 | RelativeDescriptorDelegate relativeDescriptor) 55 | => new(Name, IsSchemaDefined, 56 | IMetadataDescriptor.ConstructAncestors(Ancestors, relativeCodec, relativeDescriptor)); 57 | } 58 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/DataTypes/Json.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Gel.DataTypes; 4 | 5 | /// 6 | /// Represents a standard json value. 7 | /// 8 | public readonly struct Json 9 | { 10 | /// 11 | /// Gets or sets the raw json value. 12 | /// 13 | public readonly string Value; 14 | 15 | /// 16 | /// Creates a new json type with a provided value. 17 | /// 18 | /// The raw json value of this json object. 19 | public Json(string value) 20 | { 21 | Value = value; 22 | } 23 | 24 | /// 25 | /// Deserializes into a dotnet type using Newtonsoft.Json. 26 | /// 27 | /// 28 | /// If is null, the value 29 | /// of will be returned. 30 | /// 31 | /// The type to deserialize as. 32 | /// 33 | /// The optional custom serializer to use to deserialize . 34 | /// 35 | /// 36 | /// The deserialized form of ; or . 37 | /// 38 | public T? Deserialize(JsonSerializer? serializer = null) 39 | => Value is null 40 | ? default 41 | : serializer is not null 42 | ? serializer.Deserialize(new JsonTextReader(new StringReader(Value))) 43 | : GelClientConfig.JsonSerializer.DeserializeObject(Value); 44 | 45 | public static implicit operator string(Json j) => j.Value; 46 | public static implicit operator Json(string value) => new(value); 47 | } 48 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Models/Exceptions/NoTypeConverterException.cs: -------------------------------------------------------------------------------- 1 | namespace Gel; 2 | 3 | /// 4 | /// Represents an exception thrown when no type converter could be found. 5 | /// 6 | public class NoTypeConverterException : GelException 7 | { 8 | /// 9 | /// Constructs a new with the target and source types. 10 | /// 11 | /// The target type that was going to be converted to. 12 | /// The source type. 13 | public NoTypeConverterException(Type target, Type source) 14 | : base($"Could not convert {source.Name} to {target.Name}") 15 | { 16 | } 17 | 18 | /// 19 | /// Constructs a new with the target and source type, 20 | /// and inner exception. 21 | /// 22 | /// The target type that was going to be converted to. 23 | /// The source type. 24 | /// The inner exception. 25 | public NoTypeConverterException(Type target, Type source, Exception inner) 26 | : base($"Could not convert {source.Name} to {target.Name}", inner) 27 | { 28 | } 29 | 30 | /// 31 | /// Constructs a new with the specified error message. 32 | /// 33 | /// The error message describing why this exception was thrown. 34 | /// An optional inner exception. 35 | public NoTypeConverterException(string message, Exception? inner = null) 36 | : base(message, inner) 37 | { 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tools/Gel.DotnetTool/Util/CodeWriter.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace Gel.DotnetTool; 4 | 5 | internal class CodeWriter 6 | { 7 | private readonly ScopeTracker _scopeTracker; //We only need one. It can be reused. 8 | public readonly StringBuilder Content = new(); 9 | 10 | public CodeWriter() 11 | { 12 | _scopeTracker = new ScopeTracker(this); //We only need one. It can be reused. 13 | } 14 | 15 | public int IndentLevel { get; private set; } 16 | 17 | public void Append(string line) 18 | => Content.Append(line); 19 | 20 | public void AppendLine(string line) 21 | => Content.Append(new string(' ', IndentLevel)).AppendLine(line); 22 | 23 | public void AppendLine() 24 | => Content.AppendLine(); 25 | 26 | public IDisposable BeginScope(string line) 27 | { 28 | AppendLine(line); 29 | return BeginScope(); 30 | } 31 | 32 | public IDisposable BeginScope() 33 | { 34 | Content.Append(new string(' ', IndentLevel)).AppendLine("{"); 35 | IndentLevel += 4; 36 | return _scopeTracker; 37 | } 38 | 39 | public void EndLine() => Content.AppendLine(); 40 | 41 | public void EndScope() 42 | { 43 | IndentLevel -= 4; 44 | Content.Append(new string(' ', IndentLevel)).AppendLine("}"); 45 | } 46 | 47 | public void StartLine() 48 | => Content.Append(new string(' ', IndentLevel)); 49 | 50 | public override string ToString() 51 | => Content.ToString(); 52 | 53 | private class ScopeTracker : IDisposable 54 | { 55 | public ScopeTracker(CodeWriter parent) 56 | { 57 | Parent = parent; 58 | } 59 | 60 | public CodeWriter Parent { get; } 61 | 62 | public void Dispose() => Parent.EndScope(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Gel.Net.Driver/Utils/ReflectionUtils.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace Gel; 4 | 5 | internal static class ReflectionUtils 6 | { 7 | public static bool IsSubclassOfRawGeneric(Type generic, Type? toCheck) 8 | { 9 | while (toCheck is not null && toCheck != typeof(object)) 10 | { 11 | var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck; 12 | if (generic == cur) 13 | { 14 | return true; 15 | } 16 | 17 | toCheck = toCheck.BaseType; 18 | } 19 | 20 | return false; 21 | } 22 | 23 | public static bool TryGetRawGeneric(Type generic, Type? toCheck, out Type? genericReference) 24 | { 25 | genericReference = null; 26 | 27 | while (toCheck is not null && toCheck != typeof(object)) 28 | { 29 | var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck; 30 | if (generic == cur) 31 | { 32 | genericReference = toCheck; 33 | 34 | return true; 35 | } 36 | 37 | toCheck = toCheck.BaseType; 38 | } 39 | 40 | return false; 41 | } 42 | 43 | public static object? DynamicCast(object? entity, Type to) 44 | => typeof(ReflectionUtils).GetMethod("Cast", BindingFlags.Static | BindingFlags.NonPublic)! 45 | .MakeGenericMethod(to).Invoke(null, new[] {entity}); 46 | 47 | private static T? Cast(object? entity) 48 | => (T?)entity; 49 | 50 | public static object? GetDefault(Type t) 51 | => typeof(ReflectionUtils).GetMethod("GetDefaultGeneric", BindingFlags.Static | BindingFlags.NonPublic)! 52 | .MakeGenericMethod(t).Invoke(null, null); 53 | 54 | private static object? GetDefaultGeneric() => default(T); 55 | } 56 | --------------------------------------------------------------------------------