Skip to content

Commit

Permalink
feat: entity files
Browse files Browse the repository at this point in the history
  • Loading branch information
joscha committed Jul 29, 2024
1 parent b01509b commit ebd27bb
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 14 deletions.
26 changes: 25 additions & 1 deletion src/v1/entity_files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down Expand Up @@ -37,7 +38,7 @@ type EntityFile = Replace<EntityFileRaw, {
/**
* Represents the request parameters for retrieving entity files.
*/
type AllEntityFileRequest =
export type AllEntityFileRequest =
& {
/**
* A unique ID that represents a Person whose associated files should be retrieved.
Expand Down Expand Up @@ -110,6 +111,29 @@ export class EntityFiles {
return response.data
}

/**
* Returns an async iterator that yields all entity files matching the given request
* Each yielded array contains up to the number specified in {@link AllEntityFileRequest.page_size} of entity files.
* Use this method if you want to process the entity files in a streaming fashion.
*
* *Please note:* the yielded entity files array may be empty on the last page.
*
* @example
* ```typescript
* let page = 0
* for await (const entries of affinity.entityFiles.pagedIterator({
* person_id: 123,
* page_size: 10
* })) {
* console.log(`Page ${++page} of entries:`, entries)
* }
* ```
*/
pagedIterator = createSearchIteratorFn(
this.all.bind(this),
'entity_files',
)

/**
* Fetches an entity with a specified `entity_file_id`.
*/
Expand Down
51 changes: 48 additions & 3 deletions src/v1/tests/__snapshots__/entity_files_test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const snapshot = {};

snapshot[`persons > can list all files 1`] = `
snapshot[`entityFiles > can list all files 1`] = `
{
entity_files: [
{
Expand Down Expand Up @@ -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",
Expand All @@ -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 {
Expand All @@ -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`] = `[]`;
91 changes: 81 additions & 10 deletions src/v1/tests/entity_files_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, string>) => {
Expand All @@ -31,7 +33,7 @@ const createSnapshotBodyMatcher = (t: Deno.TestContext) => ({
},
})

describe('persons', () => {
describe('entityFiles', () => {
let mock: MockAdapter
let affinity: Affinity

Expand All @@ -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)
})

Expand Down Expand Up @@ -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)
},
})
}
10 changes: 10 additions & 0 deletions src/v1/tests/fixtures/entity_files/get.raw.response.json
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -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": []
}
]

0 comments on commit ebd27bb

Please sign in to comment.