diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml
index 923bc255..1e4c0547 100644
--- a/.github/workflows/build-and-test.yml
+++ b/.github/workflows/build-and-test.yml
@@ -35,9 +35,11 @@ jobs:
- name: Test
run: ./test.sh
env:
+ TEST_HOST_WRITE: "https://greenfield.cognitedata.com"
TEST_TENANT_ID_WRITE: ${{ secrets.TEST_TENANT_ID_WRITE }}
TEST_CLIENT_ID_WRITE: ${{ secrets.TEST_CLIENT_ID_WRITE }}
TEST_CLIENT_SECRET_WRITE: ${{ secrets.TEST_CLIENT_SECRET_WRITE }}
+ TEST_HOST_READ: "https://api.cognitedata.com"
TEST_TENANT_ID_READ: ${{ secrets.TEST_TENANT_ID_READ }}
TEST_CLIENT_ID_READ: ${{ secrets.TEST_CLIENT_ID_READ }}
TEST_CLIENT_SECRET_READ: ${{ secrets.TEST_CLIENT_SECRET_READ }}
diff --git a/CogniteSdk.Types/Alpha/Simulators/SimulatorConverters.cs b/CogniteSdk.Types/Alpha/Simulators/SimulatorConverters.cs
index d65ce41e..ab073eac 100644
--- a/CogniteSdk.Types/Alpha/Simulators/SimulatorConverters.cs
+++ b/CogniteSdk.Types/Alpha/Simulators/SimulatorConverters.cs
@@ -45,7 +45,8 @@ public override SimulatorValue Read(ref Utf8JsonReader reader, Type typeToConver
if (listStr.Count > 0 && listDbl.Count > 0)
{
throw new JsonException("Unable to parse value of type: mixed array");
- } else if (listStr.Count > 0)
+ }
+ else if (listStr.Count > 0)
{
return SimulatorValue.Create(listStr);
}
diff --git a/CogniteSdk.Types/Beta/StreamRecords/Stream.cs b/CogniteSdk.Types/Beta/StreamRecords/Stream.cs
new file mode 100644
index 00000000..183535ad
--- /dev/null
+++ b/CogniteSdk.Types/Beta/StreamRecords/Stream.cs
@@ -0,0 +1,30 @@
+// Copyright 2024 Cognite AS
+// SPDX-License-Identifier: Apache-2.0
+
+namespace CogniteSdk.Beta
+{
+ ///
+ /// Request to create a stream.
+ ///
+ public class StreamWrite
+ {
+ ///
+ /// Stream external ID. Must be unique within the project and a valid stream identifier.
+ /// Stream identifiers can only consist of alphanumeric characters, hyphens, and underscores.
+ /// It must not start with cdf_ or cognite_, as those are reserved for future use.
+ /// Stream id cannot be "logs" or "records". Max length is 100 characters.
+ ///
+ public string ExternalId { get; set; }
+ }
+
+ ///
+ /// A stream.
+ ///
+ public class Stream : StreamWrite
+ {
+ ///
+ /// Time the stream was created, in milliseconds since epoch.
+ ///
+ public long CreatedTime { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/CogniteSdk.Types/Beta/StreamRecords/StreamRecord.cs b/CogniteSdk.Types/Beta/StreamRecords/StreamRecord.cs
new file mode 100644
index 00000000..9ab05996
--- /dev/null
+++ b/CogniteSdk.Types/Beta/StreamRecords/StreamRecord.cs
@@ -0,0 +1,29 @@
+// Copyright 2024 Cognite AS
+// SPDX-License-Identifier: Apache-2.0
+
+using CogniteSdk.DataModels;
+
+namespace CogniteSdk.Beta
+{
+ ///
+ /// A retrieved stream record.
+ ///
+ /// Type of the properties bag.
+ public class StreamRecord
+ {
+ ///
+ /// Id of the space the record belongs to.
+ ///
+ public string Space { get; set; }
+ ///
+ /// The number of milliseconds since 00:00:00 Thursday 1 January 1970, Coordinated
+ /// Unversal Time (UTC) minus leap seconds.
+ ///
+ public long CreatedTime { get; set; }
+ ///
+ /// Spaces to containers to properties and their values for the requested containers.
+ /// You can use as a fallback for generic results here.
+ ///
+ public T Properties { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/CogniteSdk.Types/Beta/StreamRecords/StreamRecordIngest.cs b/CogniteSdk.Types/Beta/StreamRecords/StreamRecordIngest.cs
new file mode 100644
index 00000000..555dbb33
--- /dev/null
+++ b/CogniteSdk.Types/Beta/StreamRecords/StreamRecordIngest.cs
@@ -0,0 +1,35 @@
+// Copyright 2024 Cognite AS
+// SPDX-License-Identifier: Apache-2.0
+
+using System.Collections.Generic;
+using CogniteSdk.DataModels;
+
+namespace CogniteSdk.Beta
+{
+ ///
+ /// Stream record to ingest.
+ ///
+ public class StreamRecordWrite
+ {
+ ///
+ /// Id of the space the record belongs to.
+ ///
+ public string Space { get; set; }
+ ///
+ /// List of source properties to write. The properties are from the container(s) making up this record.
+ /// Note that `InstanceData` is abstract, you should generally use `InstanceData[T]`
+ /// to assign types to the record item, but since record sources currently only write to
+ /// containers, it is usually impossible to assign only a single type to the records.
+ ///
+ /// As a fallback, you can use .
+ ///
+ public IEnumerable Sources { get; set; }
+ }
+
+ ///
+ /// Insertion request for records.
+ ///
+ public class StreamRecordIngest : ItemsWithoutCursor
+ {
+ }
+}
\ No newline at end of file
diff --git a/CogniteSdk.Types/Beta/StreamRecords/StreamRecordRetrieve.cs b/CogniteSdk.Types/Beta/StreamRecords/StreamRecordRetrieve.cs
new file mode 100644
index 00000000..0e9b8120
--- /dev/null
+++ b/CogniteSdk.Types/Beta/StreamRecords/StreamRecordRetrieve.cs
@@ -0,0 +1,165 @@
+// Copyright 2024 Cognite AS
+// SPDX-License-Identifier: Apache-2.0
+
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
+using CogniteSdk.DataModels;
+
+namespace CogniteSdk.Beta
+{
+ ///
+ /// Sources to retrieve stream record data from.
+ ///
+ public class StreamRecordSource
+ {
+ ///
+ /// Container reference.
+ ///
+ public ContainerIdentifier Source { get; set; }
+ ///
+ /// List of properties to retrieve.
+ ///
+ public IEnumerable Properties { get; set; }
+ }
+
+ ///
+ /// Optional attribute to extend the filter with full text search capabilities for
+ /// a single query in the list of record properties with OR logic.
+ ///
+ public class StreamRecordSearch
+ {
+ ///
+ /// Query string that will be parsed and used for search.
+ ///
+ public string Query { get; set; }
+ ///
+ /// Array of property identifiers to search through.
+ ///
+ public IEnumerable> Properties { get; set; }
+ }
+
+ ///
+ /// Filter on records created within the provided range.
+ ///
+ public class CreatedTimeFilter
+ {
+ ///
+ /// Value must be greater than this
+ ///
+ [JsonPropertyName("gt")]
+ public IDMSValue GreaterThan { get; set; }
+
+ ///
+ /// Value must be greater than or equal to this
+ ///
+ [JsonPropertyName("gte")]
+ public IDMSValue GreaterThanEqual { get; set; }
+
+ ///
+ /// Value must be less than this
+ ///
+ [JsonPropertyName("lt")]
+ public IDMSValue LessThan { get; set; }
+
+ ///
+ /// Value must be less than or equal to this
+ ///
+ [JsonPropertyName("lte")]
+ public IDMSValue LessThanEqual { get; set; }
+ }
+
+ ///
+ /// Specification for sorting retrieved records.
+ ///
+ public class StreamRecordsSort
+ {
+ ///
+ /// Property you want to sort on.
+ ///
+ public IEnumerable Property { get; set; }
+ ///
+ /// Sort direction.
+ ///
+ public SortDirection? Direction { get; set; }
+ }
+
+ ///
+ /// Retrieve stream records.
+ ///
+ public class StreamRecordsRetrieve
+ {
+ ///
+ /// Name of the stream where records are located, required.
+ ///
+ public string Stream { get; set; }
+ ///
+ /// List of containers and the properties that should be selected.
+ ///
+ /// Optional, if this is left out all properties are returned.
+ ///
+ public IEnumerable Sources { get; set; }
+ ///
+ /// A filter Domain Specific Language (DSL) used to create advanced filter queries.
+ ///
+ /// Note that some filter types are not supported, see API docs.
+ ///
+ public IDMSFilter Filter { get; set; }
+ ///
+ /// Matches records with created time within the provided range.
+ ///
+ public CreatedTimeFilter CreatedTime { get; set; }
+ ///
+ /// Maximum number of results to return. Default 10, max 10000.
+ ///
+ public int? Limit { get; set; }
+ ///
+ /// Ordered list of sorting specifications.
+ ///
+ public IEnumerable Sort { get; set; }
+ }
+
+
+ ///
+ /// Request for syncing records.
+ ///
+ public class StreamRecordsSync
+ {
+ ///
+ /// List of containers and the properties that should be selected.
+ ///
+ /// Optional, if this is left out all properties are returned.
+ ///
+ public IEnumerable Sources { get; set; }
+ ///
+ /// A filter Domain Specific Language (DSL) used to create advanced filter queries.
+ ///
+ /// Note that some filter types are not supported, see API docs.
+ ///
+ public IDMSFilter Filter { get; set; }
+ ///
+ /// A cursor returned from the previous sync request.
+ ///
+ public string Cursor { get; set; }
+ ///
+ /// Maximum number of results to return.
+ ///
+ public int? Limit { get; set; }
+ ///
+ /// Initialize cursor. Required if `Cursor` is not set.
+ ///
+ public bool InitializeCursor { get; set; }
+ }
+
+ ///
+ /// Response from a sync request.
+ ///
+ /// Type of properties in returned records.
+ public class StreamRecordsSyncResponse : ItemsWithCursor>
+ {
+ ///
+ /// The attribute indiciates if there are more records to read in storage,
+ /// or if the cursor points to the last item.
+ ///
+ public bool HasNext { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/CogniteSdk.Types/Common/Converters.cs b/CogniteSdk.Types/Common/Converters.cs
index 1c28b766..739ee1af 100644
--- a/CogniteSdk.Types/Common/Converters.cs
+++ b/CogniteSdk.Types/Common/Converters.cs
@@ -142,7 +142,7 @@ private string ReadValue(ref Utf8JsonReader reader, JsonSerializerOptions option
return number.ToString();
}
return reader.GetDouble().ToString();
- default:
+ default:
throw new JsonException($"'{reader.TokenType}' is not supported");
}
}
diff --git a/CogniteSdk/src/Resources/Beta.cs b/CogniteSdk/src/Resources/Beta.cs
index b07bb0a7..a1d9d8f6 100644
--- a/CogniteSdk/src/Resources/Beta.cs
+++ b/CogniteSdk/src/Resources/Beta.cs
@@ -25,6 +25,11 @@ public class BetaResource : Resource
///
public SubscriptionsResource Subscriptions { get; }
+ ///
+ /// Resource for Stream Records.
+ ///
+ public StreamRecordsResource StreamRecords { get; }
+
///
/// Will only be instantiated by the client.
///
@@ -34,6 +39,7 @@ internal BetaResource(Func> authHandler, FSharpF
{
Templates = new TemplatesResource(authHandler, ctx);
Subscriptions = new SubscriptionsResource(authHandler, ctx);
+ StreamRecords = new StreamRecordsResource(authHandler, ctx);
}
}
}
diff --git a/CogniteSdk/src/Resources/Beta/StreamRecords.cs b/CogniteSdk/src/Resources/Beta/StreamRecords.cs
new file mode 100644
index 00000000..4ff61ee3
--- /dev/null
+++ b/CogniteSdk/src/Resources/Beta/StreamRecords.cs
@@ -0,0 +1,141 @@
+// Copyright 2024 Cognite AS
+// SPDX-License-Identifier: Apache-2.0
+
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using CogniteSdk.Beta;
+using Microsoft.FSharp.Core;
+using Oryx;
+
+namespace CogniteSdk.Resources.Beta
+{
+ ///
+ /// Contains methods for stream records.
+ ///
+ public class StreamRecordsResource : Resource
+ {
+ internal StreamRecordsResource(Func> authHandler, FSharpFunc, Task> ctx) : base(authHandler, ctx)
+ {
+ }
+
+ ///
+ /// Creates a list of records in the provided stream.
+ ///
+ /// Stream to ingest records into.
+ /// Records to ingest.
+ /// Optional cancellation token
+ public async Task IngestAsync(string stream, IEnumerable records, CancellationToken token = default)
+ {
+ if (stream is null)
+ {
+ throw new ArgumentNullException(nameof(stream));
+ }
+
+ var req = Oryx.Cognite.Beta.StreamRecords.ingest(stream, new StreamRecordIngest
+ {
+ Items = records,
+ }, GetContext(token));
+ await RunAsync(req).ConfigureAwait(false);
+ }
+
+ ///
+ /// Retrieve a list of records.
+ ///
+ /// Type of properties in the retrieved records.
+ /// Stream to ingest records into.
+ /// record retrieval request.
+ /// Optional cancellation token.
+ /// Retrieved records.
+ public async Task>> RetrieveAsync(string stream, StreamRecordsRetrieve request, CancellationToken token = default)
+ {
+ if (request is null)
+ {
+ throw new ArgumentNullException(nameof(request));
+ }
+
+ var req = Oryx.Cognite.Beta.StreamRecords.retrieve(stream, request, GetContext(token));
+ return await RunAsync(req).ConfigureAwait(false);
+ }
+
+ ///
+ /// Synchronizes updates to records. This endpoint will always return a cursor.
+ ///
+ /// Type of properties in the retrieved records.
+ /// Stream to ingest records into.
+ /// record retreival request.
+ /// Optional cancellation token.
+ /// Sync response.
+ public async Task> SyncAsync(string stream, StreamRecordsSync request, CancellationToken token = default)
+ {
+ if (request is null)
+ {
+ throw new ArgumentNullException(nameof(request));
+ }
+
+ var req = Oryx.Cognite.Beta.StreamRecords.sync(stream, request, GetContext(token));
+ return await RunAsync(req).ConfigureAwait(false);
+ }
+
+ ///
+ /// Create a new stream. A stream is a target for high volume data ingestion,
+ /// with data shaped by the Data Modeling concepts.
+ /// For beta we allow each project to create up to 10 streams.
+ ///
+ /// Stream to create
+ /// Optional cancellation token
+ /// Created stream
+ public async Task CreateStreamAsync(StreamWrite stream, CancellationToken token = default)
+ {
+ if (stream is null)
+ {
+ throw new ArgumentNullException(nameof(stream));
+ }
+
+ var req = Oryx.Cognite.Beta.StreamRecords.createStream(stream, GetContext(token));
+ return await RunAsync(req).ConfigureAwait(false);
+ }
+
+ /* Unimplemented
+ ///
+ /// Delete a stream by its identifier.
+ ///
+ /// Stream to delete
+ /// Optional cancellation token
+ public async Task DeleteStreamAsync(string stream, CancellationToken token = default)
+ {
+ if (stream is null)
+ {
+ throw new ArgumentNullException(nameof(stream));
+ }
+
+ var req = Oryx.Cognite.Beta.StreamRecords.deleteStream(stream, GetContext(token));
+ await RunAsync(req).ConfigureAwait(false);
+ }
+ */
+
+ ///
+ /// List all streams in the project.
+ ///
+ /// Optional cancellation token
+ /// Listed streams.
+ public async Task> ListStreamsAsync(CancellationToken token = default)
+ {
+ var req = Oryx.Cognite.Beta.StreamRecords.listStreams(GetContext(token));
+ return await RunAsync(req).ConfigureAwait(false);
+ }
+
+ ///
+ /// Retrieve a stream by its identifier.
+ ///
+ /// Stream to retrieve
+ /// Optional cancellation token
+ /// Retrieved stream
+ public async Task RetrieveStreamAsync(string stream, CancellationToken token = default)
+ {
+ var req = Oryx.Cognite.Beta.StreamRecords.retrieveStream(stream, GetContext(token));
+ return await RunAsync(req).ConfigureAwait(false);
+ }
+ }
+}
\ No newline at end of file
diff --git a/CogniteSdk/test/csharp/StreamRecords.cs b/CogniteSdk/test/csharp/StreamRecords.cs
new file mode 100644
index 00000000..ffe11dbc
--- /dev/null
+++ b/CogniteSdk/test/csharp/StreamRecords.cs
@@ -0,0 +1,176 @@
+// Copyright 2024 Cognite AS
+// SPDX-License-Identifier: Apache-2.0
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using CogniteSdk;
+using CogniteSdk.Beta;
+using CogniteSdk.DataModels;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Test.CSharp.Integration
+{
+ public class StreamRecordsFixture : TestFixture, IAsyncLifetime
+ {
+ public Client Write => WriteClient;
+
+ public string TestSpace { get; private set; }
+ public string TestStream { get; private set; }
+
+ public ContainerIdentifier TestContainer { get; private set; }
+
+ public override async Task InitializeAsync()
+ {
+ // Share space cross-tests because space existence is eventually consistent in
+ // stream records...
+ TestSpace = "SdkTestStreamRecordsSpace";
+
+ var testSpace = new SpaceCreate { Space = TestSpace };
+
+ await Write.DataModels.UpsertSpaces(new[] { testSpace });
+
+ var testContainer = new ContainerCreate
+ {
+ ExternalId = "TestContainer",
+ Space = TestSpace,
+ Name = "Test",
+ UsedFor = UsedFor.all,
+ Properties = new Dictionary
+ {
+ { "prop", new ContainerPropertyDefinition
+ {
+ Type = BasePropertyType.Text(),
+ Nullable = true,
+ } },
+ { "intProp", new ContainerPropertyDefinition
+ {
+ Type = BasePropertyType.Create(PropertyTypeVariant.int64),
+ Nullable = true,
+ } },
+ { "boolArrayProp", new ContainerPropertyDefinition
+ {
+ Type = BasePropertyType.Create(PropertyTypeVariant.boolean, true),
+ Nullable = true,
+ }}
+ }
+ };
+ var testContainerIdt = new ContainerIdentifier(TestSpace, "TestContainer");
+
+ await Write.DataModels.UpsertContainers(new[] { testContainer });
+ TestContainer = testContainerIdt;
+
+ TestStream = "dotnet-sdk-test-stream";
+
+ // Try to create the stream, ignore errors. Streams cannot currently
+ // be deleted, and there is a limit on the count per project, so we can't create
+ // one per test run.
+ try
+ {
+ await Write.Beta.StreamRecords.CreateStreamAsync(new StreamWrite
+ {
+ ExternalId = TestStream
+ });
+ }
+ catch (ResponseException ex) when (ex.Code == 409) { }
+ }
+ }
+
+ public class StreamRecordsTest : IClassFixture
+ {
+ private readonly StreamRecordsFixture tester;
+ private readonly int perTestUniqueInt;
+
+ private static int testCounter = 0;
+ public StreamRecordsTest(StreamRecordsFixture tester)
+ {
+ this.tester = tester;
+ perTestUniqueInt = Interlocked.Increment(ref testCounter);
+ }
+
+ [Fact]
+ public async Task TestListRetrieveStreams()
+ {
+ var streams = await tester.Write.Beta.StreamRecords.ListStreamsAsync();
+ Assert.Contains(streams, s => s.ExternalId == tester.TestStream);
+
+ var retrieved = await tester.Write.Beta.StreamRecords.RetrieveStreamAsync(tester.TestStream);
+ Assert.Equal(tester.TestStream, retrieved.ExternalId);
+ }
+
+ [Fact]
+ public async Task TestIngestRecords()
+ {
+ // Create some records
+ var req = new[] {
+ new StreamRecordWrite {
+ Space = tester.TestSpace,
+ Sources = new[] {
+ new InstanceData
+ {
+ Source = tester.TestContainer,
+ Properties = new StandardInstanceWriteData
+ {
+ { "prop", new RawPropertyValue("Test value") },
+ { "intProp", new RawPropertyValue(perTestUniqueInt) },
+ { "boolArrayProp", new RawPropertyValue(new[] {
+ true, false, true
+ })}
+ }
+ }
+ }
+ },
+ new StreamRecordWrite {
+ Space = tester.TestSpace,
+ Sources = new[] {
+ new InstanceData
+ {
+ Source = tester.TestContainer,
+ Properties = new StandardInstanceWriteData
+ {
+ { "prop", new RawPropertyValue("Test value 2") },
+ { "intProp", new RawPropertyValue(perTestUniqueInt) },
+ { "boolArrayProp", new RawPropertyValue(new[] {
+ false, true, false
+ })}
+ }
+ }
+ }
+ }
+ };
+
+ await tester.Write.Beta.StreamRecords.IngestAsync(tester.TestStream, req);
+ }
+
+ [Fact]
+ public async Task TestRetrieveRecords()
+ {
+ // The stream records API is so eventually consistent that this test would take
+ // way too long to run. Just test that we can send a request without failing.
+ var start = DateTimeOffset.UtcNow.AddMinutes(-1).ToUnixTimeMilliseconds();
+ await tester.Write.Beta.StreamRecords.RetrieveAsync(
+ tester.TestStream,
+ new StreamRecordsRetrieve
+ {
+ CreatedTime = new CreatedTimeFilter
+ {
+ GreaterThan = new RawPropertyValue(start),
+ LessThan = new RawPropertyValue(start + 1000 * 60 * 5),
+ },
+ Filter = new EqualsFilter
+ {
+ Property = new[] { tester.TestSpace, tester.TestContainer.ExternalId, "intProp" },
+ Value = new RawPropertyValue(perTestUniqueInt),
+ },
+ Limit = 123,
+ Sort = new[] { new StreamRecordsSort {
+ Property = new[] { tester.TestSpace, tester.TestContainer.ExternalId, "intProp"}
+ }}
+ }
+ );
+ }
+ }
+}
\ No newline at end of file
diff --git a/Oryx.Cognite/src/Beta/StreamRecords.fs b/Oryx.Cognite/src/Beta/StreamRecords.fs
new file mode 100644
index 00000000..bc64c211
--- /dev/null
+++ b/Oryx.Cognite/src/Beta/StreamRecords.fs
@@ -0,0 +1,90 @@
+// Copyright 2024 Cognite AS
+// SPDX-License-Identifier: Apache-2.0
+
+namespace Oryx.Cognite.Beta
+
+open Oryx
+open Oryx.Cognite
+open Oryx.Cognite.Beta
+
+open CogniteSdk.Beta
+
+[]
+module StreamRecords =
+ []
+ let Url = "/streams"
+
+ let ingest
+ (stream: string)
+ (items: StreamRecordIngest)
+ (source: HttpHandler)
+ : HttpHandler =
+ source
+ |> withLogMessage "streamrecords:ingest"
+ |> withAlphaHeader
+ |> postV10 items (Url +/ stream +/ "records")
+
+ let retrieve<'T>
+ (stream: string)
+ (request: StreamRecordsRetrieve)
+ (source: HttpHandler)
+ : HttpHandler seq> =
+ http {
+ let! ret =
+ source
+ |> withLogMessage "streamrecords:retrieve"
+ |> withAlphaHeader
+ |> withCompletion System.Net.Http.HttpCompletionOption.ResponseHeadersRead
+ |> postV10<_, CogniteSdk.ItemsWithoutCursor<_>> request (Url +/ stream +/ "records/filter")
+
+ return ret.Items
+ }
+
+ let sync<'T>
+ (stream: string)
+ (request: StreamRecordsSync)
+ (source: HttpHandler)
+ : HttpHandler> =
+ source
+ |> withLogMessage "streamrecords:sync"
+ |> withAlphaHeader
+ |> withCompletion System.Net.Http.HttpCompletionOption.ResponseHeadersRead
+ |> postV10 request (Url +/ stream +/ "records/sync")
+
+ let createStream (stream: StreamWrite) (source: HttpHandler) : HttpHandler =
+ http {
+ let request = CogniteSdk.ItemsWithoutCursor(Items = [ stream ])
+
+ let! ret =
+ source
+ |> withLogMessage "streamrecords:createstream"
+ |> withAlphaHeader
+ |> postV10<_, CogniteSdk.ItemsWithoutCursor<_>> request Url
+
+ return Seq.exactlyOne (ret.Items)
+ }
+
+ // Unimplemented
+ // let deleteStream (stream: string) (source: HttpHandler) : HttpHandler =
+ // source
+ // |> withLogMessage "streamrecords:deletestream"
+ // |> withAlphaHeader
+ // |> deleteV10 (Url +/ stream)
+
+ let listStreams (source: HttpHandler) : HttpHandler =
+ http {
+ let! ret =
+ source
+ |> withLogMessage "streamrecords:liststreams"
+ |> withAlphaHeader
+ |> withCompletion System.Net.Http.HttpCompletionOption.ResponseHeadersRead
+ |> getV10> Url
+
+ return ret.Items
+ }
+
+ let retrieveStream (stream: string) (source: HttpHandler) : HttpHandler =
+ source
+ |> withLogMessage "streamrecords:retrievestream"
+ |> withAlphaHeader
+ |> getV10 (Url +/ stream)
diff --git a/Oryx.Cognite/src/Handler.fs b/Oryx.Cognite/src/Handler.fs
index 4ec56f44..cdbf18ec 100644
--- a/Oryx.Cognite/src/Handler.fs
+++ b/Oryx.Cognite/src/Handler.fs
@@ -217,6 +217,16 @@ module HttpHandler =
let getV10<'TResult> (url: string) source =
source |> withVersion V10 |> get<'TResult> url
+ let deleteV10<'TResult> (url: string) (source: HttpHandler) =
+ source
+ |> withVersion V10
+ |> DELETE
+ |> withResource url
+ |> fetch
+ |> withError decodeError
+ |> json<'TResult> jsonOptions
+ |> log
+
let getV10Options<'TResult>
(url: string)
(options: JsonSerializerOptions)
diff --git a/Oryx.Cognite/src/Oryx.Cognite.fsproj b/Oryx.Cognite/src/Oryx.Cognite.fsproj
index d4f83b67..bf6d063a 100644
--- a/Oryx.Cognite/src/Oryx.Cognite.fsproj
+++ b/Oryx.Cognite/src/Oryx.Cognite.fsproj
@@ -37,6 +37,7 @@
+
diff --git a/test_auth.sh b/test_auth.sh
index b359d0e3..4df35138 100644
--- a/test_auth.sh
+++ b/test_auth.sh
@@ -5,14 +5,14 @@ TOKEN_WRITE=$(curl -sX POST \
-F client_id="$TEST_CLIENT_ID_WRITE" \
-F client_secret="$TEST_CLIENT_SECRET_WRITE" \
-F grant_type='client_credentials' \
--F scope='https://greenfield.cognitedata.com/.default' "https://login.microsoftonline.com/$TEST_TENANT_ID_WRITE/oauth2/v2.0/token" | jq -j '.access_token')
+-F scope="$TEST_HOST_WRITE/.default" "https://login.microsoftonline.com/$TEST_TENANT_ID_WRITE/oauth2/v2.0/token" | jq -j '.access_token')
TOKEN_READ=$(curl -sX POST \
--fail \
-F client_id="$TEST_CLIENT_ID_READ" \
-F client_secret="$TEST_CLIENT_SECRET_READ" \
-F grant_type='client_credentials' \
--F scope='https://api.cognitedata.com/.default' "https://login.microsoftonline.com/$TEST_TENANT_ID_READ/oauth2/v2.0/token" | jq -j '.access_token')
+-F scope="$TEST_HOST_READ/.default" "https://login.microsoftonline.com/$TEST_TENANT_ID_READ/oauth2/v2.0/token" | jq -j '.access_token')
if [[ -z "$TOKEN_WRITE" ]]
then