Giter Club home page Giter Club logo

ali-rds's Introduction

ali-rds

NPM version Node.js CI Test coverage npm download

Aliyun RDS client. RDS, Relational Database Service. Equal to well know Amazon RDS.

Support MySQL protocol only.

Usage

Create RDS instance

import { RDSClient } from 'ali-rds';

const db = new RDSClient({
  host: 'your-rds-address.mysql.rds.aliyuncs.com',
  port: 3306,
  user: 'your-username',
  password: 'your-password',
  database: 'your-database-name',
  // optional params
  // The charset for the connection.
  // This is called "collation" in the SQL-level of MySQL (like utf8_general_ci).
  // If a SQL-level charset is specified (like utf8mb4)
  // then the default collation for that charset is used. (Default: 'UTF8_GENERAL_CI')
  // charset: 'utf8_general_ci',
  //
  // The maximum number of connections to create at once. (Default: 10)
  // connectionLimit: 10,
  //
  // The maximum number of connection requests the pool will queue
  // before returning an error from getConnection.
  // If set to 0, there is no limit to the number of queued connection requests. (Default: 0)
  // queueLimit: 0,
  // Set asyncLocalStorage manually for transaction
  // connectionStorage: new AsyncLocalStorage(),
  // If create multiple RDSClient instances with the same connectionStorage, use this key to distinguish between the instances
  // connectionStorageKey: 'datasource',
  
  // The timeout for connecting to the MySQL server. (Default: 500 milliseconds)
  // connectTimeout: 500,

  // The timeout for waiting for a connection from the connection pool. (Default: 500 milliseconds)
  // So max timeout for get a connection is (connectTimeout + poolWaitTimeout)
  // poolWaitTimeout: 500,
});

Insert

  • Insert one row
const row = {
  name: 'fengmk2',
  otherField: 'other field value',
  createdAt: db.literals.now, // `now()` on db server
  // ...
};
const result = await db.insert('table-name', row);
console.log(result);
{ fieldCount: 0,
  affectedRows: 1,
  insertId: 3710,
  serverStatus: 2,
  warningCount: 2,
  message: '',
  protocol41: true,
  changedRows: 0 }
  • Insert multi rows

Will execute under a transaction and auto commit.

const rows = [
  {
    name: 'fengmk1',
    otherField: 'other field value',
    createdAt: db.literals.now, // `now()` on db server
    // ...
  },
  {
    name: 'fengmk2',
    otherField: 'other field value',
    createdAt: db.literals.now, // `now()` on db server
    // ...
  },
  // ...
];

const results = await db.insert('table-name', rows);
console.log(result);
{ fieldCount: 0,
  affectedRows: 2,
  insertId: 3840,
  serverStatus: 2,
  warningCount: 2,
  message: '&Records: 2  Duplicates: 0  Warnings: 0',
  protocol41: true,
  changedRows: 0 }

Update

  • Update a row with primary key: id
const row = {
  id: 123,
  name: 'fengmk2',
  otherField: 'other field value',
  modifiedAt: db.literals.now, // `now()` on db server
};
const result = await db.update('table-name', row);
console.log(result);
{ fieldCount: 0,
  affectedRows: 1,
  insertId: 0,
  serverStatus: 2,
  warningCount: 0,
  message: '(Rows matched: 1  Changed: 1  Warnings: 0',
  protocol41: true,
  changedRows: 1 }
  • Update a row with options.where and options.columns
const row = {
  name: 'fengmk2',
  otherField: 'other field value',
  modifiedAt: db.literals.now, // `now()` on db server
};
const result = await db.update('table-name', row, {
  where: { name: row.name },
  columns: [ 'otherField', 'modifiedAt' ]
});
console.log(result);
{ fieldCount: 0,
  affectedRows: 1,
  insertId: 0,
  serverStatus: 2,
  warningCount: 0,
  message: '(Rows matched: 1  Changed: 1  Warnings: 0',
  protocol41: true,
  changedRows: 1 }

