@dremio/js-sdk 0.12.2 → 0.12.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,7 @@ import { Err, Ok, Result } from "ts-results-es";
3
3
  import { type Observable } from "rxjs";
4
4
  import type { SignalParam } from "../../common/Params.ts";
5
5
  import type { JobProperties } from "./utils/jobEntityToProperties.ts";
6
+ import type { HttpError } from "../../common/HttpError.ts";
6
7
  export declare class Job {
7
8
  #private;
8
9
  readonly acceleration: JobProperties["acceleration"];
@@ -18,7 +19,7 @@ export declare class Job {
18
19
  readonly startedAt: JobProperties["startedAt"];
19
20
  readonly state: JobProperties["state"];
20
21
  readonly observer: Observable<Job>;
21
- constructor(properties: JobProperties, config: SonarV3Config, observe: (id: string) => Observable<Result<Job, unknown>>);
22
+ constructor(properties: JobProperties, config: SonarV3Config, observe: (id: string) => Observable<Result<Job, HttpError>>);
22
23
  get settled(): boolean;
23
24
  get results(): {
24
25
  jsonBatches: <T extends Record<string, unknown> = Record<string, unknown>>(args?: {
@@ -35,12 +36,12 @@ export declare class Job {
35
36
  metadata: ({ signal }?: SignalParam) => Promise<Result<{
36
37
  schema: import("./utils/JobResultsResponse.ts").JobResultsSchema<string>;
37
38
  totalRows: number;
38
- }, import("../index.ts").HttpError>>;
39
- slice: <T extends Record<string, unknown> = Record<string, unknown>>(start?: number, end?: number, { signal }?: SignalParam) => Promise<Err<unknown> | Ok<T[]>>;
39
+ }, HttpError>>;
40
+ slice: <T extends Record<string, unknown> = Record<string, unknown>>(start?: number, end?: number, { signal }?: SignalParam) => Promise<Ok<T[]> | Err<unknown>>;
40
41
  };
41
42
  /**
42
43
  * @returns A `Job` instance once it's reached a settled state
43
44
  */
44
45
  retrieveSettled(): Promise<Job>;
45
- cancel(): Promise<Result<undefined, import("../index.ts").HttpError>>;
46
+ cancel(): Promise<Result<undefined, HttpError>>;
46
47
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Job.js","sourceRoot":"","sources":["../../../src/oss/jobs/Job.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (C) 2024-2025 Dremio Corporation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { SonarV3Config } from \"../../common/Config.ts\";\nimport { Err, Ok, Result } from \"ts-results-es\";\nimport { lastValueFrom, map, of, switchMap, type Observable } from \"rxjs\";\nimport type { JobResultsResponse } from \"./utils/JobResultsResponse.ts\";\nimport { mapRowsToColumns } from \"./utils/mapRowsToColumns.ts\";\nimport { mapRowData } from \"./utils/mapRowData.ts\";\nimport type { SignalParam } from \"../../common/Params.ts\";\nimport type { JobProperties } from \"./utils/jobEntityToProperties.ts\";\n\nexport class Job {\n readonly acceleration: JobProperties[\"acceleration\"];\n readonly cancellationReason: JobProperties[\"cancellationReason\"];\n readonly errorMessage?: string;\n readonly endedAt: JobProperties[\"endedAt\"];\n readonly id: JobProperties[\"id\"];\n readonly problem: JobProperties[\"problem\"];\n readonly queryType: JobProperties[\"queryType\"];\n readonly resourceSchedulingEndedAt: JobProperties[\"resourceSchedulingEndedAt\"];\n readonly resourceSchedulingStartedAt: JobProperties[\"resourceSchedulingStartedAt\"];\n readonly rowCount: JobProperties[\"rowCount\"];\n readonly startedAt: JobProperties[\"startedAt\"];\n readonly state: JobProperties[\"state\"];\n\n public readonly observer: Observable<Job>;\n #config: SonarV3Config;\n\n constructor(\n properties: JobProperties,\n config: SonarV3Config,\n observe: (id: string) => Observable<Result<Job, unknown>>,\n ) {\n this.acceleration = properties.acceleration;\n this.cancellationReason = properties.cancellationReason;\n this.endedAt = properties.endedAt;\n this.id = properties.id;\n this.problem = properties.problem;\n this.queryType = properties.queryType;\n this.resourceSchedulingEndedAt = properties.resourceSchedulingEndedAt;\n this.resourceSchedulingStartedAt = properties.resourceSchedulingStartedAt;\n this.rowCount = properties.rowCount;\n this.startedAt = properties.startedAt;\n this.state = properties.state;\n this.#config = config;\n this.observer = of(this).pipe(\n switchMap((job) => {\n if (!job.settled) {\n return observe(this.id).pipe(\n map((result) => {\n if (result.isErr()) {\n throw result.error;\n }\n return result.value;\n }),\n );\n } else {\n return of(job);\n }\n }),\n );\n\n if (properties.errorMessage) {\n this.errorMessage = properties.errorMessage;\n }\n }\n\n get settled() {\n return (\n this.state === \"COMPLETED\" ||\n this.state === \"FAILED\" ||\n this.state === \"INVALID_STATE\" ||\n this.state === \"CANCELED\"\n );\n }\n\n get results() {\n return {\n jsonBatches: this.#jsonBatches.bind(this),\n metadata: this.#metadata.bind(this),\n slice: this.#slice.bind(this),\n };\n }\n\n /**\n * @returns A `Job` instance once it's reached a settled state\n */\n retrieveSettled() {\n return lastValueFrom(this.observer);\n }\n\n async *#jsonBatches<T extends Record<string, unknown> = Record<string, unknown>>(\n args: { limit?: number; offset?: number } = {},\n { signal }: SignalParam = {},\n ) {\n if (typeof args.limit === \"number\" && args.limit < 0) {\n throw new Error(\"Limit cannot be negative\");\n }\n\n if (typeof args.offset === \"number\" && args.offset < 0) {\n throw new Error(\"Offset cannot be negative\");\n }\n\n // Wait for job to enter a settled state before attempting to fetch batches\n if (!this.settled) {\n await this.retrieveSettled();\n }\n\n const limitArg = args.limit ?? Infinity;\n const offsetArg = args.offset || 0;\n\n // Tracks whether there are more rows available from the job results endpoint\n let hasMore = true;\n\n // Tracks the currently requested offset. If the offset arg is provided, start from there instead of 0.\n let offset = offsetArg;\n\n // Keeps track of the total number of rows that need to be loaded\n const stopAfterOffset = limitArg + offsetArg;\n\n while (hasMore && offset < stopAfterOffset) {\n // Make batch_size dynamic to allow for requesting a smaller final page\n const batch_size = Math.min(MAX_BATCH_SIZE, stopAfterOffset - offset);\n\n const batch = (\n await this.#config\n .sonarV3Request(`job/${this.id}/results?offset=${offset}&limit=${batch_size}`, { signal })\n .map((res) => res.json() as Promise<JobResultsResponse<T>>).promise\n ).unwrap();\n\n offset += batch.rows.length;\n hasMore = batch.rows.length === batch_size;\n\n if (batch.rows.length) {\n const schema = { fields: batch.schema };\n mapRowData(batch.rows, batch.schema);\n yield {\n get columns() {\n return mapRowsToColumns(batch);\n },\n rows: batch.rows,\n schema,\n totalRows: batch.rowCount,\n } as const;\n }\n }\n }\n\n async #metadata({ signal }: SignalParam = {}) {\n return this.#config\n .sonarV3Request(`job/${this.id}/results?offset=0&limit=0`, { signal })\n .map((res) => res.json() as Promise<JobResultsResponse>)\n .map((response) => ({\n schema: response.schema,\n totalRows: response.rowCount,\n })).promise;\n }\n\n async #slice<T extends Record<string, unknown> = Record<string, unknown>>(\n start: number = 0,\n end: number = Infinity,\n { signal }: SignalParam = {},\n ) {\n try {\n const rows: T[] = [];\n for await (const batch of this.#jsonBatches<T>(\n { limit: end - start, offset: start },\n { signal },\n )) {\n rows.push(...batch.rows);\n }\n return Ok(rows);\n } catch (e: unknown) {\n return Err(e);\n }\n }\n\n cancel() {\n return this.#config\n .sonarV3Request(`job/${this.id}/cancel`, {\n keepalive: true,\n method: \"POST\",\n })\n .map(() => undefined).promise;\n }\n}\n\nconst MAX_BATCH_SIZE = 500;\n"]}
1
+ {"version":3,"file":"Job.js","sourceRoot":"","sources":["../../../src/oss/jobs/Job.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (C) 2024-2025 Dremio Corporation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { SonarV3Config } from \"../../common/Config.ts\";\nimport { Err, Ok, Result } from \"ts-results-es\";\nimport { lastValueFrom, map, of, switchMap, type Observable } from \"rxjs\";\nimport type { JobResultsResponse } from \"./utils/JobResultsResponse.ts\";\nimport { mapRowsToColumns } from \"./utils/mapRowsToColumns.ts\";\nimport { mapRowData } from \"./utils/mapRowData.ts\";\nimport type { SignalParam } from \"../../common/Params.ts\";\nimport type { JobProperties } from \"./utils/jobEntityToProperties.ts\";\nimport type { HttpError } from \"../../common/HttpError.ts\";\n\nexport class Job {\n readonly acceleration: JobProperties[\"acceleration\"];\n readonly cancellationReason: JobProperties[\"cancellationReason\"];\n readonly errorMessage?: string;\n readonly endedAt: JobProperties[\"endedAt\"];\n readonly id: JobProperties[\"id\"];\n readonly problem: JobProperties[\"problem\"];\n readonly queryType: JobProperties[\"queryType\"];\n readonly resourceSchedulingEndedAt: JobProperties[\"resourceSchedulingEndedAt\"];\n readonly resourceSchedulingStartedAt: JobProperties[\"resourceSchedulingStartedAt\"];\n readonly rowCount: JobProperties[\"rowCount\"];\n readonly startedAt: JobProperties[\"startedAt\"];\n readonly state: JobProperties[\"state\"];\n\n public readonly observer: Observable<Job>;\n #config: SonarV3Config;\n\n constructor(\n properties: JobProperties,\n config: SonarV3Config,\n observe: (id: string) => Observable<Result<Job, HttpError>>,\n ) {\n this.acceleration = properties.acceleration;\n this.cancellationReason = properties.cancellationReason;\n this.endedAt = properties.endedAt;\n this.id = properties.id;\n this.problem = properties.problem;\n this.queryType = properties.queryType;\n this.resourceSchedulingEndedAt = properties.resourceSchedulingEndedAt;\n this.resourceSchedulingStartedAt = properties.resourceSchedulingStartedAt;\n this.rowCount = properties.rowCount;\n this.startedAt = properties.startedAt;\n this.state = properties.state;\n this.#config = config;\n this.observer = of(this).pipe(\n switchMap((job) => {\n if (!job.settled) {\n return observe(this.id).pipe(\n map((result) => {\n if (result.isErr()) {\n throw result.error;\n }\n return result.value;\n }),\n );\n } else {\n return of(job);\n }\n }),\n );\n\n if (properties.errorMessage) {\n this.errorMessage = properties.errorMessage;\n }\n }\n\n get settled() {\n return (\n this.state === \"COMPLETED\" ||\n this.state === \"FAILED\" ||\n this.state === \"INVALID_STATE\" ||\n this.state === \"CANCELED\"\n );\n }\n\n get results() {\n return {\n jsonBatches: this.#jsonBatches.bind(this),\n metadata: this.#metadata.bind(this),\n slice: this.#slice.bind(this),\n };\n }\n\n /**\n * @returns A `Job` instance once it's reached a settled state\n */\n retrieveSettled() {\n return lastValueFrom(this.observer);\n }\n\n async *#jsonBatches<T extends Record<string, unknown> = Record<string, unknown>>(\n args: { limit?: number; offset?: number } = {},\n { signal }: SignalParam = {},\n ) {\n if (typeof args.limit === \"number\" && args.limit < 0) {\n throw new Error(\"Limit cannot be negative\");\n }\n\n if (typeof args.offset === \"number\" && args.offset < 0) {\n throw new Error(\"Offset cannot be negative\");\n }\n\n // Wait for job to enter a settled state before attempting to fetch batches\n if (!this.settled) {\n await this.retrieveSettled();\n }\n\n const limitArg = args.limit ?? Infinity;\n const offsetArg = args.offset || 0;\n\n // Tracks whether there are more rows available from the job results endpoint\n let hasMore = true;\n\n // Tracks the currently requested offset. If the offset arg is provided, start from there instead of 0.\n let offset = offsetArg;\n\n // Keeps track of the total number of rows that need to be loaded\n const stopAfterOffset = limitArg + offsetArg;\n\n while (hasMore && offset < stopAfterOffset) {\n // Make batch_size dynamic to allow for requesting a smaller final page\n const batch_size = Math.min(MAX_BATCH_SIZE, stopAfterOffset - offset);\n\n const batch = (\n await this.#config\n .sonarV3Request(`job/${this.id}/results?offset=${offset}&limit=${batch_size}`, { signal })\n .map((res) => res.json() as Promise<JobResultsResponse<T>>).promise\n ).unwrap();\n\n offset += batch.rows.length;\n hasMore = batch.rows.length === batch_size;\n\n if (batch.rows.length) {\n const schema = { fields: batch.schema };\n mapRowData(batch.rows, batch.schema);\n yield {\n get columns() {\n return mapRowsToColumns(batch);\n },\n rows: batch.rows,\n schema,\n totalRows: batch.rowCount,\n } as const;\n }\n }\n }\n\n async #metadata({ signal }: SignalParam = {}) {\n return this.#config\n .sonarV3Request(`job/${this.id}/results?offset=0&limit=0`, { signal })\n .map((res) => res.json() as Promise<JobResultsResponse>)\n .map((response) => ({\n schema: response.schema,\n totalRows: response.rowCount,\n })).promise;\n }\n\n async #slice<T extends Record<string, unknown> = Record<string, unknown>>(\n start: number = 0,\n end: number = Infinity,\n { signal }: SignalParam = {},\n ) {\n try {\n const rows: T[] = [];\n for await (const batch of this.#jsonBatches<T>(\n { limit: end - start, offset: start },\n { signal },\n )) {\n rows.push(...batch.rows);\n }\n return Ok(rows);\n } catch (e: unknown) {\n return Err(e);\n }\n }\n\n cancel() {\n return this.#config\n .sonarV3Request(`job/${this.id}/cancel`, {\n keepalive: true,\n method: \"POST\",\n })\n .map(() => undefined).promise;\n }\n}\n\nconst MAX_BATCH_SIZE = 500;\n"]}
@@ -16,11 +16,38 @@
16
16
  import { Job } from "./Job.js";
17
17
  import { Query } from "../../common/Query.js";
18
18
  import { AsyncResult } from "ts-results-es";
19
- import { concatMap, shareReplay, takeWhile, timer } from "rxjs";
19
+ import { from, repeat, shareReplay, takeWhile, tap } from "rxjs";
20
20
  import { fromAbortable } from "../../common/fromAbortable.js";
21
21
  import { jobEntityToProperties } from "./utils/jobEntityToProperties.js";
22
+ import moize from "moize";
22
23
  export class JobsResource {
23
24
  #config;
25
+ #createJobObservable = (id) => from(fromAbortable(({ signal }) => this.retrieve(id, { signal }))).pipe(repeat({ delay: 1000 }), takeWhile((jobResult) => jobResult.isOk() && !jobResult.value.settled, true));
26
+ /**
27
+ * Reuse the same observable every time the `observe` method is called.
28
+ */
29
+ #jobObserverCache = moize.default((id) => this.#createJobObservable(id).pipe(tap({
30
+ finalize: () => {
31
+ this.#jobObserverCache.remove([id]);
32
+ },
33
+ }),
34
+ /**
35
+ * Reuse the same polling for multiple subscribers, buffering only the latest result.
36
+ * Make sure to unsubscribe from the source to stop polling when there are no subscribers (refCount: true)
37
+ */
38
+ shareReplay({
39
+ bufferSize: 1,
40
+ refCount: true,
41
+ })), {
42
+ /**
43
+ * Evict cached observables after 60s. We need some way to prevent a memory
44
+ * leak for long-running SDK processes, and a maxAge of 60 seconds should be
45
+ * enough to handle multiple subscribers attached programmatically to a job.
46
+ * If it's not, then the worst case is that we'd make additional API calls.
47
+ */
48
+ maxAge: 60_000,
49
+ maxSize: Infinity,
50
+ });
24
51
  constructor(config) {
25
52
  this.#config = config;
26
53
  }
