2016-10-31 21:02:14 +00:00
# loopback-connector-mysql
2012-12-14 14:01:44 +00:00
2020-06-05 22:16:51 +00:00
[MySQL ](https://www.mysql.com/ ) is a popular open-source relational database
management system (RDBMS). The `loopback-connector-mysql` module provides the
MySQL connector module for the LoopBack framework.
2012-12-14 14:01:44 +00:00
2013-10-28 22:12:20 +00:00
## Installation
2017-01-11 00:13:45 +00:00
In your application root directory, enter this command to install the connector:
```sh
2013-10-28 22:12:20 +00:00
npm install loopback-connector-mysql --save
2017-01-11 00:13:45 +00:00
```
2023-06-18 18:04:31 +00:00
**Note**: Since `loopback-connector-mysql` v7.x.x, this MySQL connector has dropped support for MySQL 5.7 and requires MySQL 8.0+.
2020-06-05 22:16:51 +00:00
This installs the module from npm and adds it as a dependency to the
application's `package.json` file.
2017-01-11 00:13:45 +00:00
2020-06-05 22:16:51 +00:00
If you create a MySQL data source using the data source generator as described
below, you don't have to do this, since the generator will run `npm install` for
you.
2017-01-11 00:13:45 +00:00
## Creating a MySQL data source
2020-06-05 22:16:51 +00:00
For LoopBack 4 users, use the LoopBack 4
[Command-line interface ](https://loopback.io/doc/en/lb4/Command-line-interface.html )
to generate a DataSource with MySQL connector to your LB4 application. Run
[`lb4 datasource` ](https://loopback.io/doc/en/lb4/DataSource-generator.html ), it
will prompt for configurations such as host, post, etc. that are required to
connect to a MySQL database.
After setting it up, the configuration can be found under
`src/datasources/<DataSourceName>.datasource.ts` , which would look like this:
```ts
const config = {
name: 'db',
connector: 'mysql',
url: '',
host: 'localhost',
port: 3306,
user: 'user',
password: 'pass',
database: 'testdb',
};
```
< details > < summary markdown = "span" > < strong > For LoopBack 3 users< / strong > < / summary >
Use
the [Data source generator ](http://loopback.io/doc/en/lb3/Data-source-generator.html ) to
add a MySQL data source to your application.
The generator will prompt for the database server hostname, port, and other
settings required to connect to a MySQL database. It will also run the
`npm install` command above for you.
2017-01-11 00:13:45 +00:00
The entry in the application's `/server/datasources.json` will look like this:
```javascript
"mydb": {
"name": "mydb",
"connector": "mysql",
"host": "myserver",
"port": 3306,
"database": "mydb",
"password": "mypassword",
"user": "admin"
}
```
2020-06-05 22:16:51 +00:00
< / details >
Edit `<DataSourceName>.datasources.ts` to add any other additional properties
that you require.
2017-01-11 00:13:45 +00:00
### Properties
< table >
< thead >
< tr >
< th width = "150" > Property< / th >
< th width = "80" > Type< / th >
< th > Description< / th >
< / tr >
< / thead >
< tbody >
< tr >
< td > collation< / td >
< td > String< / td >
< td > Determines the charset for the connection. Default is utf8_general_ci.< / td >
< / tr >
< tr >
< td > connector< / td >
< td > String< / td >
< td > Connector name, either “loopback-connector-mysql” or “mysql”.< / td >
< / tr >
< tr >
< td > connectionLimit< / td >
< td > Number< / td >
< td > The maximum number of connections to create at once. Default is 10.< / td >
< / tr >
< tr >
< td > database< / td >
< td > String< / td >
< td > Database name< / td >
< / tr >
< tr >
< td > debug< / td >
< td > Boolean< / td >
< td > If true, turn on verbose mode to debug database queries and lifecycle.< / td >
< / tr >
< tr >
< td > host< / td >
< td > String< / td >
< td > Database host name< / td >
< / tr >
< tr >
< td > password< / td >
< td > String< / td >
< td > Password to connect to database< / td >
< / tr >
< tr >
< td > port< / td >
< td > Number< / td >
< td > Database TCP port< / td >
< / tr >
< tr >
< td > socketPath< / td >
< td > String< / td >
< td > The path to a unix domain socket to connect to. When used host and port are ignored.< / td >
< / tr >
< tr >
< td > supportBigNumbers< / td >
< td > Boolean< / td >
< td > Enable this option to deal with big numbers (BIGINT and DECIMAL columns) in the database. Default is false.< / td >
< / tr >
< tr >
2017-04-24 20:19:33 +00:00
< td > timeZone< / td >
2017-01-11 00:13:45 +00:00
< td > String< / td >
< td > The timezone used to store local dates. Default is ‘ local’ .< / td >
< / tr >
< tr >
< td > url< / td >
< td > String< / td >
< td > Connection URL of form < code > mysql://user:password@host/db< / code > . Overrides other connection settings.< / td >
< / tr >
< tr >
< td > username< / td >
< td > String< / td >
< td > Username to connect to database< / td >
< / tr >
2021-08-23 14:11:19 +00:00
< tr >
< td > allowExtendedOperators< / td >
< td > Boolean< / td >
< td > Set to < code > true< / code > to enable MySQL-specific operators
such as < code > match< / code > . Learn more in
< a href = "#extended-operators" > Extended operators< / a > below.
< / td >
< / tr >
2017-01-11 00:13:45 +00:00
< / tbody >
< / table >
2020-06-05 22:16:51 +00:00
**NOTE**: In addition to these properties, you can use additional parameters
supported by [`node-mysql` ](https://github.com/felixge/node-mysql ).
2017-01-11 00:13:45 +00:00
## Type mappings
2013-10-28 22:12:20 +00:00
2020-08-05 14:54:52 +00:00
See [LoopBack 4 types ](http://loopback.io/doc/en/lb4/LoopBack-types.html ) (or [LoopBack 3 types ](http://loopback.io/doc/en/lb3/LoopBack-types.html )) for
2020-06-05 22:16:51 +00:00
details on LoopBack's data types.
2012-12-14 14:01:44 +00:00
2017-01-11 00:13:45 +00:00
### LoopBack to MySQL types
2012-12-14 14:01:44 +00:00
2017-01-11 00:13:45 +00:00
< table >
< thead >
< tr >
2020-03-19 16:41:21 +00:00
< th width = "450" > LoopBack Type< / th >
< th width = "450" > MySQL Type< / th >
2017-01-11 00:13:45 +00:00
< / tr >
< / thead >
< tbody >
< tr >
< td > String/JSON< / td >
< td > VARCHAR< / td >
< / tr >
< tr >
< td > Text< / td >
< td > TEXT< / td >
< / tr >
< tr >
< td > Number< / td >
< td > INT< / td >
< / tr >
< tr >
< td > Date< / td >
< td > DATETIME< / td >
< / tr >
< tr >
< td > Boolean< / td >
< td > TINYINT(1)< / td >
< / tr >
< tr >
< td > < a href = "http://apidocs.strongloop.com/loopback-datasource-juggler/#geopoint" class = "external-link" > GeoPoint< / a > object< / td >
< td > POINT< / td >
< / tr >
< tr >
< td > Custom Enum type< br > (See < a href = "#enum" > Enum< / a > below)< / td >
< td > ENUM< / td >
< / tr >
< / tbody >
< / table >
2012-12-14 14:01:44 +00:00
2017-01-11 00:13:45 +00:00
### MySQL to LoopBack types
< table >
2020-03-19 16:41:21 +00:00
< thead >
2017-01-11 00:13:45 +00:00
< tr >
2020-03-19 16:41:21 +00:00
< th width = "450" > MySQL Type< / th >
< th width = "450" > LoopBack Type< / th >
2017-01-11 00:13:45 +00:00
< / tr >
2020-03-19 16:41:21 +00:00
< / thead >
< tbody >
2017-01-11 00:13:45 +00:00
< tr >
< td > CHAR< / td >
< td > String< / td >
< / tr >
< tr >
2017-07-26 13:51:09 +00:00
< td > BIT(1)< br > CHAR(1)< br > TINYINT(1)< / td >
2017-01-11 00:13:45 +00:00
< td > Boolean< / td >
< / tr >
< tr >
< td > VARCHAR< br > TINYTEXT< br > MEDIUMTEXT< br > LONGTEXT< br > TEXT< br > ENUM< br > SET< / td >
< td > String< / td >
< / tr >
< tr >
< td > TINYBLOB< br > MEDIUMBLOB< br > LONGBLOB< br > BLOB< br > BINARY< br > VARBINARY< br > BIT< / td >
< td > Node.js < a href = "http://nodejs.org/api/buffer.html" > Buffer object< / a > < / td >
< / tr >
< tr >
< td > TINYINT< br > SMALLINT< br > INT< br > MEDIUMINT< br > YEAR< br > FLOAT< br > DOUBLE< br > NUMERIC< br > DECIMAL< / td >
< td >
< p > Number< br > For FLOAT and DOUBLE, see < a href = "#floating-point-types" > Floating-point types< / a > . < / p >
< p > For NUMERIC and DECIMAL, see < a href = "MySQL-connector.html" > Fixed-point exact value types< / a > < / p >
< / td >
< / tr >
< tr >
< td > DATE< br > TIMESTAMP< br > DATETIME< / td >
< td > Date< / td >
< / tr >
< / tbody >
< / table >
2020-03-16 14:09:17 +00:00
_NOTE_ as of v3.0.0 of MySQL Connector, the following flags were introduced:
2017-07-26 13:51:09 +00:00
2020-06-05 22:16:51 +00:00
- `treatCHAR1AsString` default `false` - treats CHAR(1) as a String instead of a
Boolean
- `treatBIT1AsBit` default `true` - treats BIT(1) as a Boolean instead of a
Binary
- `treatTINYINT1AsTinyInt` default `true` - treats TINYINT(1) as a Boolean
instead of a Number
## Data mapping properties
2020-08-05 14:54:52 +00:00
Except the common database-specific properties we introduce in [How LoopBack Models Map To Database Tables/Collections ](https://loopback.io/doc/en/lb4/Model.html#how-loopback-models-map-to-database-tablescollections ), the following are more detailed examples and MySQL-specific settings.
2020-06-05 22:16:51 +00:00
### Table/Column Names
Besides the basic LoopBack types, as we introduced above, you can also specify
additional MySQL-specific properties for a LoopBack model. It would be mapped to
the database.
Use the `mysql.<property>` in the model definition or the property definition to
configure the table/column definition.
For example, the following settings would allow you to have custom table name
(`Custom_User`) and column name (`custom_id` and `custom_name` ). Such mapping is
useful when you'd like to have different table/column names from the model:
{% include code-caption.html content="user.model.ts" %}
```ts
@model ({
settings: { mysql: { schema: 'testdb', table: 'Custom_User'} },
})
export class User extends Entity {
@property ({
type: 'number',
required: true,
id: true,
mysql: {
columnName: 'custom_id',
},
})
id: number;
2017-01-11 00:13:45 +00:00
2020-06-05 22:16:51 +00:00
@property ({
type: 'string',
mysql: {
columnName: 'custom_name',
},
})
name?: string;
```
2017-01-11 00:13:45 +00:00
2020-06-05 22:16:51 +00:00
< details > < summary markdown = "span" > < strong > For LoopBack 3 users< / strong > < / summary >
2020-03-16 14:09:17 +00:00
2017-01-11 00:13:45 +00:00
```javascript
2020-06-05 22:16:51 +00:00
{
"name": "User",
"options": {
"mysql": {
"schema": "testdb",
"table": "Custom_User"
2012-12-14 14:01:44 +00:00
}
2020-06-05 22:16:51 +00:00
},
"properties": {
"id": {
"type": "Number",
"required": true,
"mysql": {
"columnName": "custom_id",
}
},
"name": {
"type": "String",
"mysql": {
"columnName": "custom_name",
}
},
}
2017-01-11 00:13:45 +00:00
}
```
2020-06-05 22:16:51 +00:00
< / details >
### Numeric Types
2017-01-11 00:13:45 +00:00
2020-06-05 22:16:51 +00:00
Except the names, you can also use the dataType column/property attribute to
specify what MySQL column type to use. The following MySQL type-dataType
combinations are supported:
- number
2020-03-16 14:09:17 +00:00
- integer
- tinyint
- smallint
- mediumint
- int
- bigint
2020-06-05 22:16:51 +00:00
- float
- double
- decimal
2017-01-11 00:13:45 +00:00
2020-06-05 22:16:51 +00:00
The following examples will be in LoopBack 4 style, but it's the same if you
provide `mysql.<property>` to the LB3 property definition.
2020-03-16 14:09:17 +00:00
2020-06-05 22:16:51 +00:00
#### Floating-point types
2020-03-16 14:09:17 +00:00
2020-06-05 22:16:51 +00:00
For Float and Double data types, use the `precision` and `scale` options to
specify custom precision. Default is (16,8).
2017-01-11 00:13:45 +00:00
2020-06-05 22:16:51 +00:00
< details > < summary markdown = "span" > < strong > Example< / strong > < / summary >
2017-01-11 00:13:45 +00:00
2020-06-05 22:16:51 +00:00
```ts
@property ({
type: 'Number',
mysql: {
2017-01-11 00:13:45 +00:00
dataType: 'float',
precision: 20,
scale: 4
}
2020-06-05 22:16:51 +00:00
})
price: Number;
2017-01-11 00:13:45 +00:00
```
2020-06-05 22:16:51 +00:00
< / details >
2017-01-11 00:13:45 +00:00
2020-06-05 22:16:51 +00:00
#### Fixed-point exact value types
2017-01-11 00:13:45 +00:00
2020-06-05 22:16:51 +00:00
For Decimal and Numeric types, use the `precision` and `scale` options to
specify custom precision. Default is (9,2). These aren't likely to function as
true fixed-point.
2017-01-11 00:13:45 +00:00
2020-06-05 22:16:51 +00:00
< details > < summary markdown = "span" > < strong > Example< / strong > < / summary >
```ts
@property ({
type: 'Number',
mysql: {
2017-01-11 00:13:45 +00:00
dataType: 'decimal',
precision: 12,
scale: 8
}
2020-06-05 22:16:51 +00:00
})
price: Number;
2017-01-11 00:13:45 +00:00
```
2020-06-05 22:16:51 +00:00
< / details >
### Text types
2017-01-11 00:13:45 +00:00
Convert String / DataSource.Text / DataSource.JSON to the following MySQL types:
2020-03-16 14:09:17 +00:00
- varchar
- char
- text
- mediumtext
- tinytext
- longtext
2017-01-11 00:13:45 +00:00
2020-06-05 22:16:51 +00:00
< details > < summary markdown = "span" > < strong > Example< / strong > < / summary >
2017-01-11 00:13:45 +00:00
2020-06-05 22:16:51 +00:00
```ts
@property ({
type: 'String',
mysql: {
2017-01-11 00:13:45 +00:00
dataType: 'char',
2020-06-05 22:16:51 +00:00
dataLength: 24 // limits the property length
},
})
userName: String;
2017-01-11 00:13:45 +00:00
```
2020-06-05 22:16:51 +00:00
< / details >
2017-01-11 00:13:45 +00:00
2020-06-05 22:16:51 +00:00
### Dat types
2017-01-11 00:13:45 +00:00
2020-06-05 22:16:51 +00:00
Convert JSON Date types to datetime or timestamp.
2017-04-24 20:19:33 +00:00
2020-06-05 22:16:51 +00:00
< details > < summary markdown = "span" > < strong > Example< / strong > < / summary >
2017-04-24 20:19:33 +00:00
2020-06-05 22:16:51 +00:00
```ts
@property ({
type: 'Date',
mysql: {
dataType: 'timestamp',
},
})
startTime: Date;
2017-04-24 20:19:33 +00:00
```
2020-06-05 22:16:51 +00:00
< / details >
2017-01-11 00:13:45 +00:00
### Enum
2020-09-11 14:04:07 +00:00
See the [Model ENUM property ](https://loopback.io/doc/en/lb4/Model.html#enum-property ) for details.
2020-06-05 22:16:51 +00:00
### Default Clause/Constant
2020-08-05 14:54:52 +00:00
Use the `default` and `dataType` properties to have MySQL handle **setting column `DEFAULT` value** .
2020-06-05 22:16:51 +00:00
< details > < summary markdown = "span" > < strong > Example< / strong > < / summary >
```ts
@property ({
type: 'String',
mysql: {
2020-08-05 14:54:52 +00:00
dataType: 'varchar',
2020-06-05 22:16:51 +00:00
default: 'pending'
}
})
status: String;
@property ({
type: 'Number',
mysql: {
2020-08-05 14:54:52 +00:00
dataType: 'int',
2020-06-05 22:16:51 +00:00
default: 42
}
})
maxDays: Number;
2020-08-05 14:54:52 +00:00
@property ({
type: 'boolean',
mysql: {
dataType: 'tinyint',
default: 1
}
})
isDone: Boolean;
2017-01-11 00:13:45 +00:00
```
2020-06-05 22:16:51 +00:00
< / details >
For the date or timestamp types use `CURRENT_TIMESTAMP` or `now` .
< details > < summary markdown = "span" > < strong > Example< / strong > < / summary >
```ts
@property ({
type: 'Date',
mysql: {
2020-08-05 14:54:52 +00:00
dataType: 'datetime',
2020-06-05 22:16:51 +00:00
default: 'CURRENT_TIMESTAMP'
}
})
last_modified: Date;
```
< / details >
**NOTE**: The following column types do **NOT** supported
[MySQL Default Values ](https://dev.mysql.com/doc/refman/5.7/en/data-type-defaults.html ):
- BLOB
- TEXT
- GEOMETRY
- JSON
2021-08-23 14:11:19 +00:00
## Extended operators
MySQL connector supports the following MySQL-specific operators:
- [`match` ](#operator-match )
Please note extended operators are disabled by default, you must enable
them at datasource level or model level by setting `allowExtendedOperators` to
`true` .
### Operator `match`
The `match` operator allows you to perform a full text search using the [MATCH() .. AGAINST() ](https://dev.mysql.com/doc/refman/8.0/en/fulltext-search.html ) operator in MySQL.
Three different modes of the `MATCH` clause are also available in the form of operators -
- `matchbool` for [Boolean Full Text Search ](https://dev.mysql.com/doc/refman/8.0/en/fulltext-boolean.html )
- `matchnl` for [Natural Language Full Text Search ](https://dev.mysql.com/doc/refman/8.0/en/fulltext-natural-language.html )
- `matchqe` for [Full-Text Searches with Query Expansion ](https://dev.mysql.com/doc/refman/8.0/en/fulltext-query-expansion.html )
- `matchnlqe` for [Full-Text Searches with Query Expansion ](https://dev.mysql.com/doc/refman/8.0/en/fulltext-query-expansion.html ) with the `IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION` modifier.
By default, the `match` operator works in Natural Language mode.
**Note** The fields you are querying must be setup with a `FULLTEXT` index to perform full text search on them.
Assuming a model such as this:
```ts
@model ({
settings: {
allowExtendedOperators: true,
}
})
class Post {
@property ({
type: 'string',
mysql: {
index: {
kind: 'FULLTEXT'
}
},
})
content: string;
}
```
You can query the content field as follows:
```ts
const posts = await postRepository.find({
where: {
{
content: {match: 'someString'},
}
}
});
```
2017-01-11 00:13:45 +00:00
## Discovery and auto-migration
### Model discovery
2020-06-05 22:16:51 +00:00
The MySQL connector supports _model discovery_ that enables you to create
LoopBack models based on an existing database schema. Once you defined your
datasource:
- LoopBack 4 users could use the commend
[`lb4 discover` ](https://loopback.io/doc/en/lb4/Discovering-models.html ) to
discover models.
- For LB3 users, please check
[Discovering models from relational databases ](https://loopback.io/doc/en/lb3/Discovering-models-from-relational-databases.html ).
(See
[database discovery API ](http://apidocs.strongloop.com/loopback-datasource-juggler/#datasource-prototype-discoverandbuildmodels )
for related APIs information)
2017-01-11 00:13:45 +00:00
2017-05-04 14:48:46 +00:00
### Auto-migration
2017-01-11 00:13:45 +00:00
2020-06-05 22:16:51 +00:00
The MySQL connector also supports _auto-migration_ that enables you to create a
database schema from LoopBack models. For example, based on the following model,
the auto-migration method would create/alter existing `Customer` table in the
database. Table `Customer` would have two columns: `name` and `id` , where `id`
is also the primary key that has `auto_increment` set as it has definition of
`type: 'Number'` and `generated: true` :
```ts
@model ()
export class Customer extends Entity {
@property ({
id: true,
type: 'Number',
generated: true,
})
id: number;
@property ({
type: 'string',
})
name: string;
}
```
Moreover, additional MySQL-specific properties mentioned in the
[Data mapping properties ](#data-mapping-properties ) section work with
auto-migration as well.
#### Auto-generated ids
For now LoopBack MySQL connector only supports auto-generated id
(`generated: true`) for integer type as for MySQL, the default id type is
_integer_. If you'd like to use other types such as string (uuid) as the id
type, you can:
2017-01-11 00:13:45 +00:00
2020-06-05 22:16:51 +00:00
- use uuid that is **generated by your LB application** by setting
[`defaultFn: uuid` ](https://loopback.io/doc/en/lb4/Model.html#property-decorator ).
```ts
@property ({
id: true,
type: 'string'
defaultFn: 'uuidv4',
// generated: true, -> not needed
})
id: string;
```
- Alter the table in your database to use a certain function if you prefer
having **the database to generate the value** .
```ts
@property ({
id: true,
type: 'string'
generated: true, // to indicate the value generates by the db
useDefaultIdType: false, // needed
})
id: string;
```
2017-01-11 00:13:45 +00:00
2017-06-15 17:32:08 +00:00
#### Auto-migrate/Auto-update models with foreign keys
2020-06-05 22:16:51 +00:00
Foreign key constraints can be defined in the model definition.
2017-06-15 17:32:08 +00:00
2020-06-05 22:16:51 +00:00
**Note**: The order of table creation is important. A referenced table must
2021-04-13 10:38:54 +00:00
exist before creating a foreign key constraint. The order can be specified
using the optional < a href = "https://loopback.io/doc/en/lb4/apidocs.repository.schemamigrationoptions.html" > `SchemaMigrationOptions`</ a > argument of `migrateSchema` :
```
await app.migrateSchema({
models: [ 'Customer', 'Order' ]
});
```
2017-06-15 17:32:08 +00:00
2020-06-05 22:16:51 +00:00
Define your models and the foreign key constraints as follows:
{% include code-caption.html content="customer.model.ts" %}
```ts
@model ()
export class Customer extends Entity {
@property ({
id: true,
type: 'Number',
generated: true,
})
id: number;
@property ({
type: 'string',
})
name: string;
}
```
`order.model.ts` :
```ts
@model ({
settings: {
foreignKeys: {
fk_order_customerId: {
name: 'fk_order_customerId',
entity: 'Customer',
entityKey: 'id',
foreignKey: 'customerId',
},
},
})
export class Order extends Entity {
@property ({
id: true,
type: 'Number',
generated: true
})
id: number;
@property ({
type: 'string'
})
name: string;
@property ({
type: 'Number'
})
customerId: number;
}
```
< details > < summary markdown = "span" > < strong > For LoopBack 3 users< / strong > < / summary >
2020-03-16 14:09:17 +00:00
2017-06-15 17:32:08 +00:00
```json
2020-06-05 22:16:51 +00:00
({
"name": "Customer",
"options": {
"idInjection": false
},
2017-06-15 17:32:08 +00:00
"properties": {
2020-06-05 22:16:51 +00:00
"id": {
"type": "Number",
"id": 1
2017-06-20 16:01:55 +00:00
},
2017-06-15 17:32:08 +00:00
"name": {
2020-06-05 22:16:51 +00:00
"type": "String",
"required": false
2017-06-20 16:01:55 +00:00
}
2020-06-05 22:16:51 +00:00
}
},
{
"name": "Order",
"options": {
"idInjection": false,
"foreignKeys": {
"fk_order_customerId": {
"name": "fk_order_customerId",
"entity": "Customer",
"entityKey": "id",
"foreignKey": "customerId"
}
2017-06-15 17:32:08 +00:00
}
},
2020-06-05 22:16:51 +00:00
"properties": {
"id": {
"type": "Number"
"id": 1
},
"customerId": {
"type": "Number"
},
"description": {
"type": "String",
"required": false
2017-06-15 17:32:08 +00:00
}
}
2020-06-05 22:16:51 +00:00
})
2017-06-15 17:32:08 +00:00
```
2020-06-05 22:16:51 +00:00
< / details >
MySQL handles the foreign key integrity by the referential action specified by
`ON UPDATE` and `ON DELETE` . You can specify which referential actions the
foreign key follows in the model definition upon auto-migrate or auto-update
operation. Both `onDelete` and `onUpdate` default to `restrict` .
Take the example we showed above, let's add the referential action to the
foreign key `customerId` :
```ts
@model ({
settings: {
foreignKeys: {
fk_order_customerId: {
name: 'fk_order_customerId',
entity: 'Customer',
entityKey: 'id',
foreignKey: 'customerId',
onUpdate: 'restrict', // restrict|cascade|set null|no action|set default
onDelete: 'cascade' // restrict|cascade|set null|no action|set default
},
},
})
export class Order extends Entity {
...
```
< details > < summary markdown = "span" > < strong > For LoopBack 3 users< / strong > < / summary >
**model-definiton.json**
2017-06-15 17:32:08 +00:00
```json
{
2020-06-05 22:16:51 +00:00
"name": "Customer",
"options": {
"idInjection": false
},
2017-06-15 17:32:08 +00:00
"properties": {
2020-06-05 22:16:51 +00:00
"id": {
"type": "Number",
"id": 1
2017-06-20 16:01:55 +00:00
},
2017-06-15 17:32:08 +00:00
"name": {
2020-06-05 22:16:51 +00:00
"type": "String",
"required": false
}
}
},
{
"name": "Order",
"options": {
"idInjection": false,
"foreignKeys": {
"fk_order_customerId": {
"name": "fk_order_customerId",
"entity": "Customer",
"entityKey": "id",
"foreignKey": "customerId",
"onUpdate": "restrict",
"onDelete": "cascade"
}
2017-06-15 17:32:08 +00:00
}
},
2020-06-05 22:16:51 +00:00
"properties": {
"id": {
"type": "Number"
"id": 1
},
"customerId": {
"type": "Number"
},
"description": {
"type": "String",
"required": false
}
}
2017-06-15 17:32:08 +00:00
}
```
**boot-script.js**
2020-03-16 14:09:17 +00:00
2017-06-15 17:32:08 +00:00
```js
2020-06-05 22:16:51 +00:00
module.exports = function (app) {
2017-06-15 17:32:08 +00:00
var mysqlDs = app.dataSources.mysqlDS;
2020-06-05 22:16:51 +00:00
var Book = app.models.Order;
var Author = app.models.Customer;
2017-06-15 17:32:08 +00:00
2020-06-05 22:16:51 +00:00
// first autoupdate the `Customer` model to avoid foreign key constraint failure
mysqlDs.autoupdate('Customer', function (err) {
2017-06-15 17:32:08 +00:00
if (err) throw err;
2020-06-05 22:16:51 +00:00
console.log('\nAutoupdated table `Customer` .');
2017-06-15 17:32:08 +00:00
2020-06-05 22:16:51 +00:00
mysqlDs.autoupdate('Order', function (err) {
2017-06-20 16:01:55 +00:00
if (err) throw err;
2020-06-05 22:16:51 +00:00
console.log('\nAutoupdated table `Order` .');
// at this point the database table `Order` should have one foreign key `customerId` integrated
2017-06-20 16:01:55 +00:00
});
2017-06-15 17:32:08 +00:00
});
};
```
2020-03-16 14:09:17 +00:00
2020-06-05 22:16:51 +00:00
< / details >
2017-06-16 16:27:48 +00:00
#### Breaking Changes with GeoPoint since 5.x
2020-03-16 14:09:17 +00:00
2020-06-05 22:16:51 +00:00
Prior to `loopback-connector-mysql@5.x` , MySQL connector was saving and loading
GeoPoint properties from the MySQL database in reverse. MySQL expects values to
be `POINT(X, Y)` or `POINT(lng, lat)` , but the connector was saving them in the
opposite order(i.e. `POINT(lat,lng)` ).
Use the `geopoint` type to achieve so:
```ts
@property ({
type: 'geopoint'
})
name: GeoPoint;
```
If you have an application with a model that has a GeoPoint property using
previous versions of this connector, you can migrate your models using the
following programmatic approach:
2020-07-22 08:56:26 +00:00
< details > < summary markdown = "span" > < strong > Click here to expand< / strong > < / summary >
2020-06-05 22:16:51 +00:00
**NOTE** Please back up the database tables that have your application data
before performing any of the steps.
2020-03-16 14:09:17 +00:00
2017-06-16 16:27:48 +00:00
1. Create a boot script under `server/boot/` directory with the following:
2020-03-16 14:09:17 +00:00
2017-06-16 16:27:48 +00:00
```js
'use strict';
2020-06-05 22:16:51 +00:00
module.exports = function (app) {
2017-06-16 16:27:48 +00:00
function findAndUpdate() {
var teashop = app.models.teashop;
//find all instances of the model we'd like to migrate
2020-06-05 22:16:51 +00:00
teashop.find({}, function (err, teashops) {
teashops.forEach(function (teashopInstance) {
2017-06-16 16:27:48 +00:00
//what we fetch back from the db is wrong, so need to revert it here
2020-03-16 14:09:17 +00:00
var newLocation = {
lng: teashopInstance.location.lat,
2020-06-05 22:16:51 +00:00
lat: teashopInstance.location.lng,
2020-03-16 14:09:17 +00:00
};
2017-06-16 16:27:48 +00:00
//only update the GeoPoint property for the model
2020-06-05 22:16:51 +00:00
teashopInstance.updateAttribute('location', newLocation, function (
2020-03-16 14:09:17 +00:00
err,
2020-06-05 22:16:51 +00:00
inst,
2020-03-16 14:09:17 +00:00
) {
if (err) console.log('update attribute failed', err);
else console.log('updateAttribute successful');
2017-06-16 16:27:48 +00:00
});
});
});
}
findAndUpdate();
};
```
2020-03-16 14:09:17 +00:00
2017-06-16 16:27:48 +00:00
2. Run the boot script by simply running your application or `node .`
2017-06-15 17:32:08 +00:00
2017-06-16 16:27:48 +00:00
For the above example, the model definition is as follows:
2020-03-16 14:09:17 +00:00
2017-06-16 16:27:48 +00:00
```json
{
"name": "teashop",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"name": {
"type": "string",
"default": "storename"
},
"location": {
"type": "geopoint"
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": {}
}
```
2017-01-11 00:13:45 +00:00
2020-06-05 22:16:51 +00:00
< / details >
2017-01-11 00:13:45 +00:00
## Running tests
2015-03-15 21:41:46 +00:00
2017-05-12 14:13:15 +00:00
### Own instance
2020-03-16 14:09:17 +00:00
2020-06-05 22:16:51 +00:00
If you have a local or remote MySQL instance and would like to use that to run
the test suite, use the following command:
2020-03-16 14:09:17 +00:00
2017-05-12 14:13:15 +00:00
- Linux
2020-03-16 14:09:17 +00:00
2017-05-12 14:13:15 +00:00
```bash
2017-05-15 17:38:30 +00:00
MYSQL_HOST=< HOST > MYSQL_PORT=< PORT > MYSQL_USER=< USER > MYSQL_PASSWORD=< PASSWORD > MYSQL_DATABASE=< DATABASE > CI=true npm test
2017-05-12 14:13:15 +00:00
```
2020-03-16 14:09:17 +00:00
2017-05-12 14:13:15 +00:00
- Windows
2020-03-16 14:09:17 +00:00
2017-05-12 14:13:15 +00:00
```bash
2017-05-15 17:38:30 +00:00
SET MYSQL_HOST=< HOST > SET MYSQL_PORT=< PORT > SET MYSQL_USER=< USER > SET MYSQL_PASSWORD=< PASSWORD > SET MYSQL_DATABASE=< DATABASE > SET CI=true npm test
2017-05-12 14:13:15 +00:00
```
2015-03-15 21:41:46 +00:00
2017-05-12 14:13:15 +00:00
### Docker
2020-03-16 14:09:17 +00:00
2020-06-05 22:16:51 +00:00
If you do not have a local MySQL instance, you can also run the test suite with
very minimal requirements.
2020-03-16 14:09:17 +00:00
2020-06-05 22:16:51 +00:00
- Assuming you have [Docker ](https://docs.docker.com/engine/installation/ )
installed, run the following script which would spawn a MySQL instance on your
local:
2020-03-16 14:09:17 +00:00
2017-05-12 14:13:15 +00:00
```bash
2017-05-15 17:38:30 +00:00
source setup.sh < HOST > < PORT > < USER > < PASSWORD > < DATABASE >
2017-05-12 14:13:15 +00:00
```
2020-03-16 14:09:17 +00:00
2020-06-05 22:16:51 +00:00
where `<HOST>` , `<PORT>` , `<USER>` , `<PASSWORD>` and `<DATABASE>` are optional
parameters. The default values are `localhost` , `3306` , `root` , `pass` and
`testdb` respectively.
2020-03-16 14:09:17 +00:00
2017-05-12 14:13:15 +00:00
- Run the test:
2020-03-16 14:09:17 +00:00
2017-05-12 14:13:15 +00:00
```bash
npm test
```