
Security News
GitHub Actions Pricing Whiplash: Self-Hosted Actions Billing Change Postponed
GitHub postponed a new billing model for self-hosted Actions after developer pushback, but moved forward with hosted runner price cuts on January 1.
BirchTree is mainly a helper library for knexjs. It takes an instance of knex and adds two helper functions: grow and nest. These functions make it easy to get nested objects as results when running join queries.
BirchTree is also a repository library built on knexjs. It provides base Repo and Model classes that can be extended to create a basic model system.
npm install --save birchtree
BirchTree is written in typescript and should just work. You can import the type for birchtree like this
import { BirchTree } from 'birchtree'
import birchtree from 'birchtree';
import * as Knex from 'knex';
const knex = Knex({
client: 'mysql',
debug: false,
connection,
pool
});
const birch = birchtree(knex);
const songs = 'albums:songs';
const author = 'albums:songs:author';
const select = await birch.grow('artists', 'albums', `songs AS ${songs}`, `authors AS ${author}`);
const results = await birch('users')
.select(select)
.leftJoin('albums', 'albums.artist_id', 'artists.id')
.leftJoin(`songs AS ${songs}`, `${songs}.album_id`, `albums.id`)
.leftJoin(`authors as ${author}`, `${author}.id`, `${songs}.author_id`)
.where('artists.id', '=', 1);
const nestedResults = birch.nest(results);
Results will look like
[{
id: 1,
name: 'The Beatles',
albums: [{
id: 1,
name: 'Rubber Soul',
songs: [{
id: 1,
name: 'Drive My Car',
author: {
id: 2,
name: 'Paul McCartney'
}
}, {
id: 2,
name: 'Norwegian Wood (This Bird has Flown)',
author: {
id: 1,
name: 'John Lennon'
}
}]
}, {
id: 2,
name: 'Revolver',
songs: [{
id: 3,
name: 'Taxman',
author: {
id: 3,
name: 'George Harrison'
}
}, {
id: 4,
name: 'Eleanor Rigby',
author: {
id: 2,
name: 'Paul McCartney'
}
}]
}]
}]
There are some important things to note from the example.
:Asynchronous: Takes any number of table names with or without aliases as arguments and returns an array for knex's select function that will make sure columns don't get overwritten. It will select every column in each table given.
Takes the results from a select query and nests them using treeize
import { default as birchtree, BirchTree, Repo, Model } from 'birchtree';
// let's just pretend we set knex up
const birch = birchtree(knex);
// let's make a user repo
const userRepo = new UserRepo(birch);
class User extends Model {
static tableName = 'users';
private id: number;
private email: string;
private username: string;
constructor(props) {
super();
Object.assign(this, props);
}
toJSON() {
return {
id: this.id,
email: this.email,
username: this.username
}
}
}
class UserRepo extends Repo<User> {
constructor(birch) {
super(User, birch);
}
async findDuplicate(user: User, trx: BirchTree.Transaction) {
return this.createQuery(trx)
.where({ email: user.email })
.orWhere({ username: user.username });
}
}
static tableName property equal to the name of the corresponding database tabletoJSON function. This function is used to get the object to persist in repo.create, repo.update and repo.saveid propertysuper in the constructorthis.birch in extended reposconst user = new User({
email: 'fry@gmail.com',
username: 'fry'
});
await userRepo.create(user);
user.username = 'bender';
await userRepo.update(user);
user.email = 'bender@gmail.com';
await userRepo.save(user);
const leela = new User({
email: 'leela@gmail.com',
username: 'leela'
});
await userRepo.save(leela);
const bender = await userRepo.findOneById(user.id);
const benderAndLeela = await userRepo.findByIds([bender.id, leela.id]);
await userRepo.exterminate(bender);
const leelaAgain = await userRepo.findOne({ email: 'leela@gmail.com' });
const leelaAsAnArray = await userRepo.find({ email: 'leela@gmail.com' });
This returns a birchtree/knex querybuilder.
const results = await userRepo.createQuery().where('email', '=', 'bender@gmail.com');
birch.transaction(trx => {
const bender = await userRepo.findOne({ username: 'bender' }, trx);
bender.username = 'coilette';
await userRepo.save(bender, trx);
const leela = await userRepo.createQuery(trx).where({ username: 'leela' });
leela.username = 'Turanga';
await userRepo.save(leela, trx);
return [ bender, leela ];
})
.then(results => console.log(results))
.catch(err => console.error(err));
FAQs
Repository system and helper functions for knexjs
We found that birchtree demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
GitHub postponed a new billing model for self-hosted Actions after developer pushback, but moved forward with hosted runner price cuts on January 1.

Research
Destructive malware is rising across open source registries, using delays and kill switches to wipe code, break builds, and disrupt CI/CD.

Security News
Socket CTO Ahmad Nassri shares practical AI coding techniques, tools, and team workflows, plus what still feels noisy and why shipping remains human-led.