Skip to content

Commit

Permalink
Add support for batch record creation
Browse files Browse the repository at this point in the history
For example:

    const table = airtable.base('app123').table('My Table');
    const records = await table.create([
        {foo: 'boo'},
        {bar: 'yar'},
    ]);

    console.log(records.length);         // => 2
    console.log(records[0].get('foo'));  // => 'boo'
    console.log(records[1].get('bar'));  // => 'yar'
  • Loading branch information
Evan Hahn committed Apr 25, 2019
1 parent 7eceb7a commit aead452
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 5 deletions.
29 changes: 24 additions & 5 deletions lib/table.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ var Table = Class.extend({
// Public API
this.find = callbackToPromise(this._findRecordById, this);
this.select = this._selectRecords.bind(this);
this.create = callbackToPromise(this._createRecord, this);
this.create = callbackToPromise(this._createRecords, this);
this.update = callbackToPromise(this._updateRecord, this);
this.destroy = callbackToPromise(this._destroyRecord, this);
this.replace = callbackToPromise(this._replaceRecord, this);
Expand Down Expand Up @@ -78,18 +78,37 @@ var Table = Class.extend({
_urlEncodedNameOrId: function(){
return this.id || encodeURIComponent(this.name);
},
_createRecord: function(recordData, optionalParameters, done) {
_createRecords: function(recordsData, optionalParameters, done) {
var that = this;
var isCreatingMultipleRecords = isArray(recordsData);

if (!done) {
done = optionalParameters;
optionalParameters = {};
}
var requestData = assign({fields: recordData}, optionalParameters);
var requestData;
if (isCreatingMultipleRecords) {
requestData = {
records: recordsData.map(function (fields) {
return {fields: fields};
}),
};
} else {
requestData = {fields: recordsData};
}
assign(requestData, optionalParameters);
this._base.runAction('post', '/' + that._urlEncodedNameOrId() + '/', {}, requestData, function(err, resp, body) {
if (err) { done(err); return; }

var record = new Record(that, body.id, body);
done(null, record);
var result;
if (isCreatingMultipleRecords) {
result = body.records.map(function (record) {
return new Record(that, record.id, record);
});
} else {
result = new Record(that, body.id, body);
}
done(null, result);
});
},
_updateRecord: function(recordId, recordData, opts, done) {
Expand Down
94 changes: 94 additions & 0 deletions test/create.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
'use strict';

var testHelpers = require('./test_helpers');

describe('record creation', function () {
var airtable;
var teardownAsync;

beforeAll(function () {
return testHelpers.getMockEnvironmentAsync().then(function (env) {
airtable = env.airtable;
teardownAsync = env.teardownAsync;
});
});

afterAll(function () {
return teardownAsync();
});

it('can create one record', function () {
return airtable
.base('app123')
.table('Table')
.create({
foo: 'boo',
bar: 'yar',
})
.then(function (createdRecord) {
expect(createdRecord.id).toBe('rec0');
expect(createdRecord.get('foo')).toBe('boo');
expect(createdRecord.get('bar')).toBe('yar');
});
});

it('can add the "typecast" parameter when creating one record', function () {
return airtable
.base('app123')
.table('Table')
.create({
foo: 'boo',
bar: 'yar',
}, {typecast: true})
.then(function (createdRecord) {
expect(createdRecord.id).toBe('rec0');
expect(createdRecord.get('typecasted')).toBe(true);
});
});

it('can create one record with an array', function () {
return airtable
.base('app123')
.table('Table')
.create([{foo: 'boo'}])
.then(function (createdRecords) {
expect(createdRecords).toHaveLength(1);
expect(createdRecords[0].id).toBe('rec0');
expect(createdRecords[0].get('foo')).toBe('boo');
});
});

it('can create two records', function () {
return airtable
.base('app123')
.table('Table')
.create([
{foo: 'boo'},
{bar: 'yar'},
])
.then(function (createdRecords) {
expect(createdRecords).toHaveLength(2);
expect(createdRecords[0].id).toBe('rec0');
expect(createdRecords[0].get('foo')).toBe('boo');
expect(createdRecords[1].id).toBe('rec1');
expect(createdRecords[1].get('bar')).toBe('yar');
});
});

it('can create two records with the "typecast" parameter', function () {
return airtable
.base('app123')
.table('Table')
.create([
{foo: 'boo'},
{bar: 'yar'},
], {typecast: true})
.then(function (createdRecords) {
expect(createdRecords).toHaveLength(2);
expect(createdRecords[0].id).toBe('rec0');
expect(createdRecords[0].get('typecasted')).toBe(true);
expect(createdRecords[1].id).toBe('rec1');
expect(createdRecords[1].get('typecasted')).toBe(true);
});
});
});
30 changes: 30 additions & 0 deletions test/test_helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,30 @@ var bodyParser = require('body-parser');
var getPort = require('get-port');
var util = require('util');

var FAKE_CREATED_TIME = '2020-04-20T16:20:00.000Z';

function getMockEnvironmentAsync() {
var app = express();

app.use(bodyParser.json());

app.post('/v0/:baseId/:tableIdOrName', _checkParamsMiddleware, function (req, res) {
var isCreatingJustOneRecord = !!req.body.fields;
var recordsInBody = isCreatingJustOneRecord ? [req.body] : req.body.records;

var records = recordsInBody.map(function (record, index) {
var fields = req.body.typecast ? {typecasted: true} : record.fields;
return {
id: 'rec' + index,
createdTime: FAKE_CREATED_TIME,
fields: fields,
};
});

var responseBody = isCreatingJustOneRecord ? records[0] : {records: records};
res.json(responseBody);
});

app.delete('/v0/:baseId/:tableIdOrName/:recordId', _checkParamsMiddleware, function (req, res, next) {
res.json({
id: req.params.recordId,
Expand All @@ -29,6 +48,17 @@ function getMockEnvironmentAsync() {
});
});

app.use(function (err, req, res, next) {
console.error(err);
res.status(500);
res.json({
error: {
type: 'TEST_ERROR',
message: err.message,
}
});
});

return getPort().then(function (testServerPort) {
return new Promise(function (resolve, reject) {
var testServer = app.listen(testServerPort, function (err) {
Expand Down

0 comments on commit aead452

Please sign in to comment.