Skip to content

Commit 1bde03f

Browse files
committed
feat(db): simple foreign key constraint in CREATE TABLE
Signed-off-by: Kremio Software <kremio.software@gmail.com>
1 parent bf2e7c4 commit 1bde03f

File tree

3 files changed

+113
-16
lines changed

3 files changed

+113
-16
lines changed

index.js

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,20 +56,21 @@ var Sqlite3Driver = Base.extend({
5656
callback(null);
5757
},
5858

59-
createColumnDef: function(name, spec, options) {
60-
name = '"' + name + '"';
59+
createColumnDef: function(name, spec, options, tableName) {
60+
var quotedName = '"' + name + '"';
6161
var dType = this.mapDataType(spec.type);
6262
var len = spec.length ? util.format('(%s)', spec.length) : '';
63-
var constraint = this.createColumnConstraint(spec, options);
63+
var constraint = this.createColumnConstraint(spec, options, tableName, name);
6464

6565
if(spec.type === type.INTEGER)
6666
len = '';
6767

6868
return { foreignKey: null,
69-
constraints: [name, dType, len, constraint].join(' ') };
69+
constraints: [quotedName, dType, len, constraint].join(' ') };
7070
},
7171

72-
createColumnConstraint: function(spec, options) {
72+
createColumnConstraint: function(spec, options, tableName, columnName) {
73+
var cb;
7374
var constraint = [];
7475
if (spec.primaryKey && options.emitPrimaryKey) {
7576
constraint.push('PRIMARY KEY');
@@ -95,6 +96,22 @@ var Sqlite3Driver = Base.extend({
9596
constraint.push(spec.defaultValue);
9697
}
9798

99+
if (spec.foreignKey) {
100+
constraint.push(`REFERENCES ${spec.foreignKey.table}(${spec.foreignKey.mapping})`)
101+
if( spec.foreignKey.rules ){
102+
Object.keys(spec.foreignKey.rules)
103+
.forEach( (rule) => {
104+
switch(rule){
105+
case 'onDelete': constraint.push(`ON DELETE ${spec.foreignKey.rules[rule]}`)
106+
break
107+
case 'onUpdate': constraint.push(`ON UPDATE ${spec.foreignKey.rules[rule]}`)
108+
break
109+
default: throw new Error('Unsupported foreign key action trigger: ' + rule )
110+
}
111+
})
112+
}
113+
}
114+
98115
return constraint.join(' ');
99116
},
100117

test/foreign_key_batch.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
const dbmeta = require('db-meta')
2+
const dataType = require('db-migrate-shared').dataType
3+
const fs = require('fs')
4+
const assert = require('assert')
5+
6+
module.exports = (driver, config, internals) => ({
7+
'columnForeignKeySpec': {
8+
topic: function () {
9+
driver.connect(config, internals, function (err, db) {
10+
db.createTable('event_type', {
11+
12+
id: { type: dataType.INTEGER, primaryKey: true, autoIncrement: true },
13+
title: { type: dataType.STRING }
14+
}, function(err) {
15+
if (err) {
16+
return this.callback(err);
17+
}
18+
db.createTable('event', {
19+
id: {
20+
type: dataType.INTEGER,
21+
primaryKey: true,
22+
autoIncrement: true
23+
},
24+
event_type_id: {
25+
type: dataType.INTEGER,
26+
notNull: true,
27+
foreignKey: {
28+
name: 'fk_event_event_type',
29+
table: 'event_type',
30+
mapping: 'id',
31+
rules: {
32+
onDelete: 'CASCADE'
33+
},
34+
} },
35+
title: {
36+
type: dataType.STRING
37+
}
38+
}, this.callback.bind(this, null, db));
39+
}.bind(this));
40+
}.bind(this))
41+
},
42+
43+
teardown: function(db) {
44+
db.close(function (err) {
45+
fs.unlink(config.filename, this.callback);
46+
}.bind(this));
47+
},
48+
49+
'sets usage and constraints': {
50+
topic: function (db) {
51+
dbmeta('sqlite3', {connection: db.connection}, function (err, meta) {
52+
if (err) {
53+
return this.callback(err);
54+
}
55+
meta.getTables( (err, tables) => {
56+
if (err) {
57+
return this.callback(err)
58+
}
59+
this.callback( undefined, tables.find( (table) => table.getName() == "event" ) )
60+
})
61+
}.bind(this));
62+
},
63+
'that has foreign key column with the expected reference': function (err, table) {
64+
const foreignKeyDefinition = table.meta
65+
.sql
66+
.match(/"event_type_id"[^,]+/)[0]
67+
.replace(/\s{2,}/g,' ')
68+
69+
assert.equal(
70+
foreignKeyDefinition,
71+
'"event_type_id" INTEGER NOT NULL REFERENCES event_type(id) ON DELETE CASCADE'
72+
)
73+
}
74+
75+
}
76+
}
77+
})

test/sqlite3_test.js

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ var driver = require('../');
88

99
var config = require('./db.config.json').sqlite3;
1010

11+
var foreignKeyBatch = require('./foreign_key_batch')
12+
1113
var internals = {};
1214
internals.mod = {
1315
log: log,
@@ -38,7 +40,7 @@ vows.describe('sqlite3').addBatch({
3840
teardown: function (db) {
3941
db.close(function (err) {
4042
fs.unlink(config.filename, this.callback);
41-
});
43+
}.bind(this));
4244
},
4345

4446
'has resulting table metadata': {
@@ -138,7 +140,7 @@ vows.describe('sqlite3').addBatch({
138140
teardown: function (db) {
139141
db.close(function (err) {
140142
fs.unlink(config.filename, this.callback);
141-
});
143+
}.bind(this));
142144
},
143145

144146
'has table metadata': {
@@ -172,7 +174,7 @@ vows.describe('sqlite3').addBatch({
172174
teardown: function (db) {
173175
db.close(function (err) {
174176
fs.unlink(config.filename, this.callback);
175-
});
177+
}.bind(this));
176178
},
177179

178180
'has table metadata': {
@@ -208,7 +210,7 @@ vows.describe('sqlite3').addBatch({
208210
teardown: function (db) {
209211
db.close(function (err) {
210212
fs.unlink(config.filename, this.callback);
211-
});
213+
}.bind(this));
212214
},
213215

214216
'has column metadata': {
@@ -249,7 +251,7 @@ vows.describe('sqlite3').addBatch({
249251
teardown: function (db) {
250252
db.close(function (err) {
251253
fs.unlink(config.filename, this.callback);
252-
});
254+
}.bind(this));
253255
},
254256

255257
'has resulting index metadata': {
@@ -287,7 +289,7 @@ vows.describe('sqlite3').addBatch({
287289
teardown: function (db) {
288290
db.close(function (err) {
289291
fs.unlink(config.filename, this.callback);
290-
});
292+
}.bind(this));
291293
},
292294

293295
'with additional row': function (db) {
@@ -312,7 +314,7 @@ vows.describe('sqlite3').addBatch({
312314
teardown: function (db) {
313315
db.close(function (err) {
314316
fs.unlink(config.filename, this.callback);
315-
});
317+
}.bind(this));
316318
},
317319

318320
'with additional row': function (db) {
@@ -339,7 +341,7 @@ vows.describe('sqlite3').addBatch({
339341
teardown: function (db) {
340342
db.close(function (err) {
341343
fs.unlink(config.filename, this.callback);
342-
});
344+
}.bind(this));
343345
},
344346

345347
'has resulting index metadata': {
@@ -376,7 +378,7 @@ vows.describe('sqlite3').addBatch({
376378
teardown: function (db) {
377379
db.close(function (err) {
378380
fs.unlink(config.filename, this.callback);
379-
});
381+
}.bind(this));
380382
},
381383

382384
'has resulting index metadata': {
@@ -406,7 +408,7 @@ vows.describe('sqlite3').addBatch({
406408
teardown: function (db) {
407409
db.close(function (err) {
408410
fs.unlink(config.filename, this.callback);
409-
});
411+
}.bind(this));
410412
},
411413

412414
'has migrations table': {
@@ -452,7 +454,8 @@ vows.describe('sqlite3').addBatch({
452454
}
453455
}
454456
}
455-
}).export(module);
457+
}).addBatch( foreignKeyBatch(driver, config, internals) )
458+
.export(module);
456459

457460
function findByName(columns, name) {
458461
for (var i = 0; i < columns.length; i++) {

0 commit comments

Comments
 (0)