| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- 'use strict'
- const TYPES = require('./datatypes').TYPES
- const declareType = require('./datatypes').declare
- const objectHasProperty = require('./utils').objectHasProperty
- const MAX = 65535 // (1 << 16) - 1
- const JSON_COLUMN_ID = 'JSON_F52E2B61-18A1-11d1-B105-00805F49916B'
- function Table (name) {
- if (name) {
- const parsed = Table.parseName(name)
- this.name = parsed.name
- this.schema = parsed.schema
- this.database = parsed.database
- this.path = (this.database ? `[${this.database}].` : '') + (this.schema ? `[${this.schema}].` : '') + `[${this.name}]`
- this.temporary = this.name.charAt(0) === '#'
- }
- this.columns = []
- this.rows = []
- Object.defineProperty(this.columns, 'add', {
- value (name, column, options) {
- if (column == null) {
- throw new Error('Column data type is not defined.')
- }
- if (column instanceof Function) {
- column = column()
- }
- options = options || {}
- column.name = name
- column.nullable = options.nullable
- column.primary = options.primary
- if (objectHasProperty(options, 'length')) {
- column.length = options.length
- }
- return this.push(column)
- }
- }
- )
- Object.defineProperty(this.rows, 'add', {
- value () {
- return this.push(Array.prototype.slice.call(arguments))
- }
- }
- )
- }
- /*
- @private
- */
- Table.prototype._makeBulk = function _makeBulk () {
- for (let i = 0; i < this.columns.length; i++) {
- const col = this.columns[i]
- switch (col.type) {
- case TYPES.DateTime:
- case TYPES.DateTime2:
- for (let j = 0; j < this.rows.length; j++) {
- const dateValue = this.rows[j][i]
- if (typeof dateValue === 'string' || typeof dateValue === 'number') {
- const date = new Date(dateValue)
- if (isNaN(date.getDate())) {
- throw new TypeError('Invalid date value passed to bulk rows')
- }
- this.rows[j][i] = date
- }
- }
- break
- case TYPES.Xml:
- col.type = TYPES.NVarChar(MAX).type
- break
- case TYPES.UDT:
- case TYPES.Geography:
- case TYPES.Geometry:
- col.type = TYPES.VarBinary(MAX).type
- break
- default:
- break
- }
- }
- return this
- }
- Table.prototype.declare = function declare () {
- const pkey = this.columns.filter(col => col.primary === true).map(col => col.name)
- const cols = this.columns.map(col => {
- const def = [`[${col.name}] ${declareType(col.type, col)}`]
- if (col.nullable === true) {
- def.push('null')
- } else if (col.nullable === false) {
- def.push('not null')
- }
- if (col.primary === true && pkey.length === 1) {
- def.push('primary key')
- }
- return def.join(' ')
- })
- const constraint = pkey.length > 1 ? `, constraint PK_${this.temporary ? this.name.substr(1) : this.name} primary key (${pkey.join(', ')})` : ''
- return `create table ${this.path} (${cols.join(', ')}${constraint})`
- }
- Table.fromRecordset = function fromRecordset (recordset, name) {
- const t = new this(name)
- for (const colName in recordset.columns) {
- if (objectHasProperty(recordset.columns, colName)) {
- const col = recordset.columns[colName]
- t.columns.add(colName, {
- type: col.type,
- length: col.length,
- scale: col.scale,
- precision: col.precision
- }, {
- nullable: col.nullable
- })
- }
- }
- if (t.columns.length === 1 && t.columns[0].name === JSON_COLUMN_ID) {
- for (let i = 0; i < recordset.length; i++) {
- t.rows.add(JSON.stringify(recordset[i]))
- }
- } else {
- for (let i = 0; i < recordset.length; i++) {
- t.rows.add.apply(t.rows, t.columns.map(col => recordset[i][col.name]))
- }
- }
- return t
- }
- Table.parseName = function parseName (name) {
- const length = name.length
- let cursor = -1
- let buffer = ''
- let escaped = false
- const path = []
- while (++cursor < length) {
- const char = name.charAt(cursor)
- if (char === '[') {
- if (escaped) {
- buffer += char
- } else {
- escaped = true
- }
- } else if (char === ']') {
- if (escaped) {
- escaped = false
- } else {
- throw new Error('Invalid table name.')
- }
- } else if (char === '.') {
- if (escaped) {
- buffer += char
- } else {
- path.push(buffer)
- buffer = ''
- }
- } else {
- buffer += char
- }
- }
- if (buffer) {
- path.push(buffer)
- }
- switch (path.length) {
- case 1:
- return {
- name: path[0],
- schema: null,
- database: null
- }
- case 2:
- return {
- name: path[1],
- schema: path[0],
- database: null
- }
- case 3:
- return {
- name: path[2],
- schema: path[1],
- database: path[0]
- }
- default:
- throw new Error('Invalid table name.')
- }
- }
- module.exports = Table
|