Skip to content
This repository was archived by the owner on Dec 20, 2023. It is now read-only.

Commit b221cde

Browse files
committed
Merge pull request #144 from C2FO/bigint_changes
Adding defaultPrimaryKeyType and parseInt8 options
2 parents 4732fd5 + 8c4afbc commit b221cde

File tree

8 files changed

+213
-9
lines changed

8 files changed

+213
-9
lines changed

lib/adapters/postgres.js

+20-2
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ var pg = require("pg"),
4444
stream = require("stream"),
4545
PassThroughStream = stream.PassThrough,
4646
pipeAll = require("../utils").pipeAll,
47-
hashPick = comb.hash.pick;
47+
hashPick = comb.hash.pick,
48+
isSafeInteger = Number.isSafeInteger || require('is-safe-integer');
4849

4950
var getPatio = function () {
5051
return patio || (patio = require("../index.js"));
@@ -77,6 +78,19 @@ var byteaParser = function (val) {
7778
};
7879

7980
PgTypes.setTypeParser(17, "text", byteaParser);
81+
82+
PgTypes.setTypeParser(20, 'text', function (val) {
83+
if (!getPatio().parseInt8) {
84+
return val;
85+
}
86+
87+
var i = parseInt(val, 10);
88+
if (!isSafeInteger(i)) {
89+
throw new Error(format("The value '%s' cannot be represented by a javascript number.", val));
90+
}
91+
return i;
92+
});
93+
8094
var timestampOrig = PgTypes.getTypeParser(1114, "text");
8195
//PgTypes.setTypeParser(25, "text", byteaParser);
8296
PgTypes.setTypeParser(1114, "text", function (val) {
@@ -1031,7 +1045,11 @@ var DB = define(Database, {
10311045
},
10321046

10331047
serialPrimaryKeyOptions: function () {
1034-
return {primaryKey: true, serial: true, type: "integer"};
1048+
return {
1049+
primaryKey: true,
1050+
serial: true,
1051+
type: this.defaultPrimaryKeyType
1052+
};
10351053
},
10361054

10371055
supportsSavepoints: function () {

lib/database/defaults.js

+48-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ define(null, {
1818
this.__identifierInputMethod = isUndefined(opts.identifierInputMethod) ? isUndefined(statics.identifierInputMethod) ? this.identifierInputMethodDefault : statics.identifierInputMethod : opts.identifierInputMethod;
1919
this.__identifierOutputMethod = isUndefined(opts.identifierOutputMethod) ? isUndefined(statics.identifierOutputMethod) ? this.identifierOutputMethodDefault : statics.identifierOutputMethod : opts.identifierOutputMethod;
2020
this.__quoteIdentifiers = isUndefined(opts.quoteIdentifiers) ? isUndefinedOrNull(statics.quoteIdentifiers) ? this.quoteIdentifiersDefault : statics.quoteIdentifiers : opts.quoteIdentifiers;
21+
this.__defaultPrimaryKeyType = isUndefined(opts.defaultPrimaryKeyType) ? (isUndefinedOrNull(statics.defaultPrimaryKeyType) ? this.defaultPrimaryKeyTypeDefault : statics.defaultPrimaryKeyType) : opts.defaultPrimaryKeyType;
2122
},
2223

2324
getters:{
@@ -41,6 +42,17 @@ define(null, {
4142
return null;
4243
},
4344

45+
/**
46+
* Default type for primary/foreign keys when a type is not specified.
47+
*
48+
* @field
49+
* @type String
50+
* @default "integer"
51+
*/
52+
defaultPrimaryKeyTypeDefault:function () {
53+
return "integer";
54+
},
55+
4456
/**
4557
* The default String or comb method to use transform identifiers with when
4658
* sending identifiers to the database.
@@ -74,6 +86,17 @@ define(null, {
7486
return true;
7587
},
7688

89+
/**
90+
* Default type for primary/foreign keys when a type is not specified.
91+
*
92+
* @field
93+
* @type String
94+
* @default "integer"
95+
*/
96+
defaultPrimaryKeyType:function () {
97+
return this.__defaultPrimaryKeyType;
98+
},
99+
77100
/**
78101
* Default serial primary key options, used by the table creation
79102
* code.
@@ -82,7 +105,11 @@ define(null, {
82105
* @default {primaryKey : true, type : "integer", autoIncrement : true}
83106
* */
84107
serialPrimaryKeyOptions:function () {
85-
return {primaryKey:true, type:"integer", autoIncrement:true};
108+
return {
109+
primaryKey:true,
110+
type: this.defaultPrimaryKeyType,
111+
autoIncrement:true
112+
};
86113
},
87114

88115
/**
@@ -178,6 +205,10 @@ define(null, {
178205

179206
supportsSavepoints:function (supports) {
180207
this.__supportsSavePoints = supports;
208+
},
209+
210+
defaultPrimaryKeyType:function (type) {
211+
this.__defaultPrimaryKeyType = type;
181212
}
182213
}
183214
},
@@ -190,6 +221,8 @@ define(null, {
190221

191222
__quoteIdentifiers:null,
192223

224+
__defaultPrimaryKeyType:undefined,
225+
193226
getters:{
194227
/**@lends patio.Database*/
195228

@@ -224,6 +257,16 @@ define(null, {
224257
*/
225258
quoteIdentifiers:function () {
226259
return this.__quoteIdentifiers;
260+
},
261+
262+
/**
263+
* The default type for primary keys if no type is specified.
264+
* @ignore
265+
* @type String
266+
* Returns the default primary key type for schema migrations.
267+
*/
268+
defaultPrimaryKeyType:function () {
269+
return this.__defaultPrimaryKeyType;
227270
}
228271
},
229272

@@ -238,6 +281,10 @@ define(null, {
238281

239282
quoteIdentifiers:function (quoteIdentifiers) {
240283
this.__quoteIdentifiers = quoteIdentifiers;
284+
},
285+
286+
defaultPrimaryKeyType:function (type) {
287+
this.__defaultPrimaryKeyType = type;
241288
}
242289
}
243290
}

lib/database/schemaGenerators.js

+1-4
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ var AlterTableGenerator = define(null, {
470470
if (isArray(name)) {
471471
return this.__addCompositeForeignKey(name, table, opts);
472472
} else {
473-
return this.addColumn(name, "integer", merge({table:table}, opts));
473+
return this.addColumn(name, this.db.defaultPrimaryKeyType, merge({table:table}, opts));
474474
}
475475
},
476476

@@ -658,6 +658,3 @@ var AlterTableGenerator = define(null, {
658658
}
659659
}
660660
}).as(exports, "AlterTableGenerator");
661-
662-
663-

lib/index.js

+52-1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ var Patio = singleton([EventEmitter, Time], {
5757

5858
__inImportOfModels: false,
5959

60+
__parseInt8: false,
61+
6062

6163
/**
6264
* A singleton class that acts as the entry point for all actions performed in patio.
@@ -69,6 +71,8 @@ var Patio = singleton([EventEmitter, Time], {
6971
*
7072
* patio.camelize = true;
7173
* patio.quoteIdentifiers=false;
74+
* patio.parseInt8=false
75+
* patio.defaultPrimaryKeyType = "integer" //"bigint"
7276
*
7377
* patio.createModel("my_table");
7478
*
@@ -624,6 +628,17 @@ var Patio = singleton([EventEmitter, Time], {
624628
return LOGGER;
625629
},
626630

631+
632+
/**
633+
* The default type for primary keys if no type is specified.
634+
* @ignore
635+
* @type String
636+
* Returns the default primary key type for schema migrations.
637+
*/
638+
defaultPrimaryKeyType: function () {
639+
return Database.defaultPrimaryKeyType;
640+
},
641+
627642
/**
628643
* Returns the default method used to transform identifiers sent to the database.
629644
* See (@link patio.Database.identifierInputMethod}
@@ -665,6 +680,11 @@ var Patio = singleton([EventEmitter, Time], {
665680
/**@ignore*/
666681
underscore: function () {
667682
return this.__underscore;
683+
},
684+
685+
/**@ignore*/
686+
parseInt8: function () {
687+
return this.__parseInt8;
668688
}
669689

670690
},
@@ -834,6 +854,37 @@ var Patio = singleton([EventEmitter, Time], {
834854
this.identifierInputMethod = underscore ? "camelize" : "underscore";
835855
this.__camelize = !underscore;
836856
this.__underscore = underscore;
857+
},
858+
859+
/**
860+
* Sets whether bigint types should be parsed to a number. An error will be thrown if set and the number is
861+
* set and the number is greater than 2^53 or less than -2^53.
862+
*
863+
* @ignoreCode
864+
* @field
865+
* @type Boolean
866+
*
867+
* @example
868+
* patio.parseInt8 = true
869+
* */
870+
parseInt8: function (value) {
871+
this.__parseInt8 = value;
872+
},
873+
874+
/**
875+
* Set the default primary key type when not specified for all databases by default. By default,
876+
* patio uses "integer".
877+
*
878+
* @ignoreCode
879+
* @field
880+
* @type String
881+
*
882+
* @example
883+
* //changing to bigint
884+
* patio.defaultPrimaryKeyType = "bigint"
885+
* */
886+
defaultPrimaryKeyType: function (value) {
887+
Database.defaultPrimaryKeyType = value;
837888
}
838889
}
839890
}
@@ -845,4 +896,4 @@ patio.__Patio = Patio;
845896
var adapters = Database.ADAPTERS;
846897
for (var i in adapters) {
847898
patio[i] = adapters[i];
848-
}
899+
}

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"comb-proxy": "~1.0.0",
3434
"commander": "~2.9.0",
3535
"hive-cache": "0.0.3",
36+
"is-safe-integer": "1.0.1",
3637
"mysql": "2.10.0",
3738
"pg": "4.4.3",
3839
"pg-query-stream": "1.0.0",

test/adapters/postgres.test.js

+61-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ var it = require('it'),
55
patio = require("../../lib"),
66
sql = patio.SQL,
77
comb = require("comb"),
8-
config = require("../test.config.js");
8+
config = require("../test.config.js"),
9+
PgTypes = require('pg-types');
910

1011
if (process.env.PATIO_DB === "pg") {
1112
it.describe("patio.adapters.Postgres", function (it) {
@@ -545,6 +546,65 @@ if (process.env.PATIO_DB === "pg") {
545546
});
546547
});
547548

549+
it.describe("parseInt8", function (it) {
550+
551+
it.beforeEach(function () {
552+
return db.forceCreateTable("posts", function () {
553+
this.postId("bigint");
554+
});
555+
});
556+
557+
it.afterAll(function () {
558+
patio.parseInt8 = false;
559+
return db.dropTable("posts");
560+
});
561+
562+
it.should("parse bigints on select if true", function () {
563+
var ds = db.from("posts");
564+
patio.parseInt8 = true;
565+
return ds.insert({postId: "9007199254740991"})
566+
.chain(function () {
567+
return ds.one();
568+
}).chain(function (post) {
569+
assert.strictEqual(post.postId, 9007199254740991);
570+
});
571+
});
572+
573+
it.should("parse negative bigints as well", function () {
574+
var ds = db.from("posts");
575+
patio.parseInt8 = true;
576+
return ds.insert({postId: "-9007199254740991"})
577+
.chain(function () {
578+
return ds.one();
579+
}).chain(function (post) {
580+
assert.strictEqual(post.postId, -9007199254740991);
581+
});
582+
});
583+
584+
it.should("not parse bigints if false", function () {
585+
var ds = db.from("posts");
586+
patio.parseInt8 = false;
587+
return ds.insert({postId: "9007199254740992"})
588+
.chain(function () {
589+
return ds.one();
590+
}).chain(function (post) {
591+
assert.strictEqual(post.postId, "9007199254740992");
592+
});
593+
});
594+
595+
it.should("should throw if bigint is outside the range of max safe integer", function () {
596+
patio.parseInt8 = true;
597+
var bigIntParser = PgTypes.getTypeParser(20, 'text');
598+
assert.throws(function () {
599+
bigIntParser("9007199254740992");
600+
}, /The value \'9007199254740992\' cannot be represented by a javascript number\./);
601+
assert.throws(function () {
602+
bigIntParser("-9007199254740992");
603+
}, /The value \'\-9007199254740992\' cannot be represented by a javascript number\./);
604+
});
605+
606+
});
607+
548608
it.should("support opclass specification", function () {
549609
return db.createTable("posts", function () {
550610
this.title("text");

test/database/database.test.js

+24
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,30 @@ it.describe("Database", function (it) {
155155
assert.equal(db.identifierOutputMethodDefault, "toLowerCase");
156156
});
157157

158+
it.describe("defaultPrimaryKeyType", function (it) {
159+
160+
it.should("has a defaultPrimaryKeyType of integer", function () {
161+
var db = new Database();
162+
assert.equal(db.defaultPrimaryKeyType, "integer");
163+
assert.deepEqual(db.serialPrimaryKeyOptions, {
164+
primaryKey: true,
165+
type: "integer",
166+
autoIncrement:true
167+
});
168+
});
169+
170+
it.should("allow for overriding the option", function () {
171+
var db = new Database({defaultPrimaryKeyType: "bigint"});
172+
assert.equal(db.defaultPrimaryKeyType, "bigint");
173+
assert.deepEqual(db.serialPrimaryKeyOptions, {
174+
primaryKey: true,
175+
type: "bigint",
176+
autoIncrement:true
177+
});
178+
});
179+
180+
});
181+
158182
it.should("respect the identifierInputMethod option", function () {
159183
var db = new Database({identifierInputMethod: null});
160184
assert.isNull(db.identifierInputMethod);

test/patio.test.js

+6
Original file line numberDiff line numberDiff line change
@@ -383,8 +383,14 @@ it.describe("patio", function (it) {
383383
assert.equal(patio.identifierInputMethod, "underscore");
384384
});
385385

386+
it.should("set defaultPrimaryKeyType values when using defaultPrimaryKeyType", function () {
387+
patio.defaultPrimaryKeyType = "bigint";
388+
assert.equal(patio.defaultPrimaryKeyType, "bigint");
389+
assert.equal(Database.defaultPrimaryKeyType, "bigint");
390+
});
386391

387392
it.afterAll(function () {
393+
patio.defaultPrimaryKeyType = null;
388394
patio.resetIdentifierMethods();
389395
return patio.disconnect();
390396
});

0 commit comments

Comments
 (0)