Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
Sakib Hasan authored Apr 24, 2017
1 parent 70f0aca commit 345492e
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 355 deletions.
53 changes: 13 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ Edit `datasources.json` to add any other additional properties that you require.
<td>Enable this option to deal with big numbers (BIGINT and DECIMAL columns) in the database. Default is false.</td>
</tr>
<tr>
<td>timezone</td>
<td>timeZone</td>
<td>String</td>
<td>The timezone used to store local dates. Default is ‘local’.</td>
</tr>
Expand Down Expand Up @@ -280,45 +280,6 @@ Example:
}
```

### Date types

For TIMESTAMP and DATE types, use the `dateType` option to specify custom type. By default it is DATETIME.

Example:

```javascript
{ startTime :
{ type: Date,
dataType: 'timestamp'
}
}
```

**Note:** When quering a `DATE` type, please be aware that values sent to the server via REST API call will be converted to a Date object using the server timezone. Then, only `YYYY-MM-DD` part of the date will be used for the SQL query.

For example, if the client and the server is in GMT+2 and GMT -2 timezone respectively. Performing the following operation at `02:00 on 2016/11/22` from the client side:

```javascript
var products = Product.find({where:{expired:new Date(2016,11,22)}});
```

will result in the REST URL to look like: `/api/Products/?filter={"where":{"expired":"2016-12-21T22:00:00Z"}}` and the SQL will be like this:

```SQL
SELECT * FROM Product WHERE expired = '2016-12-21'
```
which is not correct.

**Solution:** The workaround to avoid such edge case boundaries with timezones is to use the `DATE` type field as a **_string_** type in the LoopBack model definition.

```javascript
{ birthday :
{ type: String,
dataType: 'date'
}
}
```

### Other types

Convert String / DataSource.Text / DataSource.JSON to the following MySQL types:
Expand Down Expand Up @@ -351,6 +312,18 @@ Example: 
}
```

Convert JSON Date types to  datetime or timestamp

Example: 

```javascript
{ startTime :
{ type: Date,
dataType: 'timestamp'
}
}
```

### Enum

Enums are special. Create an Enum using Enum factory:
Expand Down
60 changes: 9 additions & 51 deletions lib/mysql.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,6 @@ function generateOptions(settings) {
charset: s.collation.toUpperCase(), // Correct by docs despite seeming odd.
supportBigNumbers: s.supportBigNumbers,
connectionLimit: s.connectionLimit,
//prevent mysqljs from converting DATE, DATETIME and TIMESTAMP types
//to javascript Date object
dateStrings: true,
};

// Don't configure the DB if the pool can be used for multiple DBs
Expand Down Expand Up @@ -310,40 +307,17 @@ MySQL.prototype.updateOrCreate = function(model, data, options, cb) {
this._modifyOrCreate(model, data, options, fields, cb);
};

function dateToMysql(dt, tz) {
if (!tz || tz == 'local') {
return dt.getFullYear() + '-' +
fillZeros(dt.getMonth() + 1) + '-' +
fillZeros(dt.getDate()) + ' ' +
fillZeros(dt.getHours()) + ':' +
fillZeros(dt.getMinutes()) + ':' +
fillZeros(dt.getSeconds());
} else {
tz = convertTimezone(tz);

if (tz !== false && tz !== 0) dt.setTime(dt.getTime() + (tz * 60000));

return dt.getUTCFullYear() + '-' +
fillZeros(dt.getUTCMonth() + 1) + '-' +
fillZeros(dt.getUTCDate()) + ' ' +
fillZeros(dt.getUTCHours()) + ':' +
fillZeros(dt.getUTCMinutes()) + ':' +
fillZeros(dt.getUTCSeconds());
}
function dateToMysql(val) {
return val.getUTCFullYear() + '-' +
fillZeros(val.getUTCMonth() + 1) + '-' +
fillZeros(val.getUTCDate()) + ' ' +
fillZeros(val.getUTCHours()) + ':' +
fillZeros(val.getUTCMinutes()) + ':' +
fillZeros(val.getUTCSeconds());

function fillZeros(v) {
return v < 10 ? '0' + v : v;
}

function convertTimezone(tz) {
if (tz === 'Z') {
return 0;
}

var m = tz.match(/([\+\-\s])(\d\d):?(\d\d)?/);
if (m) return (m[1] == '-' ? -1 : 1) * (parseInt(m[2], 10) + ((m[3] ? parseInt(m[3], 10) : 0) / 60)) * 60;
return false;
}
}

MySQL.prototype.getInsertedId = function(model, info) {
Expand Down Expand Up @@ -382,13 +356,6 @@ MySQL.prototype.toColumnValue = function(prop, val) {
if (!val.toUTCString) {
val = new Date(val);
}

if (prop.dataType == 'date') {
return dateToMysql(val).substring(0, 10);
} else if (prop.dataType == 'timestamp' || (prop.mysql && prop.mysql.dataType == 'timestamp')) {
var tz = this.client.config.connectionConfig.timezone;
return dateToMysql(val, tz);
}
return dateToMysql(val);
}
if (prop.type === Boolean) {
Expand Down Expand Up @@ -448,19 +415,10 @@ MySQL.prototype.fromColumnValue = function(prop, val) {
// MySQL allows, unless NO_ZERO_DATE is set, dummy date/time entries
// new Date() will return Invalid Date for those, so we need to handle
// those separate.
if (!val || val == '0000-00-00 00:00:00' || val == '0000-00-00') {
if (val == '0000-00-00 00:00:00') {
val = null;
} else {
var dateString = val;
var tz = this.client.config.connectionConfig.timezone;
if (prop.dataType == 'date') {
dateString += ' 00:00:00';
}
//if datatype is timestamp and zimezone is not local - convert to proper timezone
if (tz !== 'local' && (prop.dataType == 'timestamp' || (prop.mysql && prop.mysql.dataType == 'timestamp'))) {
dateString += ' ' + tz;
}
return new Date(dateString);
val = new Date(val.toString().replace(/GMT.*$/, 'GMT'));
}
break;
case 'Boolean':
Expand Down
Loading

0 comments on commit 345492e

Please sign in to comment.