Update multiple rows

  • Update multiple rows with primary key: id
const options = [{
  id: 123,
  name: 'fengmk2',
  email: '[email protected]',
  otherField: 'other field value',
  modifiedAt: db.literals.now, // `now()` on db server
}, {
   id: 124,
  name: 'fengmk2_2',
  email: 'm@fengmk2_2.com',
  otherField: 'other field value 2',
  modifiedAt: db.literals.now, // `now()` on db server
}]
const result = await db.updateRows('table-name', options);
console.log(result);
{ fieldCount: 0,
  affectedRows: 2,
  insertId: 0,
  serverStatus: 2,
  warningCount: 0,
  message: '(Rows matched: 2  Changed: 2  Warnings: 0',
  protocol41: true,
  changedRows: 2 }
  • Update multiple rows with row and where properties
const options = [{
  row: {
    email: '[email protected]',
    otherField: 'other field value',
    modifiedAt: db.literals.now, // `now()` on db server
  },
  where: {
    id: 123,
    name: 'fengmk2',
  }
}, {
  row: {
    email: 'm@fengmk2_2.com',
    otherField: 'other field value2',
    modifiedAt: db.literals.now, // `now()` on db server
  },
  where: {
    id: 124,
    name: 'fengmk2_2',
  }
}]
const result = await db.updateRows('table-name', options);
console.log(result);
{ fieldCount: 0,
  affectedRows: 2,
  insertId: 0,
  serverStatus: 2,
  warningCount: 0,
  message: '(Rows matched: 2  Changed: 2  Warnings: 0',
  protocol41: true,
  changedRows: 2 }

Get

  • Get a row
const row = await db.get('table-name', { name: 'fengmk2' });

=> SELECT * FROM `table-name` WHERE `name` = 'fengmk2'

Select

  • Select all rows
const rows = await db.select('table-name');

=> SELECT * FROM `table-name`
  • Select rows with condition
const rows = await db.select('table-name', {
  where: {
    type: 'javascript'
  },
  columns: ['author', 'title'],
  orders: [['id', 'desc']]
});

=> SELECT `author`, `title` FROM `table-name`
 WHERE `type` = 'javascript' ORDER BY `id` DESC

Delete

  • Delete with condition
const result = await db.delete('table-name', {
  name: 'fengmk2'
});

=> DELETE FROM `table-name` WHERE `name` = 'fengmk2'

Count

  • Get count from a table with condition
const count = await db.count('table-name', {
  type: 'javascript'
});

=> SELECT COUNT(*) AS count FROM `table-name` WHERE `type` = 'javascript';

Transactions

beginTransaction, commit or rollback

const tran = await db.beginTransaction();

try {
  await tran.insert(table, row1);
  await tran.update(table, row2);
  await tran.commit();
} catch (err) {
  // error, rollback
  await tran.rollback(); // rollback call won't throw err
  throw err;
}

Transaction with scope

API: async beginTransactionScope(scope)

All query run in scope will under a same transaction. We will auto commit or rollback for you.

const result = await db.beginTransactionScope(async conn => {
  // don't commit or rollback by yourself
  await conn.insert(table, row1);
  await conn.update(table, row2);
  return { success: true };
});
// if error throw on scope, will auto rollback

In Promise.all case, Parallel beginTransactionScope will create isolated transactions.

const result = await Promise.all([
  db.beginTransactionScope(async conn => {
    // commit and success
  }),
  db.beginTransactionScope(async conn => {
    // throw err and rollback
  }),
])

Raw Queries

  • Query without arguments
const rows = await db.query('SELECT * FROM your_table LIMIT 100');
console.log(rows);
  • Query with array arguments
const rows = await db.query('SELECT * FROM your_table WHERE id=?', [ 123 ]);
console.log(rows);
  • Query with object arguments
const rows = await db.query('SELECT * FROM your_table WHERE id=:id', { id: 123 });
console.log(rows);

