Skip to content

Commit 2f098a5

Browse files
authored
Get Data from File (#780)
1 parent d8e0421 commit 2f098a5

File tree

3 files changed

+124
-30
lines changed

3 files changed

+124
-30
lines changed

integration/test/ParseFileTest.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,47 @@ describe('Parse.File', () => {
3838
result = await query.get(object.id);
3939
assert.equal(file2.url(), result.get('file2').url());
4040
});
41+
42+
it('can not get data from unsaved file', async () => {
43+
const file = new Parse.File('parse-server-logo', [61, 170, 236, 120]);
44+
file._data = null;
45+
try {
46+
await file.getData();
47+
} catch (e) {
48+
assert.equal(e.message, 'Cannot retrieve data for unsaved ParseFile.');
49+
}
50+
});
51+
52+
it('can get file data from byte array', async () => {
53+
const file = new Parse.File('parse-server-logo', [61, 170, 236, 120]);
54+
let data = await file.getData();
55+
assert.equal(data, 'ParseA==');
56+
file._data = null;
57+
await file.save();
58+
assert.equal(file._data, null)
59+
data = await file.getData();
60+
assert.equal(data, 'ParseA==');
61+
});
62+
63+
it('can get file data from base64', async () => {
64+
const file = new Parse.File('parse-server-logo', { base64: 'ParseA==' });
65+
let data = await file.getData();
66+
assert.equal(data, 'ParseA==');
67+
file._data = null;
68+
await file.save();
69+
assert.equal(file._data, null)
70+
data = await file.getData();
71+
assert.equal(data, 'ParseA==');
72+
});
73+
74+
it('can get file data from full base64', async () => {
75+
const file = new Parse.File('parse-server-logo', { base64: 'data:image/jpeg;base64,ParseA==' });
76+
let data = await file.getData();
77+
assert.equal(data, 'ParseA==');
78+
file._data = null;
79+
await file.save();
80+
assert.equal(file._data, null)
81+
data = await file.getData();
82+
assert.equal(data, 'ParseA==');
83+
});
4184
});

