Merge pull request #56 from thevahidal/api-examples-doc-rows
Api examples doc rows
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "soul-cli",
|
||||
"version": "0.0.6",
|
||||
"version": "0.0.7",
|
||||
"description": "A SQLite RESTful server",
|
||||
"main": "src/server.js",
|
||||
"bin": {
|
||||
|
||||
@@ -34,8 +34,12 @@ const listTableRows = async (req, res) => {
|
||||
description: 'Extend rows. e.g. ?_extend=user_id will return user data for each row.',
|
||||
in: 'query',
|
||||
}
|
||||
#swagger.parameters['_filters'] = {
|
||||
description: 'Filter rows. e.g. ?_filters=name:John,age:20 will return rows where name is John and age is 20.',
|
||||
in: 'query',
|
||||
}
|
||||
*/
|
||||
const { name } = req.params;
|
||||
const { name: tableName } = req.params;
|
||||
const {
|
||||
_page = 1,
|
||||
_limit = 10,
|
||||
@@ -43,41 +47,48 @@ const listTableRows = async (req, res) => {
|
||||
_ordering,
|
||||
_schema,
|
||||
_extend,
|
||||
...filters
|
||||
_filters = '',
|
||||
} = req.query;
|
||||
|
||||
const page = parseInt(_page);
|
||||
const limit = parseInt(_limit);
|
||||
|
||||
// if filters are provided, filter rows by them
|
||||
// filters consists of fields to filter by
|
||||
// filtering must be case insensitive
|
||||
// e.g. ?name=John&age=20
|
||||
// if _filters are provided, filter rows by them
|
||||
// _filters consists of fields to filter by
|
||||
// filtering is case insensitive
|
||||
// e.g. ?_filters=name:John,age:20
|
||||
// will filter by name like '%John%' and age like '%20%'
|
||||
|
||||
const filters = _filters.split(',').map((filter) => {
|
||||
const [field, value] = filter.split(':');
|
||||
return { field, value };
|
||||
});
|
||||
|
||||
let whereString = '';
|
||||
if (Object.keys(filters).length > 0) {
|
||||
if (_filters !== '') {
|
||||
whereString += ' WHERE ';
|
||||
whereString += Object.keys(filters)
|
||||
.map((key) => `${key} LIKE '%${filters[key]}%'`)
|
||||
whereString += filters
|
||||
.map((filter) => `${tableName}.${filter.field} LIKE '%${filter.value}%'`)
|
||||
.join(' AND ');
|
||||
}
|
||||
|
||||
// if _search is provided, search rows by it
|
||||
// e.g. ?_search=John will search for John in all fields of the table
|
||||
// searching must be case insensitive
|
||||
// searching is case insensitive
|
||||
if (_search) {
|
||||
if (whereString) {
|
||||
if (whereString !== '') {
|
||||
whereString += ' AND ';
|
||||
} else {
|
||||
whereString += ' WHERE ';
|
||||
}
|
||||
try {
|
||||
// get all fields of the table
|
||||
const fields = db.prepare(`PRAGMA table_info(${name})`).all();
|
||||
const fields = db.prepare(`PRAGMA table_info(${tableName})`).all();
|
||||
whereString += '(';
|
||||
whereString += fields
|
||||
.map((field) => `${field.name} LIKE '%${_search}%'`)
|
||||
.map((field) => `${tableName}.${field.name} LIKE '%${_search}%'`)
|
||||
.join(' OR ');
|
||||
whereString += ')';
|
||||
} catch (error) {
|
||||
return res.status(400).json({
|
||||
message: error.message,
|
||||
@@ -104,10 +115,10 @@ const listTableRows = async (req, res) => {
|
||||
if (_schema) {
|
||||
const schemaFields = _schema.split(',');
|
||||
schemaFields.forEach((field) => {
|
||||
schemaString += `${name}.${field},`;
|
||||
schemaString += `${tableName}.${field},`;
|
||||
});
|
||||
} else {
|
||||
schemaString = `${name}.*`;
|
||||
schemaString = `${tableName}.*`;
|
||||
}
|
||||
|
||||
// remove trailing comma
|
||||
@@ -143,31 +154,36 @@ const listTableRows = async (req, res) => {
|
||||
let extendString = '';
|
||||
if (_extend) {
|
||||
const extendFields = _extend.split(',');
|
||||
extendFields.forEach((field) => {
|
||||
extendFields.forEach((extendedField) => {
|
||||
try {
|
||||
const foreignKey = db
|
||||
.prepare(`PRAGMA foreign_key_list(${name})`)
|
||||
.prepare(`PRAGMA foreign_key_list(${tableName})`)
|
||||
.all()
|
||||
.find((fk) => fk.from === field);
|
||||
.find((fk) => fk.from === extendedField);
|
||||
|
||||
if (!foreignKey) {
|
||||
throw new Error('Foreign key not found');
|
||||
}
|
||||
|
||||
const { table } = foreignKey;
|
||||
const { table: joinedTableName } = foreignKey;
|
||||
|
||||
const fields = db.prepare(`PRAGMA table_info(${table})`).all();
|
||||
const joinedTableFields = db
|
||||
.prepare(`PRAGMA table_info(${joinedTableName})`)
|
||||
.all();
|
||||
|
||||
extendString += ` LEFT JOIN ${table} as ${table} ON ${table}.${foreignKey.to} = ${name}.${field}`;
|
||||
extendString += ` LEFT JOIN ${joinedTableName} ON ${joinedTableName}.${foreignKey.to} = ${tableName}.${extendedField}`;
|
||||
|
||||
// joined fields will be returned in a new object called {field}_data e.g. author_id_data
|
||||
const extendFieldsString =
|
||||
'json_object( ' +
|
||||
fields
|
||||
.map((field) => `'${field.name}', ${table}.${field.name}`)
|
||||
joinedTableFields
|
||||
.map(
|
||||
(joinedTableField) =>
|
||||
`'${joinedTableField.name}', ${joinedTableName}.${joinedTableField.name}`
|
||||
)
|
||||
.join(', ') +
|
||||
' ) as ' +
|
||||
field +
|
||||
extendedField +
|
||||
'_data';
|
||||
|
||||
if (schemaString) {
|
||||
@@ -185,21 +201,34 @@ const listTableRows = async (req, res) => {
|
||||
}
|
||||
|
||||
// get paginated rows
|
||||
const query = `SELECT ${schemaString} FROM ${name} ${extendString} ${whereString} ${orderString} LIMIT ${limit} OFFSET ${
|
||||
const query = `SELECT ${schemaString} FROM ${tableName} ${extendString} ${whereString} ${orderString} LIMIT ${limit} OFFSET ${
|
||||
limit * (page - 1)
|
||||
}`;
|
||||
|
||||
try {
|
||||
const data = db.prepare(query).all();
|
||||
let data = db.prepare(query).all();
|
||||
|
||||
// parse json extended files
|
||||
if (_extend) {
|
||||
const extendFields = _extend.split(',');
|
||||
data = data.map((row) => {
|
||||
Object.keys(row).forEach((key) => {
|
||||
if (extendFields.includes(key.replace('_data', ''))) {
|
||||
row[key] = JSON.parse(row[key]);
|
||||
}
|
||||
});
|
||||
return row;
|
||||
});
|
||||
}
|
||||
|
||||
// get total number of rows
|
||||
const total = db
|
||||
.prepare(`SELECT COUNT(*) as total FROM ${name} ${whereString}`)
|
||||
.prepare(`SELECT COUNT(*) as total FROM ${tableName} ${whereString}`)
|
||||
.get().total;
|
||||
|
||||
const next =
|
||||
data.length === limit ? `/tables/${name}?page=${page + 1}` : null;
|
||||
const previous = page > 1 ? `/tables/${name}?page=${page - 1}` : null;
|
||||
data.length === limit ? `/tables/${tableName}?page=${page + 1}` : null;
|
||||
const previous = page > 1 ? `/tables/${tableName}?page=${page - 1}` : null;
|
||||
|
||||
res.json({
|
||||
data,
|
||||
@@ -236,7 +265,7 @@ const insertRowInTable = async (req, res) => {
|
||||
}
|
||||
*/
|
||||
|
||||
const { name } = req.params;
|
||||
const { name: tableName } = req.params;
|
||||
const { fields } = req.body;
|
||||
const fieldsString = Object.keys(fields).join(', ');
|
||||
|
||||
@@ -250,7 +279,13 @@ const insertRowInTable = async (req, res) => {
|
||||
})
|
||||
.join(', ');
|
||||
|
||||
const query = `INSERT INTO ${name} (${fieldsString}) VALUES (${valuesString})`;
|
||||
let values = `(${fieldsString}) VALUES (${valuesString})`;
|
||||
|
||||
if (valuesString === '') {
|
||||
values = 'DEFAULT VALUES';
|
||||
}
|
||||
|
||||
const query = `INSERT INTO ${tableName} ${values}`;
|
||||
try {
|
||||
const data = db.prepare(query).run();
|
||||
|
||||
@@ -315,7 +350,7 @@ const getRowInTableByPK = async (req, res) => {
|
||||
type: 'string'
|
||||
}
|
||||
|
||||
#swagger.parameters['_field'] = {
|
||||
#swagger.parameters['_lookup_field'] = {
|
||||
in: 'query',
|
||||
description: 'If you want to get field by any other field than primary key, use this parameter',
|
||||
required: false,
|
||||
@@ -323,17 +358,24 @@ const getRowInTableByPK = async (req, res) => {
|
||||
}
|
||||
|
||||
*/
|
||||
const { name, pk } = req.params;
|
||||
const { _field, _schema, _extend } = req.query;
|
||||
const { name: tableName, pk } = req.params;
|
||||
const { _lookup_field, _schema, _extend } = req.query;
|
||||
|
||||
let searchField = _field;
|
||||
let lookupField = _lookup_field;
|
||||
|
||||
if (!_field) {
|
||||
if (!_lookup_field) {
|
||||
// find the primary key of the table
|
||||
searchField = db
|
||||
.prepare(`PRAGMA table_info(${name})`)
|
||||
.all()
|
||||
.find((field) => field.pk === 1).name;
|
||||
try {
|
||||
lookupField = db
|
||||
.prepare(`PRAGMA table_info(${tableName})`)
|
||||
.all()
|
||||
.find((field) => field.pk === 1).name;
|
||||
} catch (error) {
|
||||
return res.status(400).json({
|
||||
message: error.message,
|
||||
error: error,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// if _schema is provided, return only those fields
|
||||
@@ -344,10 +386,10 @@ const getRowInTableByPK = async (req, res) => {
|
||||
if (_schema) {
|
||||
const schemaFields = _schema.split(',');
|
||||
schemaFields.forEach((field) => {
|
||||
schemaString += `${name}.${field},`;
|
||||
schemaString += `${tableName}.${field},`;
|
||||
});
|
||||
} else {
|
||||
schemaString = `${name}.*`;
|
||||
schemaString = `${tableName}.*`;
|
||||
}
|
||||
|
||||
// remove trailing comma
|
||||
@@ -383,31 +425,36 @@ const getRowInTableByPK = async (req, res) => {
|
||||
let extendString = '';
|
||||
if (_extend) {
|
||||
const extendFields = _extend.split(',');
|
||||
extendFields.forEach((field) => {
|
||||
extendFields.forEach((extendedField) => {
|
||||
try {
|
||||
const foreignKey = db
|
||||
.prepare(`PRAGMA foreign_key_list(${name})`)
|
||||
.prepare(`PRAGMA foreign_key_list(${tableName})`)
|
||||
.all()
|
||||
.find((fk) => fk.from === field);
|
||||
.find((fk) => fk.from === extendedField);
|
||||
|
||||
if (!foreignKey) {
|
||||
throw new Error('Foreign key not found');
|
||||
}
|
||||
|
||||
const { table } = foreignKey;
|
||||
const { table: joinedTableName } = foreignKey;
|
||||
|
||||
const fields = db.prepare(`PRAGMA table_info(${table})`).all();
|
||||
const joinedTableFields = db
|
||||
.prepare(`PRAGMA table_info(${joinedTableName})`)
|
||||
.all();
|
||||
|
||||
extendString += ` LEFT JOIN ${table} as ${table} ON ${table}.${foreignKey.to} = ${name}.${field}`;
|
||||
extendString += ` LEFT JOIN ${joinedTableName} ON ${joinedTableName}.${foreignKey.to} = ${tableName}.${extendedField}`;
|
||||
|
||||
// joined fields will be returned in a new object called {field}_data e.g. author_id_data
|
||||
const extendFieldsString =
|
||||
'json_object( ' +
|
||||
fields
|
||||
.map((field) => `'${field.name}', ${table}.${field.name}`)
|
||||
joinedTableFields
|
||||
.map(
|
||||
(joinedTableField) =>
|
||||
`'${joinedTableField.name}', ${joinedTableName}.${joinedTableField.name}`
|
||||
)
|
||||
.join(', ') +
|
||||
' ) as ' +
|
||||
field +
|
||||
extendedField +
|
||||
'_data';
|
||||
|
||||
if (schemaString) {
|
||||
@@ -424,13 +471,23 @@ const getRowInTableByPK = async (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
const query = `SELECT ${schemaString} FROM ${name} ${extendString} WHERE ${name}.${searchField} = ${pk}`;
|
||||
const query = `SELECT ${schemaString} FROM ${tableName} ${extendString} WHERE ${tableName}.${lookupField} = '${pk}'`;
|
||||
|
||||
try {
|
||||
const data = db.prepare(query).get();
|
||||
let data = db.prepare(query).get();
|
||||
// parse json extended files
|
||||
if (_extend) {
|
||||
const extendFields = _extend.split(',');
|
||||
|
||||
Object.keys(data)
|
||||
.filter((key) => extendFields.includes(key.replace('_data', '')))
|
||||
.forEach((key) => {
|
||||
data[key] = JSON.parse(data[key]);
|
||||
});
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
res.status(404).json({
|
||||
return res.status(404).json({
|
||||
message: 'Row not found',
|
||||
error: 'not_found',
|
||||
});
|
||||
@@ -440,7 +497,7 @@ const getRowInTableByPK = async (req, res) => {
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
res.status(400).json({
|
||||
return res.status(400).json({
|
||||
message: error.message,
|
||||
error: error,
|
||||
});
|
||||
@@ -472,7 +529,7 @@ const updateRowInTableByPK = async (req, res) => {
|
||||
schema: { $ref: "#/definitions/UpdateRowRequestBody" }
|
||||
}
|
||||
|
||||
#swagger.parameters['_field'] = {
|
||||
#swagger.parameters['_lookup_field'] = {
|
||||
in: 'query',
|
||||
description: 'If you want to update row by any other field than primary key, use this parameter',
|
||||
required: false,
|
||||
@@ -480,18 +537,25 @@ const updateRowInTableByPK = async (req, res) => {
|
||||
}
|
||||
*/
|
||||
|
||||
const { name, pk } = req.params;
|
||||
const { name: tableName, pk } = req.params;
|
||||
const { fields } = req.body;
|
||||
const { _field } = req.query;
|
||||
const { _lookup_field } = req.query;
|
||||
|
||||
let searchField = _field;
|
||||
let lookupField = _lookup_field;
|
||||
|
||||
if (!_field) {
|
||||
if (!_lookup_field) {
|
||||
// find the primary key of the table
|
||||
searchField = db
|
||||
.prepare(`PRAGMA table_info(${name})`)
|
||||
.all()
|
||||
.find((field) => field.pk === 1).name;
|
||||
try {
|
||||
lookupField = db
|
||||
.prepare(`PRAGMA table_info(${tableName})`)
|
||||
.all()
|
||||
.find((field) => field.pk === 1).name;
|
||||
} catch (error) {
|
||||
return res.status(400).json({
|
||||
message: error.message,
|
||||
error: error,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// wrap text values in quotes
|
||||
@@ -505,7 +569,14 @@ const updateRowInTableByPK = async (req, res) => {
|
||||
})
|
||||
.join(', ');
|
||||
|
||||
const query = `UPDATE ${name} SET ${fieldsString} WHERE ${searchField} = '${pk}'`;
|
||||
if (fieldsString === '') {
|
||||
return res.status(400).json({
|
||||
message: 'No fields provided',
|
||||
error: 'no_fields_provided',
|
||||
});
|
||||
}
|
||||
|
||||
const query = `UPDATE ${tableName} SET ${fieldsString} WHERE ${lookupField} = '${pk}'`;
|
||||
try {
|
||||
db.prepare(query).run();
|
||||
|
||||
@@ -537,7 +608,7 @@ const deleteRowInTableByPK = async (req, res) => {
|
||||
description: 'Primary key',
|
||||
required: true,
|
||||
}
|
||||
#swagger.parameters['_field'] = {
|
||||
#swagger.parameters['_lookup_field'] = {
|
||||
in: 'query',
|
||||
description: 'If you want to delete row by any other field than primary key, use this parameter',
|
||||
required: false,
|
||||
@@ -545,30 +616,45 @@ const deleteRowInTableByPK = async (req, res) => {
|
||||
}
|
||||
|
||||
*/
|
||||
const { name, pk } = req.params;
|
||||
const { _field } = req.query;
|
||||
const { name: tableName, pk } = req.params;
|
||||
const { _lookup_field } = req.query;
|
||||
|
||||
let searchField = _field;
|
||||
let lookupField = _lookup_field;
|
||||
|
||||
if (!_field) {
|
||||
if (!_lookup_field) {
|
||||
// find the primary key of the table
|
||||
searchField = db
|
||||
.prepare(`PRAGMA table_info(${name})`)
|
||||
.all()
|
||||
.find((field) => field.pk === 1).name;
|
||||
try {
|
||||
lookupField = db
|
||||
.prepare(`PRAGMA table_info(${tableName})`)
|
||||
.all()
|
||||
.find((field) => field.pk === 1).name;
|
||||
} catch (error) {
|
||||
return res.status(400).json({
|
||||
message: error.message,
|
||||
error: error,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const query = `DELETE FROM ${name} WHERE ${searchField} = '${pk}'`;
|
||||
const data = db.prepare(query).run();
|
||||
const query = `DELETE FROM ${tableName} WHERE ${lookupField} = '${pk}'`;
|
||||
|
||||
if (data.changes === 0) {
|
||||
res.status(404).json({
|
||||
error: 'not_found',
|
||||
});
|
||||
} else {
|
||||
res.json({
|
||||
message: 'Row deleted',
|
||||
data,
|
||||
try {
|
||||
const data = db.prepare(query).run();
|
||||
|
||||
if (data.changes === 0) {
|
||||
res.status(404).json({
|
||||
error: 'not_found',
|
||||
});
|
||||
} else {
|
||||
res.json({
|
||||
message: 'Row deleted',
|
||||
data,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
res.status(400).json({
|
||||
message: error.message,
|
||||
error: error,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -206,8 +206,8 @@ const getTableSchema = async (req, res) => {
|
||||
}
|
||||
|
||||
*/
|
||||
const { name } = req.params;
|
||||
const query = `PRAGMA table_info(${name})`;
|
||||
const { name: tableName } = req.params;
|
||||
const query = `PRAGMA table_info(${tableName})`;
|
||||
try {
|
||||
const schema = db.prepare(query).all();
|
||||
|
||||
@@ -236,8 +236,8 @@ const deleteTable = async (req, res) => {
|
||||
}
|
||||
|
||||
*/
|
||||
const { name } = req.params;
|
||||
const query = `DROP TABLE ${name}`;
|
||||
const { name: tableName } = req.params;
|
||||
const query = `DROP TABLE ${tableName}`;
|
||||
try {
|
||||
db.prepare(query).run();
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
const Joi = require('joi');
|
||||
|
||||
// allow other fields for filtering
|
||||
const listTableRows = Joi.object({
|
||||
name: Joi.string().min(3).max(30).required(),
|
||||
_page: Joi.number().integer().min(1).default(1),
|
||||
@@ -9,6 +8,7 @@ const listTableRows = Joi.object({
|
||||
_ordering: Joi.string(),
|
||||
_schema: Joi.string(),
|
||||
_extend: Joi.string(),
|
||||
_filters: Joi.string(),
|
||||
}).unknown(true);
|
||||
|
||||
const insertRowInTable = Joi.object({
|
||||
@@ -19,7 +19,7 @@ const insertRowInTable = Joi.object({
|
||||
const getRowInTableByPK = Joi.object({
|
||||
name: Joi.string().min(3).max(30).required(),
|
||||
pk: Joi.string().required(),
|
||||
_field: Joi.string().min(3).max(30),
|
||||
_lookup_field: Joi.string().min(3).max(30),
|
||||
_schema: Joi.string(),
|
||||
_extend: Joi.string(),
|
||||
});
|
||||
@@ -28,13 +28,13 @@ const updateRowInTableByPK = Joi.object({
|
||||
name: Joi.string().min(3).max(30).required(),
|
||||
pk: Joi.string().required(),
|
||||
fields: Joi.object().required(),
|
||||
_field: Joi.string().min(3).max(30),
|
||||
_lookup_field: Joi.string().min(3).max(30),
|
||||
});
|
||||
|
||||
const deleteRowInTableByPK = Joi.object({
|
||||
name: Joi.string().min(3).max(30).required(),
|
||||
pk: Joi.string().required(),
|
||||
_field: Joi.string().min(3).max(30),
|
||||
_lookup_field: Joi.string().min(3).max(30),
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"version": "0.0.6",
|
||||
"version": "0.0.7",
|
||||
"title": "Soul API",
|
||||
"description": "API Documentation for <b>Soul</b>, a simple SQLite RESTful server. "
|
||||
},
|
||||
@@ -237,12 +237,13 @@
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "_search",
|
||||
"name": "_filters",
|
||||
"description": "Filter rows. e.g. ?_filters=name:John,age:20 will return rows where name is John and age is 20.",
|
||||
"in": "query",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "filters",
|
||||
"name": "_search",
|
||||
"in": "query",
|
||||
"type": "string"
|
||||
}
|
||||
@@ -332,7 +333,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "_field",
|
||||
"name": "_lookup_field",
|
||||
"in": "query",
|
||||
"description": "If you want to get field by any other field than primary key, use this parameter",
|
||||
"required": false,
|
||||
@@ -381,7 +382,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "_field",
|
||||
"name": "_lookup_field",
|
||||
"in": "query",
|
||||
"description": "If you want to update row by any other field than primary key, use this parameter",
|
||||
"required": false,
|
||||
@@ -439,7 +440,7 @@
|
||||
"description": "Primary key"
|
||||
},
|
||||
{
|
||||
"name": "_field",
|
||||
"name": "_lookup_field",
|
||||
"in": "query",
|
||||
"description": "If you want to delete row by any other field than primary key, use this parameter",
|
||||
"required": false,
|
||||
@@ -450,6 +451,9 @@
|
||||
"200": {
|
||||
"description": "OK"
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request"
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found"
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ Soul is consist of 3 main namespaces: `/tables`, `/rows` and `/`. In this docume
|
||||
|
||||
## Setup Environment
|
||||
|
||||
To follow the below examples run Soul with `sample.db` provided in `examples/` directory:
|
||||
To follow the below examples we need to download a sample database and also install Soul CLI.
|
||||
|
||||
### Download Sample Database
|
||||
|
||||
|
||||
41
docs/api/root-examples.md
Normal file
41
docs/api/root-examples.md
Normal file
@@ -0,0 +1,41 @@
|
||||
## Root
|
||||
|
||||
### 1. Transaction
|
||||
|
||||
To start a transaction call `/transaction` endpoint with `POST` method.
|
||||
|
||||
```bash
|
||||
curl --request POST \
|
||||
--url http://localhost:8000/api/transaction \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{
|
||||
"transaction": [
|
||||
{
|
||||
"statement": "INSERT INTO Artist (ArtistId, Name) VALUES (:id, :name)",
|
||||
"values": { "id": 100000, "name": "Glen Hansard" }
|
||||
},
|
||||
{
|
||||
"query": "SELECT * FROM Artist ORDER BY ArtistId DESC LIMIT 1"
|
||||
}
|
||||
]
|
||||
}'
|
||||
```
|
||||
|
||||
Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"changes": 1,
|
||||
"lastInsertRowid": 100000
|
||||
},
|
||||
[
|
||||
{
|
||||
"ArtistId": 100000,
|
||||
"Name": "Glen Hansard"
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
```
|
||||
213
docs/api/rows-examples.md
Normal file
213
docs/api/rows-examples.md
Normal file
@@ -0,0 +1,213 @@
|
||||
## Rows
|
||||
|
||||
### 1. List Rows of a Table
|
||||
|
||||
To list all (or some of) rows we simply call `/tables/<table-name>/rows/` endpoint with `GET` method.
|
||||
|
||||
```bash
|
||||
curl 'localhost:8000/api/tables/Album/rows/'
|
||||
```
|
||||
|
||||
Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"AlbumId": 1,
|
||||
"Title": "For Those About To Rock We Salute You",
|
||||
"ArtistId": 1
|
||||
},
|
||||
{ "AlbumId": 2, "Title": "Balls to the Wall", "ArtistId": 2 }
|
||||
// ...
|
||||
],
|
||||
"total": 347,
|
||||
"next": "/tables/Album?page=2",
|
||||
"previous": null
|
||||
}
|
||||
```
|
||||
|
||||
#### Query Params
|
||||
|
||||
- `_page` e.g. `?_page=2`, to get the second page of results.
|
||||
- `_limit` e.g. `?_limit=20`, to get 20 results per page.
|
||||
- `_search` e.g. `?_search=rock`, to search between rows.
|
||||
- `_ordering` e.g. `?_ordering=-Title`, to order rows by title descending, or without `-` to sort ascending, e.g. `?_ordering=Title`
|
||||
- `_schema` e.g. `?_schema=Title,ArtistId`, to get only the Title and ArtistId columns.
|
||||
- `_extend` e.g. `?_extend=ArtistId`, to get the Artist object related to the Album.
|
||||
- `_filters` e.g. `?_filters=ArtistId:1,Title:Rock`, to get only the rows where the ArtistId is 1 and the Title is Rock.
|
||||
|
||||
Example with query params
|
||||
|
||||
```bash
|
||||
curl 'localhost:8000/api/tables/Album/rows?_page=1&_limit=20&_search=rock&_ordering=-Title&_schema=Title,ArtistId&_extend=ArtistId&_filters=ArtistId:90'
|
||||
```
|
||||
|
||||
Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"Title": "Rock In Rio [CD2]",
|
||||
"ArtistId": 90,
|
||||
"ArtistId_data": { "ArtistId": 90, "Name": "Iron Maiden" }
|
||||
},
|
||||
{
|
||||
"Title": "Rock In Rio [CD1]",
|
||||
"ArtistId": 90,
|
||||
"ArtistId_data": { "ArtistId": 90, "Name": "Iron Maiden" }
|
||||
}
|
||||
],
|
||||
"total": 2,
|
||||
"next": null,
|
||||
"previous": null
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Insert a New Row
|
||||
|
||||
To insert a new row to a `table` call `/tables/<table-name>/rows/` endpoint with `POST` method.
|
||||
|
||||
```bash
|
||||
curl --request POST \
|
||||
--url http://localhost:8000/api/tables/Employee/rows \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{
|
||||
"fields": {
|
||||
"FirstName": "Damien",
|
||||
"LastName": "Rice"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
Response
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Row inserted",
|
||||
"data": {
|
||||
"changes": 1,
|
||||
"lastInsertRowid": 9
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Body Params
|
||||
|
||||
- `fields` e.g.
|
||||
|
||||
```json
|
||||
"fields": {
|
||||
// fields values for the new row
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Get a Row
|
||||
|
||||
To get a row call `/tables/<table-name>/rows/<lookup-value>/` endpoint with `GET` method.
|
||||
|
||||
```bash
|
||||
curl http://localhost:8000/api/tables/Album/rows/1/
|
||||
```
|
||||
|
||||
Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"AlbumId": 1,
|
||||
"Title": "For Those About To Rock We Salute You",
|
||||
"ArtistId": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Query Params
|
||||
|
||||
- `_lookup_field` e.g. `?_lookup_field=ArtistId`, to get the row by the ArtistId field. If not provided, the default lookup field is the primary key of the table.
|
||||
- `_schema` e.g. `?_schema=Title,ArtistId`, to get only the Title and ArtistId columns.
|
||||
- `_extend` e.g. `?_extend=ArtistId`, to get the Artist object related to the Album.
|
||||
|
||||
Example with query params
|
||||
|
||||
```bash
|
||||
curl 'http://localhost:8000/api/tables/Album/rows/Facelift?_lookup_field=Title&_extend=ArtistId&_schema=Title'
|
||||
```
|
||||
|
||||
Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"Title": "Facelift",
|
||||
"ArtistId_data": {
|
||||
"ArtistId": 5,
|
||||
"Name": "Alice In Chains"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### 4. Update a Row
|
||||
|
||||
To update a row call `/tables/<table-name>/rows/<lookup-value>/` endpoint with `PUT` method.
|
||||
|
||||
```bash
|
||||
curl --request PUT \
|
||||
--url http://localhost:8000/api/tables/Album/rows/7 \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{
|
||||
"fields": {
|
||||
"Title": "FaceElevate"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
Response
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Row updated"
|
||||
}
|
||||
```
|
||||
|
||||
#### Query Params
|
||||
|
||||
- `_lookup_field` e.g. `?_lookup_field=ArtistId`, to update the row by the ArtistId field. If not provided, the default lookup field is the primary key of the table.
|
||||
|
||||
#### Body Params
|
||||
- `fields` e.g.
|
||||
|
||||
```json
|
||||
"fields": {
|
||||
// fields values to update
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### 5. Delete a Row
|
||||
|
||||
To delete a row call `/tables/<table-name>/rows/<lookup-value>/` endpoint with `DELETE` method.
|
||||
|
||||
```bash
|
||||
curl --request DELETE \
|
||||
--url http://localhost:8000/api/tables/PlaylistTrack/rows/1
|
||||
```
|
||||
|
||||
Response
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Row deleted",
|
||||
"data": {
|
||||
"changes": 3290,
|
||||
"lastInsertRowid": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Query Params
|
||||
|
||||
- `_lookup_field` e.g. `?_lookup_field=ArtistId`, to delete the row by the ArtistId field. If not provided, the default lookup field is the primary key of the table.
|
||||
Reference in New Issue
Block a user