wangzhibo
2026-05-09 53418655c061ac26f66058253f39200aced1ab1d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/usr/bin/env node
const { Command } = require('commander')
const { version } = require('../package.json')
const { resolve: resolvePath } = require('node:path')
const { constants: { R_OK } } = require('node:fs')
const { ConnectionPool } = require('../')
const { lstat, access, readFile } = require('node:fs/promises')
Buffer.prototype.toJSON = () => {
  return `0x${this.toString('hex')}`
}
 
/**
 * @param {Readable} stream
 * @returns {Promise<Buffer>}
 */
async function streamToBuffer (stream) {
  const chunks = []
  return new Promise((resolve, reject) => {
    stream.on('data', (chunk) => {
      chunks.push(chunk)
    })
    stream.on('end', () => {
      resolve(Buffer.concat(chunks))
    })
    stream.on('error', reject)
  })
}
 
async function resolveConfig (opts, cfgFile) {
  const cfg = Object.entries({
    options: {
      encrypt: opts.encrypt,
      trustServerCertificate: opts.trustServerCertificate,
      tdsVersion: opts.tdsVersion
    },
    user: opts.user,
    password: opts.password,
    server: opts.server,
    database: opts.database,
    port: opts.port
  }).reduce((config, [key, value]) => {
    if (value) {
      Object.assign(config, {
        [key]: value
      })
    }
    return config
  }, {})
  let cfgPath = cfgFile || process.cwd()
  const stat = await lstat(resolvePath(cfgPath))
  if (stat.isDirectory()) {
    cfgPath = resolvePath(cfgPath, opts.config)
  }
  const configAccess = await access(cfgPath, R_OK).then(() => true).catch(() => false)
  if (!configAccess) {
    return cfg;
  }
  const config = await (readFile(cfgPath))
    .then((content) => JSON.parse(content.toString()))
 
  return {
    ...config,
    ...cfg,
    options: {
      ...(config.options || {}),
      ...cfg.options
    }
  }
}
 
const program = new Command()
 
program
  .name('mssql')
  .argument('[configPath]')
  .description('CLI tools for node-mssql')
  .version(version)
  .option('--config <file>', 'Configuration file for the connection', './.mssql.json')
  .option('--user <user>', 'User for the database connection')
  .option('--password <password>', 'Password for the database connection')
  .option('--server <server>', 'Server for the database connection')
  .option('--database <database>', 'Database for the database connection')
  .option('--tds-version <version>', 'TDS version to use for the database connection')
  .option('--port <port>', 'Port for the database connection', parseInt)
  .option('--encrypt', 'Use the encrypt option for this connection', false)
  .option('--trust-server-certificate', 'Trust the server certificate for this connection', false)
  // .option('--format <format>', 'The output format to use, eg: JSON', 'json')
  .action(async function (configPath, opts) {
    const [config, statement] = await Promise.all([
      resolveConfig(opts, configPath),
      streamToBuffer(process.stdin).then((stmt) => stmt.toString().trim())
    ])
    if (!statement.length) {
      throw new Error('Statement is empty.')
    }
    const pool = await (new ConnectionPool(config)).connect()
    const request = pool.request()
    request.stream = true
    let started = false
    request.on('error', (e) => {
      pool.close()
      throw e
    })
    request.on('recordset', () => {
      if (started) {
        process.stdout.write('],')
      } else {
        process.stdout.write('[')
      }
      started = false
    })
    request.on('row', (row) => {
      if (!started) {
        started = true
        process.stdout.write('[')
      } else {
        process.stdout.write(',')
      }
      process.stdout.write(JSON.stringify(row))
    })
    request.on('done', () => {
      if (started) {
        process.stdout.write(']]')
      }
      process.stdout.write('\n')
      pool.close()
    })
    request.query(statement)
  })
 
program.parseAsync(process.argv).catch((e) => {
  program.error(e.message, { exitCode: 1 });
})