@@ -51,29 +78,7 @@ export class JobsResource {
51
78
  return new AsyncResult(this.create(query)).andThen((jobId) => this.retrieve(jobId)).promise;
52
79
  }
53
80
  observe(id) {
54
- /**
55
- * Check every 1000ms for job status changes. 1000ms may seem too frequent,
56
- * but it helps keep the client feeling snappy, especially for jobs that complete quickly.
57
- */
58
- return timer(0, 1000).pipe(
59
- /**
60
- * Use `concatMap` instead of `switchMap` to avoid a situation where the call takes longer than
61
- * 1000ms (possibly due to network conditions or API slowdowns) which would cause switchMap to
62
- * constantly cancel unfinished requests (in which case, no requests would ever complete)
63
- */
64
- concatMap(() => fromAbortable(({ signal }) => this.retrieve(id, { signal }))),
65
- /**
66
- * Continue polling until the job has reached a settled state
67
- */
68
- takeWhile((jobResult) => jobResult.isOk() && !jobResult.value.settled, true),
69
- /**
70
- * Reuse the same polling for multiple subscribers, buffering only the latest result.
71
- * Make sure to unsubscribe from the source to stop polling when there are no subscribers (refCount: true)
72
- */
73
- shareReplay({
74
- bufferSize: 1,
75
- refCount: true,
76
- }));
81
+ return this.#jobObserverCache(id);
77
82
  }
