Skip to content

Commit

Permalink
Merge 2202db4 into c7a809c
Browse files Browse the repository at this point in the history
  • Loading branch information
digitalBush committed Dec 10, 2019
2 parents c7a809c + 2202db4 commit 80121c3
Show file tree
Hide file tree
Showing 6 changed files with 298 additions and 30 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module.exports = {
extends: [ "leankit", "leankit/es6" ],
parserOptions: {
ecmaVersion: 2017,
ecmaVersion: 2018,
sourceType: 'module'
},
rules: {
Expand Down
170 changes: 170 additions & 0 deletions spec/behavior/types.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
const { expect } = testHelpers;
const types = require( "src/types" );

describe( "types", () => {
[
"bigint",
"bit",
"date",
"datetime",
"image",
"int",
"float",
"money",
"ntext",
"real",
"smalldatetime",
"smallint",
"smallmoney",
"text",
"tvp",
"udt",
"uniqueidentifier",
"variant",
"xml"
].forEach( name => {
it( `should create wrapper for ${ name } type`, () => {
const wrappedType = types[ name ]();
wrappedType.type.name.toLowerCase().should.equal( name );
} );

it( `should declare ${ name } type`, () => {
const wrappedType = types[ name ]();
wrappedType.declaration.should.equal( name );
} );
} );

describe( "with length", () => {
[
{ name: "binary", emptyValue: 8000 },
{ name: "char", emptyValue: 8000 },
{ name: "nchar", emptyValue: 4000 },
{ name: "nvarchar", emptyValue: 4000, max: true },
{ name: "varbinary", emptyValue: 8000, max: true },
{ name: "varchar", emptyValue: 8000, max: true }
].forEach( ( { name, emptyValue, max } ) => {
describe( name, () => {
it( "should create wrapper with proper type", () => {
const wrappedType = types[ name ]( 1 );
wrappedType.type.name.toLowerCase().should.equal( name );
} );

it( "should use provided length", () => {
const wrappedType = types[ name ]( 42 );
wrappedType.length.should.equal( 42 );
} );

it( "should declare type with length", () => {
const wrappedType = types[ name ]( 42 );
wrappedType.declaration.should.equal( `${ name }(42)` );
} );

it( "should use default length", () => {
const wrappedType = types[ name ]();
wrappedType.length.should.equal( emptyValue );
} );

it( "should declare type with default length", () => {
const wrappedType = types[ name ]();
wrappedType.declaration.should.equal( `${ name }(${ emptyValue })` );
} );

if ( max ) {
it( "should use max length", () => {
const wrappedType = types[ name ]( types.max );
expect( wrappedType.length ).to.be.null();
wrappedType.max.should.equal( true );
} );

it( "should declare type with max length", () => {
const wrappedType = types[ name ]( types.max );
wrappedType.declaration.should.equal( `${ name }(max)` );
} );

it( `should have ${ name }_max type`, () => {
const wrappedType = types[ `${ name }_max` ];
expect( wrappedType.length ).to.be.null();
wrappedType.max.should.equal( true );
} );

it( `should declare type ${ name }_max with max length`, () => {
const wrappedType = types[ `${ name }_max` ];
wrappedType.declaration.should.equal( `${ name }(max)` );
} );
}
} );
} );
} );

describe( "with scale", () => {
[
{ name: "datetime2", emptyValue: 7 },
{ name: "datetimeoffset", emptyValue: 7 },
{ name: "time", emptyValue: 7 }
].forEach( ( { name, emptyValue } ) => {
describe( name, () => {
it( "should create wrapper with proper type", () => {
const wrappedType = types[ name ]( 1 );
wrappedType.type.name.toLowerCase().should.equal( name );
} );

it( "should use provided scale", () => {
const wrappedType = types[ name ]( 5 );
wrappedType.scale.should.equal( 5 );
} );

it( "should declare type with scale", () => {
const wrappedType = types[ name ]( 42 );
wrappedType.declaration.should.equal( `${ name }(42)` );
} );

it( "should use default scale", () => {
const wrappedType = types[ name ]();
wrappedType.scale.should.equal( emptyValue );
} );

it( "should declare type with default scale", () => {
const wrappedType = types[ name ]( );
wrappedType.declaration.should.equal( `${ name }(${ emptyValue })` );
} );
} );
} );
} );

describe( "with precision and scale", () => {
[
{ name: "decimal", emptyPrecision: 18, emptyScale: 0 },
{ name: "numeric", emptyPrecision: 18, emptyScale: 0 }
].forEach( ( { name, emptyPrecision, emptyScale } ) => {
describe( name, () => {
it( "should create wrapper with proper type", () => {
const wrappedType = types[ name ]( 2, 1 );
wrappedType.type.name.toLowerCase().should.equal( name );
} );

it( "should use provided precision and scale", () => {
const wrappedType = types[ name ]( 5, 1 );
wrappedType.precision.should.equal( 5 );
wrappedType.scale.should.equal( 1 );
} );

it( "should declare type with precision and scale", () => {
const wrappedType = types[ name ]( 5, 1 );
wrappedType.declaration.should.equal( `${ name }(5,1)` );
} );

it( "should use defaults", () => {
const wrappedType = types[ name ]();
wrappedType.precision.should.equal( emptyPrecision );
wrappedType.scale.should.equal( emptyScale );
} );


it( "should declare type with default precision and scale", () => {
const wrappedType = types[ name ]();
wrappedType.declaration.should.equal( `${ name }(${ emptyPrecision },${ emptyScale })` );
} );
} );
} );
} );
} );
52 changes: 50 additions & 2 deletions spec/integration/types.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ describe( "Types - Integration", () => {
datetime2: { val: datetime2, type: sql.datetime2( 7 ) },
nvarchar3: { val: "!".repeat( 3 ), type: sql.nvarchar( 3 ) },
nvarchar: { val: "!".repeat( 4000 ), type: sql.nvarchar },
nvarcharmax: { val: "!".repeat( 4000 ), type: sql.nvarchar( sql.max ) }
nvarcharmax: { val: "!".repeat( 4001 ), type: sql.nvarchar( sql.max ) }
} ).should.eventually.deep.equal( {
bit: true,
int: 1,
Expand All @@ -49,7 +49,55 @@ describe( "Types - Integration", () => {
datetime2,
nvarchar3: "!!!",
nvarchar: "!".repeat( 4000 ),
nvarcharmax: "!".repeat( 4000 )
nvarcharmax: "!".repeat( 4001 )
} );
} );

it( "it should round trip table types", () => {
const datetime = new Date();
datetime.setMilliseconds( 0 ); // compensating for sql datetime precision differences

const datetime2 = new Date();

const query = `
SELECT top 1 * from @jsonStuff;
`;

return sql.queryFirst( query, {
jsonStuff: {
type: {
bit: sql.bit,
int: sql.int,
bigint: sql.bigint,
decimal32: sql.decimal( 3, 2 ),
datetime: sql.datetime,
datetime2: sql.datetime2( 7 ),
nvarchar3: sql.nvarchar( 3 ),
nvarchar: sql.nvarchar,
nvarcharmax: sql.nvarchar( sql.max )
},
val: [ {
bit: true,
int: 1,
bigint: "1",
decimal32: 1.234,
datetime,
datetime2,
nvarchar3: "!".repeat( 3 ),
nvarchar: "!".repeat( 4000 ),
nvarcharmax: "!".repeat( 4001 )
} ]
}
} ).should.eventually.deep.equal( {
bit: true,
int: 1,
bigint: "1",
decimal32: 1.23,
datetime,
datetime2,
nvarchar3: "!!!",
nvarchar: "!".repeat( 4000 ),
nvarcharmax: "!".repeat( 4001 )
} );
} );
} );
31 changes: 29 additions & 2 deletions src/TypeWrapper.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,44 @@
module.exports = class TypeWrapper {
const max = Symbol( "skwell:max" );

class TypeWrapper {

constructor( type, opts ) {
this.type = type;

if ( opts ) {
Object.keys( opts ).forEach( k => {
this[ k ] = opts[ k ];
} );
}
if ( this.length === max ) {
this.length = null;
this.max = true;
}
}

nullable( val = true ) {
this.isNull = val;
return this;
}

};
get declaration() {
const typeName = this.type.name.toLowerCase();
if ( this.hasOwnProperty( "length" ) ) {
const val = this.max ? "max" : this.length;
return `${ typeName }(${ val })`;
} else if ( this.hasOwnProperty( "precision" ) && this.hasOwnProperty( "scale" ) ) {
return `${ typeName }(${ this.precision },${ this.scale })`;
} else if ( this.hasOwnProperty( "scale" ) ) {
return `${ typeName }(${ this.scale })`;
}
return typeName;
}

static get max() {
return max;
}

}