Custom query lifecircle

db.beforeQuery((sql: string) => {
  // change sql string
  return `/* add custom format here */ ${sql}`;
});

db.afterQuery((sql: string, result: any, execDuration: number, err?: Error) => {
  // handle logger here
});

APIs

  • * Meaning this function is yieldable.

IO queries

  • async query(sql[, values)
  • async queryOne(sql[, values)
  • async select(table, options)
  • async get(table, where, options)
  • async insert(table, row[s], options)
  • async update(table, row, options)
  • async updateRows(table, options)
  • async delete(table, where)
  • async count(table, where)

Transactions Helpers

  • async beginTransaction()
  • async beginTransactionScope(scope)

Utils

  • escape(value, stringifyObjects, timeZone)
  • escapeId(value, forbidQualified)
  • format(sql, values, stringifyObjects, timeZone)

Literals

await db.insert('user', {
  name: 'fengmk2',
  createdAt: db.literals.now,
});

=>

INSERT INTO `user` SET `name` = 'fengmk2', `createdAt` = now()

Custom Literal

const session = new db.literals.Literal('session()');
const row = await db.get('table-name', { deletedAt: new db.literals.Literal('IS NOT NULL') });

=> SELECT * FROM `table-name` WHERE `deletedAt` IS NOT NULL

Class Relation

+-----------+                          +----------------+
| RDSClient +-- beginTransaction() --> + RDSTransaction |
+--+----+---+                          +----+----+------+
   |    | getConnection()            .conn  |    |
   |    |         +---------------+         |    |
   |    +-------->+ RDSConnection +<--------+    |
   |              +-------+-------+              |
   |                      | extends              |
   |                      v                      |
   |   extends    +-------+-------+    extends   |
   +------------->+   Operator    +<-------------+
                  |    query()    |
                  +---------------+

License

MIT

Contributors

Contributors

Made with contributors-img.

ali-rds's People

Contributors

antimoron avatar csbun avatar dead-horse avatar deadhorse123 avatar fangk avatar fengmk2 avatar gxkl avatar hoythan avatar killagu avatar nodejh avatar popomore avatar qile222 avatar rockdai avatar semantic-release-bot avatar xujihui1985 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ali-rds's Issues

mysql配置项说明不完全

rds是基于mysql库开发的,但在readme中没有体现相关配置。这样对于由前端进入nodejs开发的同学来说,可能就会忽略了这些东西。建议添加完善配置说明,或者追加mysql库的说明文档链接。

mysql 时间格式查询错误

数据库格式:2018-03-12 14:46:31
通过egg-mysql查询出来的格式:2018-03-12T06:46:31.000Z
自动加上了时区而且还是错误的时区。
数据库字段类型为timestamp

支持AS语法(别名)吗?

使用 AS 指定列名,比如:

let rows = yield db.select('table-name', {
  columns: ['author AS owner'],
});

以上用法会报错:unknown column 'author AS owner'
正确的用法是什么?能否支持?

node中使用mysql连接池poll,在select/query之后未释放连接?

在node环境中,该库mysql poll每次使用完select/query/update之类的操作,是否都需要释放连接?
例如:
db.select('table').then(function(res){
//优先release连接????
}).catch(function(err){
//优先release链接????
})
如果没有释放连接,是否连接资源一直被占用呢?还是有特殊的处理方式

doc fix: 'Can\'t not auto detect...'

just fix a doc miss: 'Can't not ...'

src: lib/operator.js: Line 152

throw new Error('Can\'t not auto detect update condition, please set options.where, or make sure obj.id exists');

连接sql server 有问题

  • 代码
    连接信息都是对的
  async sql() {

    const db = rds({
        host: '',
        port:,
        user: '',
        password: '',
        database: ""
      });
      
      let res = await db.query('SELECT * FROM HrmResource from id = 3');

    return res;
  }
  • 错误信息
Handshake inactivity timeout
    at Handshake.<anonymous> (/Users/hilter/work/npm/shellPortal/node_modules/mysql/lib/protocol/Protocol.js:164:17)
    at emitNone (events.js:106:13)
    at Handshake.emit (events.js:208:7)
    at Handshake._onTimeout (/Users/hilter/work/npm/shellPortal/node_modules/mysql/lib/protocol/sequences/Sequence.js:129:8)
    at ontimeout (timers.js:482:11)
    at tryOnTimeout (timers.js:317:5)
    at Timer.listOnTimeout (timers.js:277:5)
    --------------------
    at Protocol._enqueue (/Users/hilter/work/npm/shellPortal/node_modules/mysql/lib/protocol/Protocol.js:145:48)
    at Protocol.handshake (/Users/hilter/work/npm/shellPortal/node_modules/mysql/lib/protocol/Protocol.js:52:23)
    at PoolConnection.connect (/Users/hilter/work/npm/shellPortal/node_modules/mysql/lib/Connection.js:130:18)
    at Pool.getConnection (/Users/hilter/work/npm/shellPortal/node_modules/mysql/lib/Pool.js:48:16)
    at /Users/hilter/work/npm/shellPortal/node_modules/ali-rds/node_modules/pify/index.js:29:7
    at new Promise (<anonymous>)
    at Pool.<anonymous> (/Users/hilter/work/npm/shellPortal/node_modules/ali-rds/node_modules/pify/index.js:12:10)
    at Pool.ret [as getConnection] (/Users/hilter/work/npm/shellPortal/node_modules/ali-rds/node_modules/pify/index.js:56:34)
    at Pool.query (/Users/hilter/work/npm/shellPortal/node_modules/mysql/lib/Pool.js:202:8)
    at /Users/hilter/work/npm/shellPortal/node_modules/ali-rds/node_modules/pify/index.js:29:7
    at new Promise (<anonymous>)
    at Pool.<anonymous> (/Users/hilter/work/npm/shellPortal/node_modules/ali-rds/node_modules/pify/index.js:12:10)
    at Pool.ret [as query] (/Users/hilter/work/npm/shellPortal/node_modules/ali-rds/node_modules/pify/index.js:56:34)
    at RDSClient.proto._query (/Users/hilter/work/npm/shellPortal/node_modules/ali-rds/lib/client.js:34:20)

Egg.js 还能用吗 ,基础库中还有这种神仙代码

在 /lib/operator.js 文件中的 269 行,数组直接与字符相加,并且 255 行的 SQL 就没必要声明成数组,运行是能运行,但这么神仙的代码,我对 Egg.js 很担忧啊

let SQL = [ 'UPDATE ?? SET ' ];
  let VALUES = [ table ];

  const TEMPLATE = [];
  for (const key in SQL_CASE) {
    let templateSql = ' ?? = CASE ';
    VALUES.push(key);
    templateSql += SQL_CASE[key].when.join(' ');
    VALUES = VALUES.concat(SQL_CASE[key].then);
    templateSql += ' ELSE ?? END ';
    TEMPLATE.push(templateSql);
    VALUES.push(key);
  }

  SQL += TEMPLATE.join(' , ');

supportBigNumbers时候where参数的支持问题

当supportBigNumbers开启后,查询出来的bigint会转换成字符串,业务层拿到的也是字符串。

当使用这些bigint字段做其他操作时候可能出现问题,比如 WHERE IN,CASE WHEN THEN的时候无法正常匹配到数据

select('table', {
  where: {
    id: ['882066002862186496', '882066002996400128']
  }
})

实际的调用应该是

select('table', {
  where: {
    id: [882066002862186496, 882066002996400128]
  }
})

where 空数组问题

如果 where 是一个空的数组会报错,msyql 语法有问题。感觉这种情况是不是可以直接退出,不查询了。一个空的 where 就返回一个空就行了。

if (Array.isArray(value)) {

sqlMessage: 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near \')\' at line 1'
sqlState: '42000'
index: 0
sql: 'SELECT * FROM `table` WHERE `tableId` IN ()'

如何查看生成的sql语句

let list = await this.ctx.app.mysql.select('article',{
      where:{title:`%${title}%`},
      limit:count,
      offset:(p-1)*count
    });

如何查看生成的sql语句,用的是egg

where 是否可以支持比较?

源码如下:

proto._where = function(where) {
  if (!where) {
    return '';
  }

  const wheres = [];
  const values = [];
  for (const key in where) {
    const value = where[key];
    if (Array.isArray(value)) {
      wheres.push('?? IN (?)');
    } else {
      wheres.push('?? = ?');
    }
    values.push(key);
    values.push(value);
  }
  if (wheres.length > 0) {
    return this.format(' WHERE ' + wheres.join(' AND '), values);
  }
  return '';

};

看起来仅支持 IN=,但是 != 和其他常用比较运算符也很有用啊,为啥不能顺便支持呢?

还是说,官方推荐,其他比较运算符,自己写 SQL 呢?

count接口问题,报语法错误!!!

ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ' fund_id = 2' at line 1 (code: ER_PARSE_ERROR)


let queryResult = await this.app.mysql.count('fund_lp_relation', {
            where: {
                status: 1,
                fund_id: 2
            }
 });


let queryResult = await this.app.mysql.query(`SELECT COUNT(*) FROM fund_lp_relation WHERE status = 1 and fund_id = 2`)

上面2种写法都没毛病吧,但是用count接口就报如上错误

db.query对应的原生sql如何打印

let rows = yield db.query('SELECT * FROM your_table WHERE id=:id', { id: 123 });
console.log(rows);

如何查看这个sql查询的原生sql,如果sql很复杂,需要获取原生sql查看问题

update 有 bug

proto.update = function* (table, row, options) {
  // TODO: support multi rows
  options = options || {};
  if (!options.columns) {
    options.columns = Object.keys(row);
  }
  if (!options.where) {
    if (!('id' in row)) {
      throw new Error('Can not auto detect update condition, please set options.where, or make sure obj.id exists');
    }
    options.where = {
      id: row.id,
    };
  }

  const sets = [];
  const values = [];
  for (let i = 0; i < options.columns.length; i++) {
    const column = options.columns[i];
    if (column in options.where) {
      continue;
    }
    sets.push('?? = ?');
    values.push(column);
    values.push(row[column]);
  }
  const sql = this.format('UPDATE ?? SET ', [ table ]) +
    this.format(sets.join(', '), values) +
    this._where(options.where);
  debug('update(%j, %j, %j) \n=> %j', table, row, options, sql);
  return yield this.query(sql);
};

用例

update(
  'table',
  {
    status: 1,
  },
  {
    status: 0
  }
)

把所有未读的 status 改成已读,这里执行下来,sets 是个 []

这里为啥跳过了

ali-rds/lib/operator.js

Lines 163 to 166 in 004713c

if (column in options.where) {
continue;
}
sets.push('?? = ?');

比如

update({ is_read: 1, gmt_modified: 'now()' }, {
  where: { is_read: 0, user_id: 'xxx' },
});

这种情况 转换的 sql 会是

update xxx set gmt_modified = now() where is_read = 0 and user_id = 'xxx'

预期应该是

update xxx set gmt_modified = now(), is_read = 1 where is_read = 0 and user_id = 'xxx'

support object param

query('select * from table where name = ? and id = ?', [name, id]) =>

query('select * from table where name = :name and id = :id', {name, id})

get 方法不能匹配 null 字段

使用 this.app.mysql.get方法时,如果有字段 a 是 null,生成的 sql 代码是:

"SELECT * FROM page WHERE a = NULL"
这会导致匹配不到正确的数据,需要生成:

"SELECT * FROM page WHERE a is NULL"

support group by

请问能加上这个的扩展嘛 谢谢 虽然自己拼也可以解决(因为用了egg.js 然后发现egg-mysql插件又是用的ali-rds。。。)

当 where 和 row 中有相同值时, update 会报错

// 这种情况的意思是 查询 userid 等于 12  并且 key 等于 'world' 的然后改成 hello
mysql.update('table',{ key: 'hello' }, { where: { userid:12, key:'world'  } })
     Error: ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE `userid` = 1 AND `key` = 'wo' at line 1
      at Query.Sequence._packetToError (test/fixtures/apps/api-utils-test/node_modules/mysql/lib/protocol/sequences/Sequence.js:47:14)
      at Query.ErrorPacket (test/fixtures/apps/api-utils-test/node_modules/mysql/lib/protocol/sequences/Query.js:77:18)
      at Protocol._parsePacket (test/fixtures/apps/api-utils-test/node_modules/mysql/lib/protocol/Protocol.js:278:3)
      at Parser.write (test/fixtures/apps/api-utils-test/node_modules/mysql/lib/protocol/Parser.js:76:12)
      at Protocol.write (test/fixtures/apps/api-utils-test/node_modules/mysql/lib/protocol/Protocol.js:38:16)
      at Socket.<anonymous> (test/fixtures/apps/api-utils-test/node_modules/mysql/lib/Connection.js:91:28)
      at Socket.<anonymous> (test/fixtures/apps/api-utils-test/node_modules/mysql/lib/Connection.js:502:10)
      at addChunk (_stream_readable.js:263:12)
      at readableAddChunk (_stream_readable.js:250:11)
      at Socket.Readable.push (_stream_readable.js:208:10)
      at TCP.onread (net.js:597:20)

但这种情况在 mysql 是支持的

原因

发现是因为ali-rds 中判断了如果条件和 set 值相同,将会被过滤,导致 set 为空

怎么进行多库联查?

假如我有 A, B两个数据库
A库有个admin_account表用于存管理员数据
B库有个comment_info表用于存评论数据
B库得comment_info表中有一个字段adminId对应着A库admin_account的id
现在我查询B库comment_info中的评论数据的时候,想联合查询出A表中id=adminId的数据。

select 不能支持sql函数 如sum


select fund_id, sum(amount) as totalAmount from fund_token_order group by fund_id

这是合法的sql 但是在这个库里面无法操作
导致应用无法快速计算相同字段的数据和

事务中间出错并不会自动回滚

'use strict'
const rds = require('ali-rds');

const db = rds({
    host: '',
    user: '',
    password: '',
    pool: true,
    port: 3306,
    database: "test"
});

require('co')(function *() {
    //例子1
    var result = yield db.beginTransactionScope(function*(conn) {
        yield conn.update('user', {
            email: '7'
        }, {
            where: {id: 54},
        });
        yield conn.insert('123', {a: 1});
        return {success: true};
    });

    //例子2
    let tran = yield db.beginTransaction();
    try {
        yield tran.update('user', {
            email: '2'
        }, {
            where: {id: 54},
        });
        throw new Error('123');
        yield tran.commit();
    } catch (err) {
        yield tran.rollback(); // rollback call won't throw err
        throw err;
    }
})

在上面2段代码中,如果事务中间执行出错期间并不会回滚, 自己也在打算写类似这样的库, 但是一直困扰mysql事务回滚的问题

pg中这么写是没有问题的

不知道你有研究过么,有什么好的解决方案, 麻烦你了

select columns 错误

const [{ balance, out_sum }] = await app.mysql .get('admin') .select('user_bamboo', { columns: ['balance, out_sum'], where: { user_uid: uid }, limit: 1, }); console.log(balance, out_sum);

sql: "SELECT balance, out_sumFROMuser_bambooWHEREuser_uid = 'vic' LIMIT 0, 1"

Error: ER_BAD_FIELD_ERROR: Unknown column 'balance, out_sum' in 'field list'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.