78
83
  retrieve(id, { signal } = {}) {
79
84
  return this.#config
@@ -1 +1 @@
1
- {"version":3,"file":"JobsResource.js","sourceRoot":"","sources":["../../../src/oss/jobs/JobsResource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAkB,MAAM,kCAAkC,CAAC;AAEzF,MAAM,OAAO,YAAY;IACvB,OAAO,CAAgB;IAEvB,YAAY,MAAqB;QAC/B,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;IACxB,CAAC;IAED,cAAc,CAAC,EAAU,EAAE,MAAiB;QAC1C,OAAO,IAAI,GAAG,CAAC,qBAAqB,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3F,CAAC;IAED,MAAM,CAAC,KAAY;QACjB,OAAO,IAAI,CAAC,OAAO;aAChB,cAAc,CAAC,KAAK,EAAE;YACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,GAAG,EAAE,KAAK,CAAC,GAAG;aACf,CAAC;YACF,OAAO,EAAE;gBACP,MAAM,EAAE,kBAAkB;gBAC1B,cAAc,EAAE,kBAAkB;aACnC;YACD,SAAS,EAAE,IAAI;YACf,MAAM,EAAE,MAAM;SACf,CAAC;aACD,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,EAA6B,CAAC;aAC7D,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC;IAC5C,CAAC;IAED;;OAEG;IACH,iBAAiB,CAAC,KAAY;QAC5B,OAAO,IAAI,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;IAC9F,CAAC;IAED,OAAO,CAAC,EAAU;QAChB;;;WAGG;QACH,OAAO,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI;QACxB;;;;WAIG;QACH,SAAS,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QAC7E;;WAEG;QACH,SAAS,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC;QAC5E;;;WAGG;QACH,WAAW,CAAC;YACV,UAAU,EAAE,CAAC;YACb,QAAQ,EAAE,IAAI;SACf,CAAC,CACH,CAAC;IACJ,CAAC;IAED,QAAQ,CAAC,EAAU,EAAE,EAAE,MAAM,KAAkB,EAAE;QAC/C,OAAO,IAAI,CAAC,OAAO;aAChB,cAAc,CAAC,OAAO,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC;aACvC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,EAAwB,CAAC;aAC9C,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IAC9D,CAAC;CACF","sourcesContent":["/*\n * Copyright (C) 2024-2025 Dremio Corporation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { SonarV3Config } from \"../../common/Config.ts\";\nimport { Job } from \"./Job.ts\";\nimport { Query } from \"../../common/Query.ts\";\nimport { AsyncResult } from \"ts-results-es\";\nimport type { SignalParam } from \"../../common/Params.ts\";\nimport { concatMap, shareReplay, takeWhile, timer } from \"rxjs\";\nimport { fromAbortable } from \"../../common/fromAbortable.ts\";\nimport { jobEntityToProperties, type JobEntity } from \"./utils/jobEntityToProperties.ts\";\n\nexport class JobsResource {\n #config: SonarV3Config;\n\n constructor(config: SonarV3Config) {\n this.#config = config;\n }\n\n _jobFromEntity(id: string, entity: JobEntity): Job {\n return new Job(jobEntityToProperties(id, entity), this.#config, this.observe.bind(this));\n }\n\n create(query: Query) {\n return this.#config\n .sonarV3Request(`sql`, {\n body: JSON.stringify({\n context: query.context,\n sql: query.sql,\n }),\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n keepalive: true,\n method: \"POST\",\n })\n .map((response) => response.json() as Promise<{ id: string }>)\n .map((response) => response.id).promise;\n }\n\n /**\n * A convenience method to combine job creation and retrieval\n */\n createAndRetrieve(query: Query) {\n return new AsyncResult(this.create(query)).andThen((jobId) => this.retrieve(jobId)).promise;\n }\n\n observe(id: string) {\n /**\n * Check every 1000ms for job status changes. 1000ms may seem too frequent,\n * but it helps keep the client feeling snappy, especially for jobs that complete quickly.\n */\n return timer(0, 1000).pipe(\n /**\n * Use `concatMap` instead of `switchMap` to avoid a situation where the call takes longer than\n * 1000ms (possibly due to network conditions or API slowdowns) which would cause switchMap to\n * constantly cancel unfinished requests (in which case, no requests would ever complete)\n */\n concatMap(() => fromAbortable(({ signal }) => this.retrieve(id, { signal }))),\n /**\n * Continue polling until the job has reached a settled state\n */\n takeWhile((jobResult) => jobResult.isOk() && !jobResult.value.settled, true),\n /**\n * Reuse the same polling for multiple subscribers, buffering only the latest result.\n * Make sure to unsubscribe from the source to stop polling when there are no subscribers (refCount: true)\n */\n shareReplay({\n bufferSize: 1,\n refCount: true,\n }),\n );\n }\n\n retrieve(id: string, { signal }: SignalParam = {}) {\n return this.#config\n .sonarV3Request(`job/${id}`, { signal })\n .map((res) => res.json() as Promise<JobEntity>)\n .map((entity) => this._jobFromEntity(id, entity)).promise;\n }\n}\n"]}
1
+ {"version":3,"file":"JobsResource.js","sourceRoot":"","sources":["../../../src/oss/jobs/JobsResource.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (C) 2024-2025 Dremio Corporation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { SonarV3Config } from \"../../common/Config.ts\";\nimport { Job } from \"./Job.ts\";\nimport { Query } from \"../../common/Query.ts\";\nimport { AsyncResult } from \"ts-results-es\";\nimport type { SignalParam } from \"../../common/Params.ts\";\nimport { from, repeat, shareReplay, takeWhile, tap } from \"rxjs\";\nimport { fromAbortable } from \"../../common/fromAbortable.ts\";\nimport { jobEntityToProperties, type JobEntity } from \"./utils/jobEntityToProperties.ts\";\nimport moize from \"moize\";\n\nexport class JobsResource {\n #config: SonarV3Config;\n\n #createJobObservable = (id: string) =>\n from(fromAbortable(({ signal }) => this.retrieve(id, { signal }))).pipe(\n repeat({ delay: 1000 }),\n takeWhile((jobResult) => jobResult.isOk() && !jobResult.value.settled, true),\n );\n\n /**\n * Reuse the same observable every time the `observe` method is called.\n */\n #jobObserverCache = moize.default(\n (id: string) =>\n this.#createJobObservable(id).pipe(\n tap({\n finalize: () => {\n this.#jobObserverCache.remove([id]);\n },\n }),\n /**\n * Reuse the same polling for multiple subscribers, buffering only the latest result.\n * Make sure to unsubscribe from the source to stop polling when there are no subscribers (refCount: true)\n */\n shareReplay({\n bufferSize: 1,\n refCount: true,\n }),\n ),\n {\n /**\n * Evict cached observables after 60s. We need some way to prevent a memory\n * leak for long-running SDK processes, and a maxAge of 60 seconds should be\n * enough to handle multiple subscribers attached programmatically to a job.\n * If it's not, then the worst case is that we'd make additional API calls.\n */\n maxAge: 60_000,\n maxSize: Infinity,\n },\n );\n\n constructor(config: SonarV3Config) {\n this.#config = config;\n }\n\n _jobFromEntity(id: string, entity: JobEntity): Job {\n return new Job(jobEntityToProperties(id, entity), this.#config, this.observe.bind(this));\n }\n\n create(query: Query) {\n return this.#config\n .sonarV3Request(`sql`, {\n body: JSON.stringify({\n context: query.context,\n sql: query.sql,\n }),\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n keepalive: true,\n method: \"POST\",\n })\n .map((response) => response.json() as Promise<{ id: string }>)\n .map((response) => response.id).promise;\n }\n\n /**\n * A convenience method to combine job creation and retrieval\n */\n createAndRetrieve(query: Query) {\n return new AsyncResult(this.create(query)).andThen((jobId) => this.retrieve(jobId)).promise;\n }\n\n observe(id: string) {\n return this.#jobObserverCache(id);\n }\n\n retrieve(id: string, { signal }: SignalParam = {}) {\n return this.#config\n .sonarV3Request(`job/${id}`, { signal })\n .map((res) => res.json() as Promise<JobEntity>)\n .map((entity) => this._jobFromEntity(id, entity)).promise;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dremio/js-sdk",
3
- "version": "0.12.2",
3
+ "version": "0.12.4",
4
4
  "description": "JavaScript library for the Dremio API",
5
5
  "keywords": [
6
6
  "dremio",