module.exports = TypeWrapper;
3 changes: 1 addition & 2 deletions src/parameterBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ function typeDeclarations( definition ) {
if ( typeof column === "function" ) {
column = column();
}
const declaration = column.type.declaration( column );
return {
name,
declaration
declaration: column.declaration
};
} );
}
Expand Down
70 changes: 47 additions & 23 deletions src/types.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,53 @@
/* eslint-disable camelcase */
/* eslint-disable no-magic-numbers */
const { TYPES } = require( "tedious" );

const TypeWrapper = require( "./TypeWrapper" );
const { max } = TypeWrapper;

module.exports =
Object.keys( TYPES ).reduce( ( acc, name ) => {
if ( name.endsWith( "N" ) || name === "Null" ) {
// Stop deprecated type warnings from tedious.
return acc;
}
const type = TYPES[ name ];
const key = name.toLowerCase();
const types = {
binary: ( length = 8000 ) => new TypeWrapper( TYPES.Binary, { length } ),
bigint: () => new TypeWrapper( TYPES.BigInt ),
bit: () => new TypeWrapper( TYPES.Bit ),
char: ( length = 8000 ) => new TypeWrapper( TYPES.Char, { length } ),
date: () => new TypeWrapper( TYPES.Date ),
datetime: () => new TypeWrapper( TYPES.DateTime ),
datetime2: ( scale = 7 ) => new TypeWrapper( TYPES.DateTime2, { scale } ),
datetimeoffset: ( scale = 7 ) => new TypeWrapper( TYPES.DateTimeOffset, { scale } ),
decimal: ( precision = 18, scale = 0 ) => new TypeWrapper( TYPES.Decimal, { precision, scale } ),
image: () => new TypeWrapper( TYPES.Image ),
int: () => new TypeWrapper( TYPES.Int ),
float: () => new TypeWrapper( TYPES.Float ),
money: () => new TypeWrapper( TYPES.Money ),
nchar: ( length = 4000 ) => new TypeWrapper( TYPES.NChar, { length } ),
ntext: () => new TypeWrapper( TYPES.NText ),
nvarchar: ( length = 4000 ) => new TypeWrapper( TYPES.NVarChar, { length } ),
numeric: ( precision = 18, scale = 0 ) => new TypeWrapper( TYPES.Numeric, { precision, scale } ),
real: () => new TypeWrapper( TYPES.Real ),
smalldatetime: () => new TypeWrapper( TYPES.SmallDateTime ),
smallint: () => new TypeWrapper( TYPES.SmallInt ),
smallmoney: () => new TypeWrapper( TYPES.SmallMoney ),
text: () => new TypeWrapper( TYPES.Text ),
time: ( scale = 7 ) => new TypeWrapper( TYPES.Time, { scale } ),
tvp: () => new TypeWrapper( TYPES.TVP ),
udt: () => new TypeWrapper( TYPES.UDT ),
uniqueidentifier: () => new TypeWrapper( TYPES.UniqueIdentifier ),
varbinary: ( length = 8000 ) => new TypeWrapper( TYPES.VarBinary, { length } ),
varchar: ( length = 8000 ) => new TypeWrapper( TYPES.VarChar, { length } ),
variant: () => new TypeWrapper( TYPES.Variant ),
xml: () => new TypeWrapper( TYPES.Xml )
};

if ( type.maximumLength ) {
acc[ key ] = length => new TypeWrapper( type, { length } );
} else if ( type.hasPrecision && type.hasScale ) {
acc[ key ] = ( precision, scale ) => new TypeWrapper( type, { precision, scale } );
} else if ( type.hasScale ) {
acc[ key ] = scale => new TypeWrapper( type, { scale } );
} else {
acc[ key ] = () => new TypeWrapper( type );
}
Object.keys( types ).forEach( key => {
types[ key ].nullable = function( val ) {
return types[ key ]().nullable( val );
};
} );

acc[ key ].nullable = function( val ) {
return acc[ key ]().nullable( val );
};

return acc;
}, { max: null } );
module.exports = {
...types,
varbinary_max: types.varbinary( max ),
varchar_max: types.varchar( max ),
nvarchar_max: types.nvarchar( max ),
max
};

0 comments on commit 80121c3

Please sign in to comment.