2
0
mirror of https://github.com/frappe/books.git synced 2024-12-22 10:58:59 +00:00

get_all with filters

This commit is contained in:
Rushabh Mehta 2018-01-01 15:58:30 +05:30
parent 2ed02ea846
commit 80699c833a
7 changed files with 209 additions and 24 deletions

118
README.md
View File

@ -2,22 +2,124 @@
Core libs for Frappe Framework JS
### Examples
## Examples
### Declaring Models
Models are declared by adding a `.json` model file in the `models/doctype` folder of the module/app.
{
"autoname": "hash",
"name": "ToDo",
"doctype": "DocType",
"issingle": 0,
"fields": [
{
"fieldname": "subject",
"label": "Subject",
"fieldtype": "Data",
"reqd": 1
},
{
"fieldname": "description",
"label": "Description",
"fieldtype": "Text"
},
{
"fieldname": "status",
"label": "Status",
"fieldtype": "Select",
"options": [
"Open",
"Closed"
],
"default": "Open",
"reqd": 1
}
]
}
### Setup / Migrate
const frappe = require('frappe-core);
# init database
frappe.init();
# make a new todo
// sync all schema from `models` folders in all apps
frappe.migrate();
### Managing Documents
Frappe Object-Relational-Mapper (ORM) helps you manage (create, read, update, delete) documents based on the DocTypes declared
#### Create
const frappe = require('frappe-core);
frappe.init();
// make a new todo
let todo = frappe.get_doc({doctype: 'ToDo', subject: 'something'})
todo.insert()
# get all todos
let total_open = 0;
for (let d of frappe.get_all('ToDo')) {
todo = frappe.get_doc('ToDo', d.name);
if (todo.status == 'Open') total_open += 1;
#### Read
const frappe = require('frappe-core);
frappe.init();
// get all open todos
let todos = frappe.db.get_all('ToDo', ['name'], {status: "Open"});
let first_todo = frappe.get_doc('ToDo', toods.name);
#### Update
const frappe = require('frappe-core);
frappe.init();
// get all open todos
let todos = frappe.db.get_all('ToDo', ['name'], {status: "Open"});
let first_todo = frappe.get_doc('ToDo', toods.name);
first_todo.status = 'Closed';
first_todo.update();
### Metadata
const frappe = require('frappe-core);
frappe.init();
let todo_meta = frappe.get_meta('ToDo');
// get all fields of type "Data"
let data_fields = todo_meta.fields.map(d => d.fieldtype=='Data' ? d : null);
### Controllers
You can write event handlers in controllers, by declaring a `.js` file in the `models/doctype/` folder along with the model file.
The name of the class must be the slugged name of the DocType
const frappe = require('frappe-core');
class todo extends frappe.document.Document {
validate() {
// set default status as "Open" if not set
if (!this.status) {
this.status = 'Open';
}
}
}
module.exports = { todo: todo };
### Database
You can also directly write SQL with `frappe.db.sql`
const frappe = require('frappe-core);
frappe.init();
all_todos = frappe.db.sql('select name from todo');

View File

@ -43,20 +43,21 @@ class Database {
}
}
migrate() {
for (let doctype in frappe.models.path_map.doctype) {
if (this.table_exists(doctype)) {
this.alter_table(doctype);
} else {
this.create_table(doctype);
}
}
}
create_table(doctype) {
let meta = frappe.get_meta(doctype);
let columns = [];
// add standard fields
let fields = frappe.model.standard_fields.slice();
if (meta.istable) {
fields = fields.concat(model.child_fields);
}
// add model fields
fields = fields.concat(meta.fields);
for (let df of fields) {
for (let df of this.get_fields(meta)) {
if (frappe.model.type_map[df.fieldtype]) {
columns.push(`${df.fieldname} ${frappe.model.type_map[df.fieldtype]} ${df.reqd ? "not null" : ""} ${df.default ? ("default " + frappe.utils.sqlescape(df.default)) : ""}`);
}
@ -68,6 +69,13 @@ class Database {
return this.sql(query);
}
alter_table(doctype) {
// add columns
// change columns
}
get(doctype, name) {
let doc = frappe.db.sql(`select * from ${frappe.slug(doctype)} where name = ${frappe.db.escape(name)}`);
return doc ? doc[0] : {};
@ -88,6 +96,29 @@ class Database {
set ${assigns.join(", ")}`);
}
get_all(doctype, fields=['name'], filters, start, limit) {
return this.sql(`select ${fields.join(", ")}
from ${frappe.slug(doctype)}
${filters ? "where" : ""} ${this.get_filter_conditions(filters)}
${limit ? ("limit " + limit) : ""} ${start ? ("offset " + start) : ""}`);
}
get_filter_conditions(filters) {
// {"status": "Open"} => `status = "Open"`
// {"status": "Open", "name": ["like", "apple%"]}
// => `status="Open" and name like "apple%"
let conditions = [];
for (let key in filters) {
const value = filters[key];
if (value instanceof Array) {
conditions.push(`${key} ${value[0]} ${this.escape(value)}`);
} else {
conditions.push(`${key} = ${this.escape(value)}`);
}
}
return conditions.join(" and ");
}
sql(query, opts={}) {
//console.log(query);
const result = frappe.db._conn.exec(query);
@ -109,6 +140,23 @@ class Database {
escape(value) {
return frappe.utils.sqlescape(value);
}
get_fields(meta) {
// add standard fields
let fields = frappe.model.standard_fields.slice();
if (meta.istable) {
fields = fields.concat(frappe.model.child_fields);
}
// add model fields
fields = fields.concat(meta.fields);
return fields;
}
table_exists(table) {
return this.sql(`SELECT name FROM sqlite_master WHERE type='table' AND name='${table}'`) ? true : false;
}
}
function sql_result_to_obj(result) {

View File

@ -4,7 +4,7 @@ const frappe = require('frappe-core');
describe('Controller', () => {
before(function() {
frappe.init();
frappe.db.create_table('ToDo');
frappe.db.migrate();
});
it('should call controller method', () => {

View File

@ -4,10 +4,43 @@ const frappe = require('frappe-core');
describe('Document', () => {
before(function() {
frappe.init();
frappe.db.migrate();
});
// it('should create a table', () => {
// frappe.db.create_table('ToDo');
// frappe.db.write();
// });
it('should insert and get values', () => {
frappe.db.sql('delete from todo');
frappe.get_doc({doctype:'ToDo', subject: 'testing 1'}).insert();
frappe.get_doc({doctype:'ToDo', subject: 'testing 3'}).insert();
frappe.get_doc({doctype:'ToDo', subject: 'testing 2'}).insert();
let subjects = frappe.db.get_all('ToDo', ['name', 'subject']).map(d => d.subject);
assert.ok(subjects.includes('testing 1'));
assert.ok(subjects.includes('testing 2'));
assert.ok(subjects.includes('testing 3'));
});
it('should filter correct values', () => {
let subjects = null;
frappe.db.sql('delete from todo');
frappe.get_doc({doctype:'ToDo', subject: 'testing 1', status: 'Open'}).insert();
frappe.get_doc({doctype:'ToDo', subject: 'testing 3', status: 'Open'}).insert();
frappe.get_doc({doctype:'ToDo', subject: 'testing 2', status: 'Closed'}).insert();
subjects = frappe.db.get_all('ToDo', ['name', 'subject'],
{status: 'Open'}).map(d => d.subject);
assert.ok(subjects.includes('testing 1'));
assert.ok(subjects.includes('testing 3'));
assert.equal(subjects.includes('testing 2'), false);
subjects = frappe.db.get_all('ToDo', ['name', 'subject'],
{status: 'Closed'}).map(d => d.subject);
assert.equal(subjects.includes('testing 1'), false);
assert.equal(subjects.includes('testing 3'), false);
assert.ok(subjects.includes('testing 2'));
});
});

View File

@ -4,7 +4,7 @@ const frappe = require('frappe-core');
describe('Document', () => {
before(function() {
frappe.init();
frappe.db.create_table('ToDo');
frappe.db.migrate();
});
it('should insert a doc', () => {

View File

@ -4,6 +4,7 @@ const frappe = require('frappe-core');
describe('Meta', () => {
before(function() {
frappe.init();
frappe.db.migrate();
});
it('should get init from json file', () => {

View File

@ -4,6 +4,7 @@ const frappe = require('frappe-core');
describe('Models', () => {
before(function() {
frappe.init();
frappe.db.migrate();
});
it('should get todo json', () => {