From ebd27bbc6200825700b5156e78c59e5bf5bec4e5 Mon Sep 17 00:00:00 2001 From: Joscha Feth Date: Mon, 29 Jul 2024 21:14:22 +0100 Subject: [PATCH] feat: entity files --- src/v1/entity_files.ts | 26 +++++- .../__snapshots__/entity_files_test.ts.snap | 51 ++++++++++- src/v1/tests/entity_files_test.ts | 91 +++++++++++++++++-- .../entity_files/get.raw.response.json | 10 ++ .../paginated.iterator.combined.response.json | 36 ++++++++ 5 files changed, 200 insertions(+), 14 deletions(-) create mode 100644 src/v1/tests/fixtures/entity_files/get.raw.response.json create mode 100644 src/v1/tests/fixtures/entity_files/paginated.iterator.combined.response.json diff --git a/src/v1/entity_files.ts b/src/v1/entity_files.ts index f1541ad..4ed615a 100644 --- a/src/v1/entity_files.ts +++ b/src/v1/entity_files.ts @@ -10,6 +10,7 @@ export type { DateTime } from './types.ts' import { Readable } from 'node:stream' import { EntityRequestFilter } from './field_value_changes.ts' import { assert } from '@std/assert' +import { createSearchIteratorFn } from './create_search_iterator_fn.ts' type EntityFileRaw = { /** The unique identifier of the entity file object. */ @@ -37,7 +38,7 @@ type EntityFile = Replace can list all files 1`] = ` +snapshot[`entityFiles > can list all files 1`] = ` { entity_files: [ { @@ -28,7 +28,20 @@ snapshot[`persons > can list all files 1`] = ` } `; -snapshot[`persons > can upload a file 1`] = ` +snapshot[`entityFiles > can get a single file 1`] = ` +{ + created_at: 2019-01-13T20:52:51.539Z, + id: 131, + name: "Import.csv", + opportunity_id: null, + organization_id: null, + person_id: 38654, + size: 227224, + uploader_id: 101, +} +`; + +snapshot[`entityFiles > can upload a file 1`] = ` { file: File { name: "test.pdf", @@ -39,7 +52,7 @@ snapshot[`persons > can upload a file 1`] = ` } `; -snapshot[`persons > can upload multiple files 1`] = ` +snapshot[`entityFiles > can upload multiple files 1`] = ` { "files[]": [ File { @@ -56,3 +69,35 @@ snapshot[`persons > can upload multiple files 1`] = ` person_id: "170614434", } `; + +snapshot[`page 1 of entity files 1`] = ` +[ + { + created_at: 2011-01-25T17:59:35.288Z, + id: 43212, + name: "JohnDoeFriends.csv", + opportunity_id: null, + organization_id: null, + person_id: 142, + size: 993, + uploader_id: 10, + }, +] +`; + +snapshot[`page 2 of entity files 1`] = ` +[ + { + created_at: 2019-01-13T20:52:51.539Z, + id: 131, + name: "Import.csv", + opportunity_id: null, + organization_id: null, + person_id: 142, + size: 227224, + uploader_id: 101, + }, +] +`; + +snapshot[`page 3 of entity files 1`] = `[]`; diff --git a/src/v1/tests/entity_files_test.ts b/src/v1/tests/entity_files_test.ts index 5989c26..3a1ff25 100644 --- a/src/v1/tests/entity_files_test.ts +++ b/src/v1/tests/entity_files_test.ts @@ -3,12 +3,14 @@ import { afterEach, beforeEach, describe, it } from '@std/testing/bdd' import { assertSnapshot } from '@std/testing/snapshot' import axios from 'axios' import MockAdapter from 'axios-mock-adapter' +import { Buffer } from 'jsr:@std/io/buffer' +import { Readable } from 'node:stream' +import { buffer } from 'node:stream/consumers' +import { AllEntityFileRequest } from '../entity_files.ts' import { Affinity } from '../index.ts' import { entityFilesUrl } from '../urls.ts' import { apiKey, isLiveRun } from './env.ts' import { getRawFixture, readFixtureFile } from './get_raw_fixture.ts' -import { buffer } from 'node:stream/consumers' -import { Buffer } from 'jsr:@std/io/buffer' const multipartFormDataHeaderMatcher = { asymmetricMatch: (headers: Record) => { @@ -31,7 +33,7 @@ const createSnapshotBodyMatcher = (t: Deno.TestContext) => ({ }, }) -describe('persons', () => { +describe('entityFiles', () => { let mock: MockAdapter let affinity: Affinity @@ -50,7 +52,18 @@ describe('persons', () => { 200, await getRawFixture('entity_files/all.raw.response.json'), ) - const res = await affinity.entityFiles.all() + const res = await affinity.entityFiles.all({ + person_id: 170614434, + }) + await assertSnapshot(t, res) + }) + + it('can get a single file', async (t) => { + mock?.onGet(entityFilesUrl(131)).reply( + 200, + await getRawFixture('entity_files/get.raw.response.json'), + ) + const res = await affinity.entityFiles.get(131) await assertSnapshot(t, res) }) @@ -106,16 +119,74 @@ describe('persons', () => { assert(res) }) - it.only('can download a file', async (t) => { - // mock?.onGet(entityFilesUrl(6534776, true)).reply( - // 200, - // await readFixtureFile('./entity_files/test.pdf'), - // ) + it('can download a file', async (t) => { + const pdfContents = await readFixtureFile('./entity_files/test.pdf') + + mock?.onGet(entityFilesUrl(6534776, true)).reply( + 200, + readableFromArray(pdfContents), + ) + const stream = await affinity.entityFiles.download(6534776) const buf: ArrayBuffer = await buffer(stream) - const pdfContents = await readFixtureFile('./entity_files/test.pdf') + const expected = new Buffer() expected.read(pdfContents) assertEquals(new Buffer(buf), expected) }) + + it('iterates over all entity files', async (t) => { + const params: AllEntityFileRequest = { + person_id: 142, + page_size: 1, + } + + { + // set up pages sequentially, each referencing the one after + const { default: pages } = await import( + './fixtures/entity_files/paginated.iterator.combined.response.json', + { + with: { + type: 'json', + }, + } + ) + + pages.forEach((page, i) => { + const { next_page_token: previous_page_token } = pages[i - 1] || + {} + const data: AllEntityFileRequest = { + ...params, + } + if (previous_page_token) { + data.page_token = previous_page_token + } + // console.log('Setting up page', params, page.list_entries) + mock?.onGet(entityFilesUrl(), { + params: data, + }).reply( + 200, + page, + ) + }) + } + + let page = 0 + for await ( + const entries of affinity.entityFiles.pagedIterator(params) + ) { + await assertSnapshot(t, entries, { + name: `page ${++page} of entity files`, + }) + } + }) }) + +function readableFromArray(arr: Uint8Array) { + return new Readable({ + read(size: number) { + this.push(arr) + this.push(null) + }, + }) +} diff --git a/src/v1/tests/fixtures/entity_files/get.raw.response.json b/src/v1/tests/fixtures/entity_files/get.raw.response.json new file mode 100644 index 0000000..2f86d76 --- /dev/null +++ b/src/v1/tests/fixtures/entity_files/get.raw.response.json @@ -0,0 +1,10 @@ +{ + "id": 131, + "name": "Import.csv", + "size": 227224, + "person_id": 38654, + "organization_id": null, + "opportunity_id": null, + "created_at": "2019-01-13T12:52:51.539-08:00", + "uploader_id": 101 +} diff --git a/src/v1/tests/fixtures/entity_files/paginated.iterator.combined.response.json b/src/v1/tests/fixtures/entity_files/paginated.iterator.combined.response.json new file mode 100644 index 0000000..18aecd7 --- /dev/null +++ b/src/v1/tests/fixtures/entity_files/paginated.iterator.combined.response.json @@ -0,0 +1,36 @@ +[ + { + "next_page_token": "B", + "entity_files": [ + { + "id": 43212, + "name": "JohnDoeFriends.csv", + "size": 993, + "person_id": 142, + "organization_id": null, + "opportunity_id": null, + "created_at": "2011-01-25T09:59:35.288-08:00", + "uploader_id": 10 + } + ] + }, + { + "next_page_token": "C", + "entity_files": [ + { + "id": 131, + "name": "Import.csv", + "size": 227224, + "person_id": 142, + "organization_id": null, + "opportunity_id": null, + "created_at": "2019-01-13T12:52:51.539-08:00", + "uploader_id": 101 + } + ] + }, + { + "next_page_token": null, + "entity_files": [] + } +]