Merge branch 'release/1.2.0' into production

This commit is contained in:
Raymond Feng 2014-04-08 10:50:11 -07:00
commit a6c2299637
16 changed files with 2234 additions and 2239 deletions

3
.gitignore vendored
View File

@ -1,2 +1,5 @@
node_modules node_modules
coverage coverage
*.tgz
*.xml
.loopbackrc

294
LICENSE
View File

@ -1,4 +1,10 @@
Copyright (c) 2013 StrongLoop, Inc. Copyright (c) 2013-2014 StrongLoop, Inc.
loopback-connector-mysql uses a 'dual license' model. Users may use
loopback-connector-mysql under the terms of the MIT license, or under the
StrongLoop License. The text of both is included below.
MIT license
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -17,3 +23,289 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
StrongLoop License
STRONGLOOP SUBSCRIPTION AGREEMENT
PLEASE READ THIS AGREEMENT CAREFULLY BEFORE YOU AGREE TO THESE TERMS. IF YOU
ARE ACTING ON BEHALF OF AN ENTITY, THEN YOU REPRESENT THAT YOU HAVE THE
AUTHORITY TO ENTER INTO THIS AGREEMENT ON BEHALF OF THAT ENTITY. IF YOU DO NOT
AGREE TO THESE TERMS, YOU SHOULD NOT AGREE TO THE TERMS OF THIS AGREEMENT OR
INSTALL OR USE THE SOFTWARE.
This StrongLoop Subscription Agreement ("Agreement") is made by and between
StrongLoop, Inc. ("StrongLoop") with its principal place of business at 107 S.
B St, Suite 220, San Mateo, CA 94401 and the person or entity entering into this
Agreement ("Customer"). The effective date ("Effective Date") of this Agreement
is the date Customer agrees to these terms or installs or uses the Software (as
defined below). This Agreement applies to Customer's use of the Software but it
shall be superseded by any signed agreement between you and StrongLoop
concerning the Software.
1. Subscriptions and Licenses.
1.1 Subscriptions. StrongLoop offers five different subscription levels to its
customers, each as more particularly described on StrongLoop's website located
at www.strongloop.com (the "StrongLoop Site"): (1) Free; (2) Developer; (3)
Professional; (4) Gold; and (5) Platinum. The actual subscription level
applicable to Customer (the "Subscription") will be specified in the purchase
order that Customer issues to StrongLoop. This Agreement applies to Customer
regardless of the level of the Subscription selected by Customer and whether or
not Customer upgrades or downgrades its Subscription. StrongLoop hereby agrees
to provide the services as described on the StrongLoop Site for each
Subscription level during the term for which Customer has purchased the
applicable Subscription, subject to Customer paying the fees applicable to the
Subscription level purchased, if any (the "Subscription Fees"). StrongLoop may
modify the services to be provided under any Subscription upon notice to
Customer.
1.2 License Grant. Subject to the terms and conditions of this Agreement,
StrongLoop grants to Customer, during the Subscription Term (as defined in
Section 7.1 (Term and Termination) of this Agreement, a limited, non-exclusive,
non-transferable right and license, to install and use the StrongLoop Suite
software (the "Software") and the documentation made available electronically as
part of the Software (the "Documentation"), either of which may be modified
during the Term (as defined in Section 7.1 below), solely for development,
production and commercial purposes so long as Customer is using the Software to
run only one process on a given operating system at a time. This Agreement,
including but not limited to the license and restrictions contained herein,
apply to Customer regardless of whether Customer accesses the Software via
download from the StrongLoop Site or through a third-party website or service,
even if Customer acquired the Software prior to agreeing to this Agreement.
1.3 License Restrictions. Customer shall not itself, or through any parent,
subsidiary, affiliate, agent or other third party:
1.3.1 sell, lease, license, distribute, sublicense or otherwise transfer
in whole or in part, any Software or the Documentation to a third party;
or
1.3.2 decompile, disassemble, translate, reverse engineer or otherwise
attempt to derive source code from the Software, in whole or in part, nor
shall Customer use any mechanical, electronic or other method to trace,
decompile, disassemble, or identify the source code of the Software or
encourage others to do so, except to the limited extent, if any, that
applicable law permits such acts notwithstanding any contractual
prohibitions, provided, however, before Customer exercises any rights that
Customer believes to be entitled to based on mandatory law, Customer shall
provide StrongLoop with thirty (30) days prior written notice and provide
all reasonably requested information to allow StrongLoop to assess
Customer's claim and, at StrongLoop's sole discretion, to provide
alternatives that reduce any adverse impact on StrongLoop's intellectual
property or other rights; or
1.3.3 allow access or permit use of the Software by any users other than
Customer's employees or authorized third-party contractors who are
providing services to Customer and agree in writing to abide by the terms
of this Agreement, provided further that Customer shall be liable for any
failure by such employees and third-party contractors to comply with the
terms of this Agreement and no usage restrictions, if any, shall be
exceeded; or
1.3.4 create, develop, license, install, use, or deploy any third party
software or services to circumvent or provide access, permissions or
rights which violate the license keys embedded within the Software; or
1.3.5 modify or create derivative works based upon the Software or
Documentation; or disclose the results of any benchmark test of the
Software to any third party without StrongLoop's prior written approval;
or
1.3.6 change any proprietary rights notices which appear in the Software
or Documentation; or
1.3.7 use the Software as part of a time sharing or service bureau
purposes or in any other resale capacity.
1.4 Third-Party Software. The Software may include individual certain software
that is owned by third parties, including individual open source software
components (the "Third-Party Software"), each of which has its own copyright and
its own applicable license conditions. Such third-party software is licensed to
Customer under the terms of the applicable third-party licenses and/or copyright
notices that can be found in the LICENSES file, the Documentation or other
materials accompanying the Software, except that Sections 5 (Warranty
Disclaimer) and 6 (Limitation of Liability) also govern Customer's use of the
third-party software. Customer agrees to comply with the terms and conditions
of the relevant third-party software licenses.
2. Support Services. StrongLoop has no obligation to provide any support for
the Software other than the support services specifically described on the
StrongLoop Site for the Subscription level procured by Customer. However,
StrongLoop has endeavored to establish a community of users of the Software who
have provided their own feedback, hints and advice regarding their experiences
in using the Software. You can find that community and user feedback on the
StrongLoop Site. The use of any information, content or other materials from,
contained in or on the StrongLoop Site are subject to the StrongLoop website
terms of use located here http://www.strongloop.com/terms-of-service.
3. Confidentiality. For purposes of this Agreement, "Confidential Information"
means any and all information or proprietary materials (in every form and media)
not generally known in the relevant trade or industry and which has been or is
hereafter disclosed or made available by StrongLoop to Customer in connection
with the transactions contemplated under this Agreement, including (i) all trade
secrets, (ii) existing or contemplated Software, services, designs, technology,
processes, technical data, engineering, techniques, methodologies and concepts
and any related information, and (iii) information relating to business plans,
sales or marketing methods and customer lists or requirements. For a period of
five (5) years from the date of disclosure of the applicable Confidential
Information, Customer shall (i) hold the Confidential Information in trust and
confidence and avoid the disclosure or release thereof to any other person or
entity by using the same degree of care as it uses to avoid unauthorized use,
disclosure, or dissemination of its own Confidential Information of a similar
nature, but not less than reasonable care, and (ii) not use the Confidential
Information for any purpose whatsoever except as expressly contemplated under
this Agreement; provided that, to the extent the Confidential Information
constitutes a trade secret under law, Customer agrees to protect such
information for so long as it qualifies as a trade secret under applicable law.
Customer shall disclose the Confidential Information only to those of its
employees and contractors having a need to know such Confidential Information
and shall take all reasonable precautions to ensure that such employees and
contractors comply with the provisions of this Section. The obligations of
Customer under this Section shall not apply to information that Customer can
demonstrate (i) was in its possession at the time of disclosure and without
restriction as to confidentiality, (ii) at the time of disclosure is generally
available to the public or after disclosure becomes generally available to the
public through no breach of agreement or other wrongful act by Customer, (iii)
has been received from a third party without restriction on disclosure and
without breach of agreement by Customer, or (iv) is independently developed by
Customer without regard to the Confidential Information. In addition, Customer
may disclose Confidential Information as required to comply with binding orders
of governmental entities that have jurisdiction over it; provided that Customer
gives StrongLoop reasonable written notice to allow StrongLoop to seek a
protective order or other appropriate remedy, discloses only such Confidential
Information as is required by the governmental entity, and uses commercially
reasonable efforts to obtain confidential treatment for any Confidential
Information disclosed. Notwithstanding the above, Customer agrees that
StrongLoop, its employees and agents shall be free to use and employ their
general skills, know-how, and expertise, and to use, disclose, and employ any
generalized ideas, concepts, know-how, methods, techniques or skills gained or
learned during the Term or thereafter.
4. Ownership. StrongLoop shall retain all intellectual property and proprietary
rights in the Software, Documentation, and related works, including but not
limited to any derivative work of the foregoing and StrongLoop's licensors shall
retain all intellectual property and proprietary rights in any Third-Party
Software that may be provided with or as a part of the Software. Customer shall
do nothing inconsistent with StrongLoop's or its licensors' title to the
Software and the intellectual property rights embodied therein, including, but
not limited to, transferring, loaning, selling, assigning, pledging, or
otherwise disposing, encumbering, or suffering a lien or encumbrance upon or
against any interest in the Software. The Software (including any Third-Party
Software) contain copyrighted material, trade secrets and other proprietary
material of StrongLoop and/or its licensors.
5. Warranty Disclaimer. THE SOFTWARE (INCLUDING ANY THIRD-PARTY SOFTWARE) AND
DOCUMENTATION MADE AVAILABLE TO CUSTOMER ARE PROVIDED "AS-IS" AND STRONGLOOP,
ON BEHALF OF ITSELF AND ITS LICENSORS, EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, TITLE,
PERFORMANCE, AND ACCURACY AND ANY IMPLIED WARRANTIES ARISING FROM STATUTE,
COURSE OF DEALING, COURSE OF PERFORMANCE, OR USAGE OF TRADE. STRONGLOOP DOES
NOT WARRANT THAT THE OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR
ERROR-FREE, THAT DEFECTS IN THE SOFTWARE WILL BE CORRECTED OR THAT THE SOFTWARE
WILL PROVIDE OR ENSURE ANY PARTICULAR RESULTS OR OUTCOME. NO ORAL OR WRITTEN
INFORMATION OR ADVICE GIVEN BY STRONGLOOP OR ITS AUTHORIZED REPRESENTATIVES
SHALL CREATE A WARRANTY OR IN ANY WAY INCREASE THE SCOPE OF THIS WARRANTY.
STRONGLOOP IS NOT OBLIGATED TO PROVIDE CUSTOMER WITH UPGRADES TO THE SOFTWARE,
BUT MAY ELECT TO DO SO IN ITS SOLE DISCRETION. SOME JURISDICTIONS DO NOT ALLOW
THE EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT APPLY TO
CUSTOMER.WITHOUT LIMITING THE GENERALITY OF THE FOREGOING DISCLAIMER, THE
SOFTWARE AND DOCUMENTATION ARE NOT DESIGNED, MANUFACTURED OR INTENDED FOR USE IN
THE PLANNING, CONSTRUCTION, MAINTENANCE, CONTROL, OR DIRECT OPERATION OF NUCLEAR
FACILITIES, AIRCRAFT NAVIGATION, CONTROL OR COMMUNICATION SYSTEMS, WEAPONS
SYSTEMS, OR DIRECT LIFE SUPPORT SYSTEMS.
6. Limitation of Liability.
6.1 Exclusion of Liability. IN NO EVENT WILL STRONGLOOP OR ITS LICENSORS
BE LIABLE UNDER THIS AGREEMENT FOR ANY INDIRECT, RELIANCE, PUNITIVE,
CONSEQUENTIAL, SPECIAL, EXEMPLARY, OR INCIDENTAL DAMAGES OF ANY KIND AND
HOWEVER CAUSED (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF
BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION AND
THE LIKE), EVEN IF STRONGLOOP HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES. CUSTOMER BEARS FULL RESPONSIBILITY FOR USE OF THE SOFTWARE AND
THE SUBSCRIPTION AND STRONGLOOP DOES NOT GUARANTEE THAT THE USE OF THE
SOFTWARE AND SUBSCRIPTION WILL ENSURE THAT CUSTOMER'S NETWORK WILL BE
AVAILABLE, SECURE, MONITORED OR PROTECTED AGAINST ANY DOWNTIME, DENIAL OF
SERVICE ATTACKS, SECUITY BREACHES, HACKERS AND THE LIKE. IN NO EVENT WILL
STRONGLOOP'S CUMULATIVE LIABILITY FOR ANY DAMAGES, LOSSES AND CAUSES OF
ACTION (WHETHER IN CONTRACT, TORT, INCLUDING NEGLIGENCE, OR OTHERWISE)
ARISING OUT OF OR RELATED TO THIS AGREEMENT EXCEED THE GREATER OF ONE
HUNDRED DOLLARS (US$100) OR THE TOTAL SUBSCRIPTION FEES PAID BY CUSTOMER
TO STRONGLOOP IN THE TWELVE (12) MONTHS PRECEDING THE DATE THE CLAIM
ARISES.
6.2 Limitation of Damages. IN NO EVENT WILL STRONGLOOP'S LICENSORS HAVE
ANY LIABILITY FOR ANY CLAIM ARISING IN CONNECTION WITH THIS AGREEMENT.
THE PROVISIONS OF THIS SECTION 6 ALLOCATE RISKS UNDER THIS AGREEMENT
BETWEEN CUSTOMER, STRONGLOOP AND STRONGLOOP'S SUPPLIERS. THE FOREGOING
LIMITATIONS, EXCLUSIONS AND DISCLAIMERS APPLY TO THE MAXIMUM EXTENT
PERMITTED BY APPLICABLE LAW, EVEN IF ANY REMEDY FAILS IN ITS ESSENTIAL
PURPOSE.
6.3 Failure of Essential Purpose. THE PARTIES AGREE THAT THESE
LIMITATIONS SHALL APPLY EVEN IF THIS AGREEMENT OR ANY LIMITED REMEDY
SPECIFIED HEREIN IS FOUND TO HAVE FAILED OF ITS ESSENTIAL PURPOSE.
6.4 Allocation of Risk. The sections on limitation of liability and
disclaimer of warranties allocate the risks in the Agreement between the
parties. This allocation is an essential element of the basis of the
bargain between the parties.
7. Term and Termination.
7.1 This Agreement shall commence on the Effective Date and continue for so long
as Customer has a valid Subscription and is current on the payment of any
Subscription Fees required to be paid for that Subscription (the "Subscription
Term"). Either party may terminate this Agreement immediately upon written
notice to the other party, and the Subscription and licenses granted hereunder
automatically terminate upon the termination of this Agreement. This Agreement
will terminate immediately without notice from StrongLoop if Customer fails to
comply with or otherwise breaches any provision of this Agreement.
7.2 All Sections other than Section 1.1 (Subscriptions) and 1.2 (Licenses) shall
survive the expiration or termination of this Agreement.
8. Subscription Fees and Payments. StrongLoop, Customer agrees to pay
StrongLoop the Subscription Fees as described on the StrongLoop Site for the
Subscription purchased unless a different amount has been agreed to in a
separate agreement between Customer and StrongLoop. In addition, Customer shall
pay all sales, use, value added, withholding, excise taxes and other tax, duty,
custom and similar fees levied upon the delivery or use of the Software and the
Subscriptions described in this Agreement. Fees shall be invoiced in full upon
StrongLoop's acceptance of Customer's purchase order for the Subscription. All
invoices shall be paid in US dollars and are due upon receipt and shall be paid
within thirty (30) days. Payments shall be made without right of set-off or
chargeback. If Customer does not pay the invoices when due, StrongLoop may
charge interest at one percent (1%) per month or the highest rate permitted by
law, whichever is lower, on the unpaid balance from the original due date. If
Customer fails to pay fees in accordance with this Section, StrongLoop may
suspend fulfilling its obligations under this Agreement (including but not
limited to suspending the services under the Subscription) until payment is
received by StrongLoop. If any applicable law requires Customer to withhold
amounts from any payments to StrongLoop under this Agreement, (a) Customer shall
effect such withholding, remit such amounts to the appropriate taxing
authorities and promptly furnish StrongLoop with tax receipts evidencing the
payments of such amounts and (b) the sum payable by Customer upon which the
deduction or withholding is based shall be increased to the extent necessary to
ensure that, after such deduction or withholding, StrongLoop receives and
retains, free from liability for such deduction or withholding, a net amount
equal to the amount StrongLoop would have received and retained absent the
required deduction or withholding.
9. General.
9.1 Compliance with Laws. Customer shall abide by all local, state, federal and
international laws, rules, regulations and orders applying to Customer's use of
the Software, including, without limitation, the laws and regulations of the
United States that may restrict the export and re-export of certain commodities
and technical data of United States origin, including the Software. Customer
agrees that it will not export or re-export the Software without the appropriate
United States or foreign government licenses.
9.2 Entire Agreement. This Agreement constitutes the entire agreement between
the parties concerning the subject matter hereof. This Agreement supersedes all
prior or contemporaneous discussions, proposals and agreements between the
parties relating to the subject matter hereof. No amendment, modification or
waiver of any provision of this Agreement shall be effective unless in writing
and signed by both parties. Any additional or different terms on any purchase
orders issued by Customer to StrongLoop shall not be binding on either party,
are hereby rejected by StrongLoop and void.
9.3 Severability. If any provision of this Agreement is held to be invalid or
unenforceable, the remaining portions shall remain in full force and effect and
such provision shall be enforced to the maximum extent possible so as to effect
the intent of the parties and shall be reformed to the extent necessary to make
such provision valid and enforceable.
9.4 Waiver. No waiver of rights by either party may be implied from any actions
or failures to enforce rights under this Agreement.
9.5 Force Majeure. Neither party shall be liable to the other for any delay or
failure to perform due to causes beyond its reasonable control (excluding
payment of monies due).
9.6 No Third Party Beneficiaries. Unless otherwise specifically stated, the
terms of this Agreement are intended to be and are solely for the benefit of
StrongLoop and Customer and do not create any right in favor of any third party.
9.7 Governing Law and Jurisdiction. This Agreement shall be governed by the
laws of the State of California, without reference to the principles of
conflicts of law. The provisions of the Uniform Computerized Information
Transaction Act and United Nations Convention on Contracts for the International
Sale of Goods shall not apply to this Agreement. The parties shall attempt to
resolve any dispute related to this Agreement informally, initially through
their respective management, and then by non-binding mediation in San Francisco
County, California. Any litigation related to this Agreement shall be brought
in the state or federal courts located in San Francisco County, California, and
only in those courts and each party irrevocably waives any objections to such
venue.
9.8 Notices. All notices must be in writing and shall be effective three (3)
days after the date sent to the other party's headquarters, Attention Chief
Financial Officer.

331
README.md
View File

@ -1,6 +1,8 @@
## loopback-connector-mysql ## loopback-connector-mysql
`loopback-connector-mysql` is the MySQL connector module for [loopback-datasource-juggler](http://docs.strongloop.com/loopback-datasource-juggler/). `loopback-connector-mysql` is the MySQL connector module for [loopback-datasource-juggler](https://github.com/strongloop/loopback-datasource-juggler/).
For complete documentation, see [StrongLoop Documentation | MySQL Connector](http://docs.strongloop.com/display/DOC/MySQL+connector).
## Installation ## Installation
@ -8,7 +10,7 @@
npm install loopback-connector-mysql --save npm install loopback-connector-mysql --save
```` ````
## Usage ## Basic use
To use it you need `loopback-datasource-juggler`. To use it you need `loopback-datasource-juggler`.
@ -42,328 +44,3 @@ To use it you need `loopback-datasource-juggler`.
to `utf8_general_ci`. The `collation` value will also be used to derive the to `utf8_general_ci`. The `collation` value will also be used to derive the
connection charset. connection charset.
## Data type mappings
`loopback-connector-mysql` uses the following rules to map between JSON types and MySQL data types.
### JSON to MySQL types
- String/JSON: VARCHAR
- Text: TEXT
- Number: INT
- Date: DATETIME
- BOOLEAN: TINYINT(1)
- Point/GeoPoint: POINT
- Enum: ENUM
### MySQL to JSON types
- CHAR: String
- CHAR(1): Boolean
- VARCHAR/TINYTEXT/MEDIUMTEXT/LONGTEXT/TEXT/ENUM/SET: String
- TINYBLOB/MEDIUMBLOB/LONGBLOB/BLOB/BINARY/VARBINARY/BIT: Binary
- TINYINT/SMALLINT/INT/MEDIUMINT/YEAR/FLOAT/DOUBLE/NUMERIC/DECIMAL: Number
- DATE/TIMESTAMP/DATETIME: Date
## Using the `dataType` field/column option with MySQL
`loopback-connector-mysql` allows mapping of LoopBack model properties to MYSQL columns using the 'mysql' property of the
property definition. For example,
"locationId":{
"type":"String",
"required":true,
"length":20,
"mysql":
{
"columnName":"LOCATION_ID",
"dataType":"VARCHAR2",
"dataLength":20,
"nullable":"N"
}
}
`loopback-connector-mysql` also supports using the `dataType` column/property attribute to specify what MySQL column
type is used for many loopback-datasource-juggler types.
The following type-dataType combinations are supported:
- Number
- integer
- tinyint
- smallint
- mediumint
- int
- bigint
Use the `limit` option to alter the display width.
Example:
`{ count : { type: Number, dataType: 'smallInt' }}`
- floating point types
- float
- double
Use the `precision` and `scale` options to specify custom precision. Default is (16,8).
Example:
`{ average : { type: Number, dataType: 'float', precision: 20, scale: 4 }}`
- fixed-point exact value types
- decimal
- numeric
Use the `precision` and `scale` options to specify custom precision. Default is (9,2).
These aren't likely to function as true fixed-point.
Example:
`{ stdDev : { type: Number, dataType: 'decimal', precision: 12, scale: 8 }}`
- String / DataSource.Text / DataSource.JSON
- varchar
- char
- text
- mediumtext
- tinytext
- longtext
Example:
`{ userName : { type: String, dataType: 'char', limit: 24 }}`
Example:
`{ biography : { type: String, dataType: 'longtext' }}`
- Date
- datetime
- timestamp
Example:
`{ startTime : { type: Date, dataType: 'timestamp' }}`
* Enum
Enums are special.
Create an Enum using Enum factory:
```javascript
var MOOD = dataSource.EnumFactory('glad', 'sad', 'mad');
MOOD.SAD; // 'sad'
MOOD(2); // 'sad'
MOOD('SAD'); // 'sad'
MOOD('sad'); // 'sad'
```
- `{ mood: { type: MOOD }}`
- `{ choice: { type: dataSource.EnumFactory('yes', 'no', 'maybe'), null: false }}`
## Discovering Models
MySQL data sources allow you to discover model definition information from existing mysql databases. See the following APIs:
- [dataSource.discoverModelDefinitions([owner], fn)](https://github.com/strongloop/loopback#datasourcediscovermodeldefinitionsusername-fn)
- [dataSource.discoverSchema([owner], name, fn)](https://github.com/strongloop/loopback#datasourcediscoverschemaowner-name-fn)
### Asynchronous APIs for discovery
* MySQL.prototype.discoverModelDefinitions = function (options, cb)
- options:
- all: {Boolean} To include tables/views from all schemas/owners
- owner/schema: {String} The schema/owner name
- views: {Boolean} To include views
- cb:
- Get a list of table/view names, for example:
{type: 'table', name: 'INVENTORY', owner: 'STRONGLOOP' }
{type: 'table', name: 'LOCATION', owner: 'STRONGLOOP' }
{type: 'view', name: 'INVENTORY_VIEW', owner: 'STRONGLOOP' }
* MySQL.prototype.discoverModelProperties = function (table, options, cb)
- table: {String} The name of a table or view
- options:
- owner/schema: {String} The schema/owner name
- cb:
- Get a list of model property definitions, for example:
{ owner: 'STRONGLOOP',
tableName: 'PRODUCT',
columnName: 'ID',
dataType: 'VARCHAR2',
dataLength: 20,
nullable: 'N',
type: 'String' }
{ owner: 'STRONGLOOP',
tableName: 'PRODUCT',
columnName: 'NAME',
dataType: 'VARCHAR2',
dataLength: 64,
nullable: 'Y',
type: 'String' }
* MySQL.prototype.discoverPrimaryKeys= function(table, options, cb)
- table: {String} The name of a table or view
- options:
- owner/schema: {String} The schema/owner name
- cb:
- Get a list of primary key definitions, for example:
{ owner: 'STRONGLOOP',
tableName: 'INVENTORY',
columnName: 'PRODUCT_ID',
keySeq: 1,
pkName: 'ID_PK' }
{ owner: 'STRONGLOOP',
tableName: 'INVENTORY',
columnName: 'LOCATION_ID',
keySeq: 2,
pkName: 'ID_PK' }
* MySQL.prototype.discoverForeignKeys= function(table, options, cb)
- table: {String} The name of a table or view
- options:
- owner/schema: {String} The schema/owner name
- cb:
- Get a list of foreign key definitions, for example:
{ fkOwner: 'STRONGLOOP',
fkName: 'PRODUCT_FK',
fkTableName: 'INVENTORY',
fkColumnName: 'PRODUCT_ID',
keySeq: 1,
pkOwner: 'STRONGLOOP',
pkName: 'PRODUCT_PK',
pkTableName: 'PRODUCT',
pkColumnName: 'ID' }
* MySQL.prototype.discoverExportedForeignKeys= function(table, options, cb)
- table: {String} The name of a table or view
- options:
- owner/schema: {String} The schema/owner name
- cb:
- Get a list of foreign key definitions that reference the primary key of the given table, for example:
{ fkName: 'PRODUCT_FK',
fkOwner: 'STRONGLOOP',
fkTableName: 'INVENTORY',
fkColumnName: 'PRODUCT_ID',
keySeq: 1,
pkName: 'PRODUCT_PK',
pkOwner: 'STRONGLOOP',
pkTableName: 'PRODUCT',
pkColumnName: 'ID' }
### Discover/build/try the models
#### Build a LDL schema by discovery
Data sources backed by the MySQL connector can discover LDL models from the database using the `discoverSchema` API. For
example,
dataSource.discoverSchema('INVENTORY', {owner: 'STRONGLOOP'}, function (err, schema) {
...
}
Here is the sample result. Please note there are 'mysql' properties in addition to the regular LDL model options and
properties. The 'mysql' objects contain the MySQL specific mappings.
{
"name":"Inventory",
"options":{
"idInjection":false,
"mysql":{
"schema":"STRONGLOOP",
"table":"INVENTORY"
}
},
"properties":{
"productId":{
"type":"String",
"required":false,
"length":60,
"precision":null,
"scale":null,
"id":1,
"mysql":{
"columnName":"PRODUCT_ID",
"dataType":"varchar",
"dataLength":60,
"dataPrecision":null,
"dataScale":null,
"nullable":"NO"
}
},
"locationId":{
"type":"String",
"required":false,
"length":60,
"precision":null,
"scale":null,
"id":2,
"mysql":{
"columnName":"LOCATION_ID",
"dataType":"varchar",
"dataLength":60,
"dataPrecision":null,
"dataScale":null,
"nullable":"NO"
}
},
"available":{
"type":"Number",
"required":false,
"length":null,
"precision":10,
"scale":0,
"mysql":{
"columnName":"AVAILABLE",
"dataType":"int",
"dataLength":null,
"dataPrecision":10,
"dataScale":0,
"nullable":"YES"
}
},
"total":{
"type":"Number",
"required":false,
"length":null,
"precision":10,
"scale":0,
"mysql":{
"columnName":"TOTAL",
"dataType":"int",
"dataLength":null,
"dataPrecision":10,
"dataScale":0,
"nullable":"YES"
}
}
}
}
We can also discover and build model classes in one shot. The following example uses `discoverAndBuildModels` to discover,
build and try the models:
dataSource.discoverAndBuildModels('INVENTORY', { owner: 'STRONGLOOP', visited: {}, associations: true},
function (err, models) {
// Show records from the models
for(var m in models) {
models[m].all(show);
};
// Find one record for inventory
models.Inventory.findOne({}, function(err, inv) {
console.log("\nInventory: ", inv);
// Follow the foreign key to navigate to the product
inv.product(function(err, prod) {
console.log("\nProduct: ", prod);
console.log("\n ------------- ");
});
});
}

View File

@ -1,8 +1,14 @@
{ {
"content": [ "content": [
{"title": "LoopBack MySQL Connector API", "depth": 2}, {
"title": "LoopBack MySQL Connector API",
"depth": 2
},
"lib/mysql.js", "lib/mysql.js",
{"title": "MySQL Discovery API", "depth": 2}, {
"title": "MySQL Discovery API",
"depth": 2
},
"lib/discovery.js" "lib/discovery.js"
], ],
"codeSectionDepth": 3 "codeSectionDepth": 3

View File

@ -17,7 +17,6 @@ function show(err, models) {
} }
} }
ds.discoverModelDefinitions({views: true, limit: 20}, show); ds.discoverModelDefinitions({views: true, limit: 20}, show);
ds.discoverModelProperties('customer', show); ds.discoverModelProperties('customer', show);
@ -29,7 +28,6 @@ ds.discoverForeignKeys('inventory', show);
ds.discoverExportedForeignKeys('location', show); ds.discoverExportedForeignKeys('location', show);
ds.discoverAndBuildModels('weapon', {owner: 'strongloop', visited: {}, associations: true}, function (err, models) { ds.discoverAndBuildModels('weapon', {owner: 'strongloop', visited: {}, associations: true}, function (err, models) {
for (var m in models) { for (var m in models) {

View File

@ -35,7 +35,7 @@ function mixinDiscovery(MySQL) {
+ ' FROM information_schema.tables WHERE table_schema=\'' + owner + '\'', 'table_schema, table_name', options); + ' FROM information_schema.tables WHERE table_schema=\'' + owner + '\'', 'table_schema, table_name', options);
} else { } else {
sqlTables = paginateSQL('SELECT \'table\' AS "type", table_name AS "name",' sqlTables = paginateSQL('SELECT \'table\' AS "type", table_name AS "name",'
+ ' table_schema AS "owner" FROM information_schema.tables', + ' table_schema AS "owner" FROM information_schema.tables WHERE table_schema=SUBSTRING_INDEX(USER(),\'@\',1)',
'table_name', options); 'table_name', options);
} }
return sqlTables; return sqlTables;
@ -348,6 +348,8 @@ function mixinDiscovery(MySQL) {
case 'TIMESTAMP': case 'TIMESTAMP':
case 'DATETIME': case 'DATETIME':
return 'Date'; return 'Date';
case 'POINT':
return 'GeoPoint';
default: default:
return 'String'; return 'String';
} }

View File

@ -6,6 +6,8 @@ var mysql = require('mysql');
var juggler = require('loopback-datasource-juggler'); var juggler = require('loopback-datasource-juggler');
var EnumFactory = require('./enumFactory').EnumFactory; var EnumFactory = require('./enumFactory').EnumFactory;
var debug = require('debug')('loopback:connector:mysql');
/** /**
* @module loopback-connector-mysql * @module loopback-connector-mysql
* *
@ -41,7 +43,6 @@ exports.initialize = function initializeDataSource(dataSource, callback) {
user: s.username || s.user, user: s.username || s.user,
password: s.password, password: s.password,
timezone: s.timezone, timezone: s.timezone,
debug: s.debug,
socketPath: s.socketPath, socketPath: s.socketPath,
charset: s.collation.toUpperCase(), // Correct by docs despite seeming odd. charset: s.collation.toUpperCase(), // Correct by docs despite seeming odd.
supportBigNumbers: s.supportBigNumbers, supportBigNumbers: s.supportBigNumbers,
@ -61,8 +62,8 @@ exports.initialize = function initializeDataSource(dataSource, callback) {
dataSource.connecting = false; dataSource.connecting = false;
}); });
if (s.debug) { if (debug.enabled) {
console.log('Settings: ', s); debug('Settings: %j', s);
} }
dataSource.connector = new MySQL(dataSource.client, s); dataSource.connector = new MySQL(dataSource.client, s);
@ -110,12 +111,12 @@ MySQL.prototype.query = function (sql, callback) {
} }
var client = this.client; var client = this.client;
var time = Date.now(); var time = Date.now();
var debug = this.settings.debug; var debugEnabled = debug.enabled;
var db = this.settings.database; var db = this.settings.database;
var log = this.log; var log = this.log;
if (typeof callback !== 'function') throw new Error('callback should be a function'); if (typeof callback !== 'function') throw new Error('callback should be a function');
if (debug) { if (debugEnabled) {
console.log('SQL:', sql); debug('SQL: %s', sql);
} }
function releaseConnectionAndCallback(connection, err, result) { function releaseConnectionAndCallback(connection, err, result) {
@ -125,13 +126,15 @@ MySQL.prototype.query = function (sql, callback) {
function runQuery(connection) { function runQuery(connection) {
connection.query(sql, function (err, data) { connection.query(sql, function (err, data) {
if (debug) { if (debugEnabled) {
if (err) { if (err) {
console.error('Error: ', err); console.error('Error: ', err);
} }
console.log('Data:', data); debug('Data: ', data);
}
if (log) {
log(sql, time);
} }
if (log) log(sql, time);
releaseConnectionAndCallback(connection, err, data); releaseConnectionAndCallback(connection, err, data);
}); });
} }
@ -173,7 +176,6 @@ MySQL.prototype.query = function (sql, callback) {
}); });
}; };
/** /**
* Create the data model in MySQL * Create the data model in MySQL
* *
@ -216,9 +218,13 @@ MySQL.prototype.updateOrCreate = function (model, data, callback) {
} else { } else {
v = data[key]; v = data[key];
} }
if (v !== undefined) {
fieldsNames.push(k); fieldsNames.push(k);
fieldValues.push(v); fieldValues.push(v);
if (!mysql.id(model, key)) combined.push(k + ' = ' + v); if (!mysql.id(model, key)) {
combined.push(k + ' = ' + v);
}
}
} }
}); });
@ -270,7 +276,7 @@ function dateToMysql(val) {
*/ */
MySQL.prototype.toDatabase = function (prop, val) { MySQL.prototype.toDatabase = function (prop, val) {
if (val === null) return 'NULL'; if (val === null) return 'NULL';
if (val === undefined) return; if (val === undefined) return 'NULL';
if (val.constructor.name === 'Object') { if (val.constructor.name === 'Object') {
var operator = Object.keys(val)[0] var operator = Object.keys(val)[0]
val = val[operator]; val = val[operator];
@ -611,7 +617,7 @@ MySQL.prototype.isActual = function (cb) {
function done(err, needAlter) { function done(err, needAlter) {
if (err) { if (err) {
console.log(err); debug(err);
} }
ok = ok || needAlter; ok = ok || needAlter;
if (--wait === 0 && cb) { if (--wait === 0 && cb) {
@ -790,7 +796,13 @@ MySQL.prototype.propertiesSQL = function (model) {
var sql = []; var sql = [];
if (pks.length === 1) { if (pks.length === 1) {
var idName = this.idName(model); var idName = this.idName(model);
var idProp = this._models[model].properties[idName];
if(idProp.generated) {
sql.push(self.columnEscaped(model, idName) + ' INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY'); sql.push(self.columnEscaped(model, idName) + ' INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY');
} else {
idProp.nullable = false;
sql.push(self.columnEscaped(model, idName) + ' ' + self.propertySettingsSQL(model, idName) + ' PRIMARY KEY');
}
} }
Object.keys(this._models[model].properties).forEach(function (prop) { Object.keys(this._models[model].properties).forEach(function (prop) {
if (self.id(model, prop) && pks.length === 1) { if (self.id(model, prop) && pks.length === 1) {
@ -1083,7 +1095,7 @@ function unsigned(p, dt) {
*/ */
MySQL.prototype.disconnect = function () { MySQL.prototype.disconnect = function () {
if (this.debug) { if (this.debug) {
console.log('disconnect'); debug('disconnect');
} }
if (this.client) { if (this.client) {
this.client.end(); this.client.end();

View File

@ -1,27 +1,28 @@
{ {
"name": "loopback-connector-mysql", "name": "loopback-connector-mysql",
"version": "1.1.1", "version": "1.2.0",
"description": "MySQL connector for loopback-datasource-juggler", "description": "MySQL connector for loopback-datasource-juggler",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"test": "make test" "test": "mocha"
}, },
"dependencies": { "dependencies": {
"mysql": "~2.0.0-rc2", "mysql": "~2.1.1",
"async": "~0.2.9" "async": "~0.7.0",
}, "debug": "~0.8.0"
"devDependencies": {
"loopback-datasource-juggler": "1.x.x"
}, },
"devDependencies": { "devDependencies": {
"loopback-datasource-juggler": "1.x.x", "loopback-datasource-juggler": "1.x.x",
"should": "~1.3.0", "should": "~1.3.0",
"mocha": "~1.14.0", "mocha": "~1.18.0",
"rc": "~0.3.1" "rc": "~0.3.1"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/strongloop/loopback-connector-mysql.git" "url": "https://github.com/strongloop/loopback-connector-mysql.git"
}, },
"license": "MIT" "license": {
"name": "Dual MIT/StrongLoop",
"url": "https://github.com/strongloop/loopback-connector-mysql/blob/master/LICENSE"
}
} }

View File

@ -12,7 +12,6 @@ describe('migrations', function() {
db = odb; db = odb;
}); });
it('should use utf8 charset', function (done) { it('should use utf8 charset', function (done) {
var test_set = /utf8/; var test_set = /utf8/;
@ -49,8 +48,6 @@ describe('migrations', function() {
}); });
}); });
function charsetTest(test_set, test_collo, test_set_str, test_set_collo, done) { function charsetTest(test_set, test_collo, test_set_str, test_set_collo, done) {
query('DROP DATABASE IF EXISTS ' + odb.settings.database, function (err) { query('DROP DATABASE IF EXISTS ' + odb.settings.database, function (err) {

View File

@ -75,8 +75,7 @@ describe('migrations', function() {
// Note: getIndexes truncates multi-key indexes to the first member. Hence index1 is correct. // Note: getIndexes truncates multi-key indexes to the first member. Hence index1 is correct.
getIndexes('UserData', function (err, fields) { getIndexes('UserData', function (err, fields) {
// console.log('....', fields); // console.log('....', fields);
assert.deepEqual(fields, { PRIMARY: assert.deepEqual(fields, { PRIMARY: { Table: 'UserData',
{ Table: 'UserData',
Non_unique: 0, Non_unique: 0,
Key_name: 'PRIMARY', Key_name: 'PRIMARY',
Seq_in_index: 1, Seq_in_index: 1,
@ -88,8 +87,7 @@ describe('migrations', function() {
Null: '', Null: '',
Index_type: 'BTREE', Index_type: 'BTREE',
Comment: '' }, Comment: '' },
email: email: { Table: 'UserData',
{ Table: 'UserData',
Non_unique: 1, Non_unique: 1,
Key_name: 'email', Key_name: 'email',
Seq_in_index: 1, Seq_in_index: 1,
@ -101,8 +99,7 @@ describe('migrations', function() {
Null: '', Null: '',
Index_type: 'BTREE', Index_type: 'BTREE',
Comment: '' }, Comment: '' },
index0: index0: { Table: 'UserData',
{ Table: 'UserData',
Non_unique: 1, Non_unique: 1,
Key_name: 'index0', Key_name: 'index0',
Seq_in_index: 1, Seq_in_index: 1,
@ -121,43 +118,38 @@ describe('migrations', function() {
it('StringData should have correct columns', function (done) { it('StringData should have correct columns', function (done) {
getFields('StringData', function (err, fields) { getFields('StringData', function (err, fields) {
assert.deepEqual(fields, { id: assert.deepEqual(fields, {
{ Field: 'id', idString: { Field: "idString",
Type: 'int(11)', Type: 'varchar(255)',
Null: 'NO', Null: 'NO',
Key: 'PRI', Key: 'PRI',
Default: null, Default: null,
Extra: 'auto_increment' }, Extra: ''},
smallString: smallString: { Field: 'smallString',
{ Field: 'smallString',
Type: 'char(127)', Type: 'char(127)',
Null: 'NO', Null: 'NO',
Key: 'MUL', Key: 'MUL',
Default: null, Default: null,
Extra: '' }, Extra: '' },
mediumString: mediumString: { Field: 'mediumString',
{ Field: 'mediumString',
Type: 'varchar(255)', Type: 'varchar(255)',
Null: 'NO', Null: 'NO',
Key: '', Key: '',
Default: null, Default: null,
Extra: '' }, Extra: '' },
tinyText: tinyText: { Field: 'tinyText',
{ Field: 'tinyText',
Type: 'tinytext', Type: 'tinytext',
Null: 'YES', Null: 'YES',
Key: '', Key: '',
Default: null, Default: null,
Extra: '' }, Extra: '' },
giantJSON: giantJSON: { Field: 'giantJSON',
{ Field: 'giantJSON',
Type: 'longtext', Type: 'longtext',
Null: 'YES', Null: 'YES',
Key: '', Key: '',
Default: null, Default: null,
Extra: '' }, Extra: '' },
text: text: { Field: 'text',
{ Field: 'text',
Type: 'varchar(1024)', Type: 'varchar(1024)',
Null: 'YES', Null: 'YES',
Key: '', Key: '',
@ -171,36 +163,31 @@ describe('migrations', function() {
it('NumberData should have correct columns', function (done) { it('NumberData should have correct columns', function (done) {
getFields('NumberData', function (err, fields) { getFields('NumberData', function (err, fields) {
assert.deepEqual(fields, { assert.deepEqual(fields, {
id: id: { Field: 'id',
{ Field: 'id',
Type: 'int(11)', Type: 'int(11)',
Null: 'NO', Null: 'NO',
Key: 'PRI', Key: 'PRI',
Default: null, Default: null,
Extra: 'auto_increment' }, Extra: 'auto_increment' },
number: number: { Field: 'number',
{ Field: 'number',
Type: 'decimal(10,3) unsigned', Type: 'decimal(10,3) unsigned',
Null: 'NO', Null: 'NO',
Key: 'MUL', Key: 'MUL',
Default: null, Default: null,
Extra: '' }, Extra: '' },
tinyInt: tinyInt: { Field: 'tinyInt',
{ Field: 'tinyInt',
Type: 'tinyint(2)', Type: 'tinyint(2)',
Null: 'YES', Null: 'YES',
Key: '', Key: '',
Default: null, Default: null,
Extra: '' }, Extra: '' },
mediumInt: mediumInt: { Field: 'mediumInt',
{ Field: 'mediumInt',
Type: 'mediumint(8) unsigned', Type: 'mediumint(8) unsigned',
Null: 'YES', Null: 'YES',
Key: '', Key: '',
Default: null, Default: null,
Extra: '' }, Extra: '' },
floater: floater: { Field: 'floater',
{ Field: 'floater',
Type: 'double(14,6)', Type: 'double(14,6)',
Null: 'YES', Null: 'YES',
Key: '', Key: '',
@ -214,22 +201,19 @@ describe('migrations', function() {
it('DateData should have correct columns', function (done) { it('DateData should have correct columns', function (done) {
getFields('DateData', function (err, fields) { getFields('DateData', function (err, fields) {
assert.deepEqual(fields, { assert.deepEqual(fields, {
id: id: { Field: 'id',
{ Field: 'id',
Type: 'int(11)', Type: 'int(11)',
Null: 'NO', Null: 'NO',
Key: 'PRI', Key: 'PRI',
Default: null, Default: null,
Extra: 'auto_increment' }, Extra: 'auto_increment' },
dateTime: dateTime: { Field: 'dateTime',
{ Field: 'dateTime',
Type: 'datetime', Type: 'datetime',
Null: 'YES', Null: 'YES',
Key: '', Key: '',
Default: null, Default: null,
Extra: '' }, Extra: '' },
timestamp: timestamp: { Field: 'timestamp',
{ Field: 'timestamp',
Type: 'timestamp', Type: 'timestamp',
Null: 'YES', Null: 'YES',
Key: '', Key: '',
@ -240,7 +224,7 @@ describe('migrations', function() {
}); });
}); });
it('should autoupgrade', function(done) { it('should autoupdate', function (done) {
var userExists = function (cb) { var userExists = function (cb) {
query('SELECT * FROM UserData', function (err, res) { query('SELECT * FROM UserData', function (err, res) {
cb(!err && res[0].email == 'test@example.com'); cb(!err && res[0].email == 'test@example.com');
@ -323,7 +307,7 @@ describe('migrations', function() {
it('should disconnect when done', function (done) { it('should disconnect when done', function (done) {
db.disconnect(); db.disconnect();
done() done();
}); });
}); });
@ -349,6 +333,7 @@ function setup(done) {
}); });
StringData = db.define('StringData', { StringData = db.define('StringData', {
idString: {type: String, id: true},
smallString: {type: String, null: false, index: true, dataType: 'char', limit: 127}, smallString: {type: String, null: false, index: true, dataType: 'char', limit: 127},
mediumString: {type: String, null: false, dataType: 'varchar', limit: 255}, mediumString: {type: String, null: false, dataType: 'varchar', limit: 255},
tinyText: {type: String, dataType: 'tinyText'}, tinyText: {type: String, dataType: 'tinyText'},

2
test/mocha.opts Normal file
View File

@ -0,0 +1,2 @@
--globals getSchema
--timeout 15000

View File

@ -3,10 +3,10 @@ require('should');
var assert = require('assert'); var assert = require('assert');
var DataSource = require('loopback-datasource-juggler').DataSource; var DataSource = require('loopback-datasource-juggler').DataSource;
var db; var db, config;
before(function () { before(function () {
var config = require('rc')('loopback', {dev: {mysql: {}}}).dev.mysql; config = require('rc')('loopback', {dev: {mysql: {}}}).dev.mysql;
config.database = 'STRONGLOOP'; config.database = 'STRONGLOOP';
db = new DataSource(require('../'), config); db = new DataSource(require('../'), config);
}); });
@ -37,6 +37,26 @@ describe('discoverModels', function() {
}); });
}); });
describe('Discover current user\'s tables', function () {
it('should return an array of tables for the current user', function (done) {
db.discoverModelDefinitions({
limit: 3
}, function (err, models) {
if (err) {
console.error(err);
done(err);
} else {
var views = false;
models.forEach(function (m) {
assert.equal(m.owner, config.username);
});
done(null, models);
}
});
});
});
describe('Discover models excluding views', function () { describe('Discover models excluding views', function () {
it('should return an array of only tables', function (done) { it('should return an array of only tables', function (done) {