Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update pinejs-client and make use of improved typings #54

Merged
merged 1 commit into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 90 additions & 34 deletions lib/release/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,15 +144,27 @@ 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 @@ -161,31 +173,62 @@ 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' },
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This $select was previously missing

} as const)
.catch(models.wrapResponseError);
if (user == null) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could always be null but in the past it would have error'ed with something like TypeError: cannot read 'id' of undefined downstream

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' },
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This $select was previously missing

} as const)
.catch(models.wrapResponseError);
if (app == null) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could always be null but in the past it would have error'ed with something like TypeError: cannot read 'id' of undefined downstream

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, {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I replaced this with the built in getOrCreate to keep things standardized with other repos using the client

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 @@ -195,29 +238,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 @@ -228,12 +279,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 @@ -34,7 +34,7 @@
},
"homepage": "https://github.com/balena-io-modules/balena-compose#readme",
"devDependencies": {
"@balena/lint": "^7.2.1",
"@balena/lint": "^7.3.0",
"@types/chai-as-promised": "^7.1.3",
"@types/docker-modem": "^3.0.6",
"@types/dockerode": "^3.3.23",
Expand All @@ -60,7 +60,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 @@ -82,7 +82,7 @@
"memoizee": "^0.4.15",
"mz": "^2.7.0",
"p-map": "^4.0.0",
"pinejs-client-core": "^6.13.0",
"pinejs-client-core": "^6.14.13",
"semver": "^7.3.5",
"stream-to-promise": "^3.0.0",
"tar-stream": "^3.1.6",
Expand Down