Skip to content

Commit

Permalink
Update pinejs-client and make use of improved typings
Browse files Browse the repository at this point in the history
Change-type: patch
  • Loading branch information
Page- committed Jul 15, 2024
1 parent b44ec75 commit 6ad2ec9
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 108 deletions.
120 changes: 85 additions & 35 deletions lib/release/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const MAX_CONCURRENT_REQUESTS = 5;
export interface ClientConfig {
/**
* The host address of the API server to use, complete with the protocol,
* eg. `https://api.balena-cloud.com`. This module will issue requests to v4 of
* eg. `https://api.balena-cloud.com`. This module will issue requests to v6 of
* the API.
*/
apiEndpoint: string;
Expand Down Expand Up @@ -177,15 +177,23 @@ export async function updateRelease(
id: number,
body: Partial<models.ReleaseAttributes>,
): Promise<void> {
return models.update(api, 'release', id, body);
await api.patch({
resource: 'release',
id,
body,
} as const).catch(models.wrapResponseError);
}

export async function updateImage(
api: PinejsClientCore<unknown>,
id: number,
body: Partial<models.ImageAttributes>,
): Promise<void> {
return models.update(api, 'image', id, body);
await api.patch({
resource: 'image',
id,
body,
} as const).catch(models.wrapResponseError);
}

// Helpers
Expand All @@ -194,31 +202,60 @@ async function getUser(
api: PinejsClientCore<unknown>,
id: number,
): Promise<models.UserModel> {
return models.get(api, 'user', id);
const user = await api
.get({
resource: 'user',
id,
options: { $select: 'id' },
} as const)
.catch(models.wrapResponseError);
if (user == null) {
throw new Error('Could not find user with id: ' + id);
}
return user;
}

async function getApplication(
api: PinejsClientCore<unknown>,
id: number,
): Promise<models.ApplicationModel> {
return models.get(api, 'application', id);
const app = await api
.get({
resource: 'application',
id,
options: { $select: 'id' },
} as const)
.catch(models.wrapResponseError);
if (app == null) {
throw new Error('Could not find application with id: ' + id);
}
return app;
}

async function getOrCreateService(
api: PinejsClientCore<unknown>,
body: models.ServiceAttributes,
): Promise<models.ServiceModel> {
return models.getOrCreate(api, 'service', body, {
application: body.application,
service_name: body.service_name,
});
return (await api.getOrCreate({
resource: 'service',
id: {
application: body.application,
service_name: body.service_name,
},
body,
} as const).catch(models.wrapResponseError)) as models.ServiceModel;
}

async function createRelease(
api: PinejsClientCore<unknown>,
body: models.ReleaseAttributes,
): Promise<models.ReleaseModel> {
return models.create(api, 'release', body);
return (await api
.post({
resource: 'release',
body,
})
.catch(models.wrapResponseError)) as models.ReleaseModel;
}

async function createImage(
Expand All @@ -228,29 +265,37 @@ async function createImage(
envvars: Dict<string> | undefined,
body: models.ImageAttributes,
): Promise<models.ImageModel> {
const image = await models.create<models.ImageModel, models.ImageAttributes>(
api,
'image',
body,
);

const releaseImage = await models.create<
models.ReleaseImageModel,
models.ReleaseImageAttributes
>(api, 'image__is_part_of__release', {
is_part_of__release: release,
image: image.id,
});
const image = (await api
.post({
resource: 'image',
body,
} as const)
.catch(models.wrapResponseError)) as models.ImageModel;

const releaseImage = (await api
.post({
resource: 'image__is_part_of__release',
body: {
is_part_of__release: release,
image: image.id,
},
} as const)
.catch(models.wrapResponseError)) as models.ReleaseImageModel;

if (labels) {
await pMap(
Object.entries(labels),
([name, value]) => {
return models.create(api, 'image_label', {
release_image: releaseImage.id,
label_name: name,
value: (value || '').toString(),
});
async ([name, value]) => {
await api
.post({
resource: 'image_label',
body: {
release_image: releaseImage.id,
label_name: name,
value: (value || '').toString(),
},
} as const)
.catch(models.wrapResponseError);
},
{
concurrency: MAX_CONCURRENT_REQUESTS,
Expand All @@ -261,12 +306,17 @@ async function createImage(
if (envvars) {
await pMap(
Object.entries(envvars),
([name, value]) => {
return models.create(api, 'image_environment_variable', {
release_image: releaseImage.id,
name,
value: (value || '').toString(),
});
async ([name, value]) => {
await api
.post({
resource: 'image_environment_variable',
body: {
release_image: releaseImage.id,
name,
value: (value || '').toString(),
},
} as const)
.catch(models.wrapResponseError);
},
{
concurrency: MAX_CONCURRENT_REQUESTS,
Expand Down
72 changes: 2 additions & 70 deletions lib/release/models.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
import type {
Expand,
Filter,
ODataOptions,
PinejsClientCore,
} from 'pinejs-client-core';

import type { Composition } from '../../lib/parse';

import * as errors from './errors';
Expand Down Expand Up @@ -99,69 +92,8 @@ export interface ReleaseImageModel extends ReleaseImageAttributesBase {

// Helpers

export function getOrCreate<T, U extends object, V extends Filter>(
api: PinejsClientCore<unknown>,
resource: string,
body: U,
filter: V,
): Promise<T> {
return create(api, resource, body).catch((error) => {
if (error instanceof errors.UniqueConstraintError) {
return find<T>(api, resource, { $filter: filter }).then((obj) => {
if (obj.length > 0) {
return obj[0];
}
throw new errors.ObjectDoesNotExistError();
});
}
throw error;
}) as Promise<T>;
}

export function create<T, U extends object>(
api: PinejsClientCore<unknown>,
resource: string,
body: U,
): Promise<T> {
return api.post({ resource, body }).catch(wrapResponseError) as Promise<T>;
}

export function update<T extends object>(
api: PinejsClientCore<unknown>,
resource: string,
id: number,
body: T,
): Promise<void> {
return api.patch({ resource, id, body }).catch(wrapResponseError);
}

export function find<T>(
api: PinejsClientCore<unknown>,
resource: string,
options: ODataOptions,
): Promise<T[]> {
return api.get({ resource, options }).catch(wrapResponseError) as Promise<
T[]
>;
}

export function get<T>(
api: PinejsClientCore<unknown>,
resource: string,
id: number,
expand?: Expand,
): Promise<T> {
return api
.get({
resource,
id,
options: expand ? { $expand: expand } : undefined,
})
.catch(wrapResponseError) as Promise<T>;
}

function wrapResponseError<E extends Error>(e: E): void {
const error: { statusCode?: number; message?: unknown } = e as any;
export function wrapResponseError(e: Error): void {
const error: { statusCode?: number; message?: unknown } = e;
if (!error.statusCode) {
throw e;
}
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
"proxyquire": "^2.1.3",
"rimraf": "^5.0.1",
"ts-mocha": "^10.0.0",
"typescript": "^5.2.2"
"typescript": "^5.5.3"
},
"dependencies": {
"ajv": "^6.12.3",
Expand All @@ -83,8 +83,8 @@
"memoizee": "^0.4.15",
"mz": "^2.7.0",
"p-map": "^4.0.0",
"pinejs-client-core": "^6.13.0",
"pinejs-client-request": "^7.3.5",
"pinejs-client-core": "^6.15.10",
"pinejs-client-request": "^7.5.2",
"request": "^2.88.2",
"semver": "^7.3.5",
"stream-to-promise": "^3.0.0",
Expand Down

0 comments on commit 6ad2ec9

Please sign in to comment.