Skip to content

Commit

Permalink
feat: allow project_id to be optional in projection class (#78)
Browse files Browse the repository at this point in the history
* make project id optional on projection class
  • Loading branch information
rguo123 authored Sep 26, 2024
1 parent 7bbc014 commit e82b9da
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 13 deletions.
69 changes: 56 additions & 13 deletions src/projection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ type TagStatus = {
is_complete: boolean;
};

type DatasetIdResponse = {
dataset_id: UUID;
index_id: UUID;
};

export class AtlasProjection extends BaseAtlasClass<
components['schemas']['ProjectionResponse']
> {
Expand All @@ -102,7 +107,8 @@ export class AtlasProjection extends BaseAtlasClass<
* at a point in time. Every projection belongs to a Dataset.
*/
_project?: AtlasDataset;
project_id: UUID;
protected project_id?: UUID;
_project_id_promise?: Promise<UUID>;
_index?: AtlasIndex;

/**
Expand All @@ -119,16 +125,13 @@ export class AtlasProjection extends BaseAtlasClass<
const { project, project_id } = options;
super(user || project?.viewer);

if (project_id === undefined && project === undefined) {
throw new Error('project_id or project is required');
}
if (project_id !== undefined && project !== undefined) {
throw new Error('project_id and project are mutually exclusive');
}

if (project_id !== undefined) {
this.project_id = project_id;
} else {
} else if (project !== undefined) {
this.project_id = project!.id;
this._project = project;
}
Expand All @@ -137,6 +140,36 @@ export class AtlasProjection extends BaseAtlasClass<
}
}

/**
* @returns the UUID of the dataset that this projection belongs to.
*/
async datasetId(): Promise<UUID> {
if (this.project_id !== undefined) {
return this.project_id;
}
if (this._project !== undefined) {
return this._project.id;
}

const endpoint = `/v1/project/projection/${this.id}/get/dataset_id`;

if (this._project_id_promise !== undefined) {
return this._project_id_promise;
}

this._project_id_promise = (
this.apiCall(endpoint, 'GET') as Promise<DatasetIdResponse>
).then(
// Assign it to the project id while returning.
({ dataset_id }) => {
this.project_id = dataset_id;
return dataset_id;
}
);

return this._project_id_promise;
}

async createTag(options: CreateTagOptions): Promise<TagResponse> {
const endpoint = '/v1/project/projection/tags/create';
const { tag_name, dsl_rule, tag_definition_id } = options;
Expand All @@ -148,9 +181,9 @@ export class AtlasProjection extends BaseAtlasClass<
if (dsl_rule === undefined) {
throw new Error('dsl_rule is required');
}

const project_id = await this.datasetId();
const data = {
project_id: this.project_id,
project_id: project_id,
tag_name,
dsl_rule: JSON.stringify(dsl_rule),
projection_id: this.id,
Expand Down Expand Up @@ -192,16 +225,17 @@ export class AtlasProjection extends BaseAtlasClass<
throw new Error('tag_id is required');
}
const data = {
project_id: this.project_id,
project_id: await this.datasetId(),
tag_id,
};
await this.apiCall(endpoint, 'POST', data);
}

async getTags(): Promise<Array<TagResponse>> {
const endpoint = '/v1/project/projection/tags/get/all';
const project_id = await this.datasetId();
const params = new URLSearchParams({
project_id: this.project_id,
project_id: project_id,
projection_id: this.id,
}).toString();
return this.apiCall(`${endpoint}?${params}`, 'GET') as Promise<
Expand All @@ -214,9 +248,10 @@ export class AtlasProjection extends BaseAtlasClass<
if (tag_id === undefined) {
throw new Error('tag_id is required');
}
const project_id = await this.datasetId();
const endpoint = '/v1/project/projection/tags/status';
const params = new URLSearchParams({
project_id: this.project_id,
project_id: project_id,
tag_id,
}).toString();
return this.apiCall(`${endpoint}?${params}`, 'GET') as Promise<TagStatus>;
Expand All @@ -228,6 +263,7 @@ export class AtlasProjection extends BaseAtlasClass<
): Promise<void> {
const endpoint = '/v1/project/projection/tags/update/mask';
const { tag_id, tag_definition_id, complete } = options;
const project_id = await this.datasetId();

// Upsert tag mask with tag definition id
let post_tag_definition_id = tag_definition_id;
Expand All @@ -240,7 +276,7 @@ export class AtlasProjection extends BaseAtlasClass<
const bitmask = tableFromIPC(bitmask_bytes);

bitmask.schema.metadata.set('tag_id', tag_id as string);
bitmask.schema.metadata.set('project_id', this.project_id);
bitmask.schema.metadata.set('project_id', project_id);
bitmask.schema.metadata.set(
'tag_definition_id',
post_tag_definition_id as string
Expand All @@ -264,7 +300,7 @@ export class AtlasProjection extends BaseAtlasClass<
const { tag_id } = options;
const request = {
tag_id,
project_id: this.project_id,
project_id: await this.datasetId(),
};
const endpoint = '/v1/project/projection/tags/robotag';
await this.apiCall(endpoint, 'POST', request);
Expand All @@ -287,7 +323,8 @@ export class AtlasProjection extends BaseAtlasClass<

async project(): Promise<AtlasDataset> {
if (this._project === undefined) {
this._project = new AtlasDataset(this.project_id, this.viewer);
const project_id = await this.datasetId();
this._project = new AtlasDataset(project_id, this.viewer);
}
return this._project;
}
Expand Down Expand Up @@ -318,13 +355,19 @@ export class AtlasProjection extends BaseAtlasClass<
* 'public' may be be added in fetching.
*/
get quadtree_root(): string {
if (this.project_id === undefined) {
throw new Error('project_id is undefined. Fetch project_id first.');
}
const protocol = this.viewer.apiLocation.startsWith('localhost')
? 'http'
: 'https';
return `${protocol}://${this.viewer.apiLocation}/v1/project/${this.project_id}/index/projection/${this.id}/quadtree`;
}

protected endpoint() {
if (this.project_id === undefined) {
throw new Error('project_id is undefined. Fetch project_id first.');
}
return `/v1/project/${this.project_id}/index/projection/${this.id}`;
}

Expand Down
3 changes: 3 additions & 0 deletions tests/project.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ test('Full project flow', async () => {
// Re-instantiate with just the project; test if we properly infer the index.
console.log('re-instantiating projection');
const projection = new AtlasProjection(orig_projection.id, user, { project });
// Fetch dataset id from projection
const projectionWithoutId = new AtlasProjection(orig_projection.id, user);
assert.is(await projectionWithoutId.datasetId(), project.id);
const inferred_index = await projection.index();
assert.is(inferred_index.id, index.id);
// // Create a tag
Expand Down

0 comments on commit e82b9da

Please sign in to comment.