src/ParseFile.js

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ class ParseFile {
6565
_url: ?string;
6666
_source: FileSource;
6767
_previousSave: ?Promise;
68+
_data: string;
6869

6970
/**
7071
* @param name {String} The file's name. This will be prefixed by a unique
@@ -101,9 +102,10 @@ class ParseFile {
101102

102103
if (data !== undefined) {
103104
if (Array.isArray(data)) {
105+
this._data = ParseFile.encodeBase64(data);
104106
this._source = {
105107
format: 'base64',
106-
base64: ParseFile.encodeBase64(data),
108+
base64: this._data,
107109
type: specifiedType
108110
};
109111
} else if (typeof File !== 'undefined' && data instanceof File) {
@@ -125,12 +127,14 @@ class ParseFile {
125127
if (commaIndex !== -1) {
126128
const matches = dataUriRegexp.exec(base64.slice(0, commaIndex + 1));
127129
// if data URI with type and charset, there will be 4 matches.
130+
this._data = base64.slice(commaIndex + 1);
128131
this._source = {
129132
format: 'base64',
130-
base64: base64.slice(commaIndex + 1),
133+
base64: this._data,
131134
type: matches[1]
132135
};
133136
} else {
137+
this._data = base64;
134138
this._source = {
135139
format: 'base64',
136140
base64: base64,
@@ -143,6 +147,25 @@ class ParseFile {
143147
}
144148
}
145149

150+
/**
151+
* Return the data for the file, downloading it if not already present.
152+
* Data is present if initialized with Byte Array, Base64 or Saved with Uri.
153+
* Data is cleared if saved with File object selected with a file upload control
154+
*
155+
* @return {Promise} Promise that is resolve with base64 data
156+
*/
157+
async getData(): Promise<String> {
158+
if (this._data) {
159+
return this._data;
160+
}
161+
if (!this._url) {
162+
throw new Error('Cannot retrieve data for unsaved ParseFile.');
163+
}
164+
const controller = CoreManager.getFileController();
165+
const result = await controller.download(this._url);
166+
this._data = result.base64;
167+
return this._data;
168+
}
146169
/**
147170
* Gets the name of the file. Before save is called, this is the filename
148171
* given by the user. After save is called, that name gets prefixed with a
@@ -189,10 +212,19 @@ class ParseFile {
189212
this._previousSave = controller.saveFile(this._name, this._source, options).then((res) => {
190213
this._name = res.name;
191214
this._url = res.url;
215+
this._data = null;
192216
return this;
193217
});
194218
} else if (this._source.format === 'uri') {
195-
this._previousSave = controller.saveUri(this._name, this._source, options).then((res) => {
219+
this._previousSave = controller.download(this._source.uri).then((result) => {
220+
const newSource = {
221+
format: 'base64',
222+
base64: result.base64,
223+
type: result.contentType,
224+
};
225+
this._data = result.base64;
226+
return controller.saveBase64(this._name, newSource, options);
227+
}).then((res) => {
196228
this._name = res.name;
197229
this._url = res.url;
198230
return this;
@@ -299,20 +331,6 @@ const DefaultController = {
299331
return CoreManager.getRESTController().request('POST', path, data, options);
300332
},
301333

302-
saveUri: function(name: string, source: FileSource, options?: FullOptions) {
303-
if (source.format !== 'uri') {
304-
throw new Error('saveUri can only be used with Uri-type sources.');
305-
}
306-
return this.download(source.uri).then((result) => {
307-
const newSource = {
308-
format: 'base64',
309-
base64: result.base64,
310-
type: result.contentType,
311-
};
312-
return this.saveBase64(name, newSource, options);
313-
});
314-
},
315-
316334
download: function(uri) {
317335
if (XHR) {
318336
return this.downloadAjax(uri);

src/__tests__/ParseFile-test.js

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ describe('ParseFile', () => {
3737
CoreManager.setFileController({
3838
saveFile: generateSaveMock('http://files.parsetfss.com/a/'),
3939
saveBase64: generateSaveMock('http://files.parsetfss.com/a/'),
40-
saveUri: generateSaveMock('http://files.parsetfss.com/a/'),
40+
download: () => Promise.resolve({
41+
base64: 'ParseA==',
42+
contentType: 'image/png',
43+
}),
4144
});
4245
});
4346

@@ -274,17 +277,9 @@ describe('FileController', () => {
274277
});
275278
});
276279

277-
it('saveUri without uri type', () => {
278-
try {
279-
defaultController.saveUri('name', { format: 'unknown' });
280-
} catch (error) {
281-
expect(error.message).toBe('saveUri can only be used with Uri-type sources.');
282-
}
283-
});
284-
285280
it('saveUri with uri type', async () => {
286-
const source = { format: 'uri', uri: 'https://example.com/image.png' };
287-
jest.spyOn(
281+
const file = new ParseFile('parse.png', { uri: 'https://example.com/image.png' });
282+
const spy = jest.spyOn(
288283
defaultController,
289284
'download'
290285
)
@@ -296,14 +291,15 @@ describe('FileController', () => {
296291
});
297292

298293
jest.spyOn(defaultController, 'saveBase64');
299-
await defaultController.saveUri('fileName', source, {});
294+
await file.save();
300295
expect(defaultController.download).toHaveBeenCalledTimes(1);
301296
expect(defaultController.saveBase64).toHaveBeenCalledTimes(1);
302297
expect(defaultController.saveBase64.mock.calls[0]).toEqual([
303-
'fileName',
298+
'parse.png',
304299
{ format: 'base64', base64: 'ParseA==', type: 'image/png' },
305300
{}
306301
]);
302+
spy.mockRestore();
307303
});
308304

309305
it('download with base64 http', async () => {
@@ -408,4 +404,41 @@ describe('FileController', () => {
408404
expect(e).toBe('Cannot make a request: No definition of XMLHttpRequest was found.');
409405
}
410406
});
407+
408+
it('getData', async () => {
409+
const file = new ParseFile('parse.png', [61, 170, 236, 120]);
410+
const data = await file.getData();
411+
expect(data).toBe('ParseA==');
412+
});
413+
414+
it('getData unsaved file', async () => {
415+
const file = new ParseFile('parse.png');
416+
try {
417+
await file.getData();
418+
} catch (e) {
419+
expect(e.message).toBe('Cannot retrieve data for unsaved ParseFile.');
420+
}
421+
});
422+
423+
it('getData via download', async () => {
424+
const file = new ParseFile('parse.txt', { base64: 'ParseA==' });
425+
file._data = null;
426+
const result = await file.save();
427+
428+
const spy = jest.spyOn(
429+
defaultController,
430+
'download'
431+
)
432+
.mockImplementationOnce(() => {
433+
return Promise.resolve({
434+
base64: 'ParseA==',
435+
contentType: 'image/png',
436+
});
437+
});
438+
439+
const data = await result.getData();
440+
expect(defaultController.download).toHaveBeenCalledTimes(1);
441+
expect(data).toBe('ParseA==');
442+
spy.mockRestore();
443+
});
411444
});

0 commit comments

Comments
 (0)