Spinosaurus
Spinosaurus is a ORM that can run in deno platforms and can be use with TypeScript. Its goal is to always support the latest TypeScript features and provide additional features that help you to develop any kind of application that uses databases - from small applications with a few tables to large scale enterprise applications with multiple databases. (this project is inspired by typeORM)
Features
- Supports both DataMapper and ActiveRecord (your choice)
- Entities and columns
- Database-specific column types
- Entity manager
- Repositories and custom repositories
- Clean object relational model
- Associations (relations)
- Uni-directional relations
- Bi-directional relations
- Self-referenced relations
- Eager and lazy relations
- Supports multiple inheritance patterns
- Cascades
- Indices
- Transactions
- Migrations and automatic migrations generation
- Connection pooling
- Replication
- Using multiple database connections
- Working with multiple databases types
- Cross-database and cross-schema queries
- Elegant-syntax, flexible and powerful QueryBuilder
- Left and inner joins
- Proper pagination for queries using joins
- Query caching
- Streaming raw results
- Logging
- Listeners and subscribers (hooks)
- Supports closure table pattern
- Schema declaration in models or separate configuration files
- Connection configuration in json / xml / yml / yaml / env formats
- Database supports
- Postgresql
- MySql / MariaDB
- Microsoft Sql Server
- Oracle
- Supports MongoDB NoSQL database
- works in platforms
- Deno
- NodeJS
- Browser
- Electron
- Language support
- JavaScript
- TypeScript
- Produced code is performant, flexible, clean and maintainable
- Follows all possible best practices
- CLI
Scripts (Velociraptor)
Test all
deno run -qA https://code.velociraptor.run test
Test one
deno run -qA https://code.velociraptor.run test:one tests/unit/decorator_column_executor_test.ts
Test SQL
deno run -qA https://code.velociraptor.run test:sql
Test Executor
deno run -qA https://code.velociraptor.run test:exec
TODO
documentation
code coments
testing getMetadata, getTempMetadata, clearMetadata, clearTempMetadata create(...).columns() functions
testing primary column executor testing
testing generated column executor testing
column, unique, check alter testing
alter column (implement primary key and auto-increment)
testing for generate columns from entity in select using options
adding primary key column in each delete
throw a error when @UpdateColumn property is not a Number type
implement in @InsertColumn, @UpdateColumn (value) and ({options}, value) params
does not update object without primary key in entity mode (updating a antity), create testing too
create a option in update entity option witch can update without a primary key
adding joinAndOne, leftAndOne, rigthAndOne and exec testing, remember include in joinAndSelect, joinAndSelect,
adding joinAndWrap, leftAndWrap, rigthAndWrap and exec testing, remember include in joinAndSelect, joinAndSelect, joinAndSelect as a option (wrap: boolean)
suport multiple connection
rename a column, using index in @Column({ columnIndex: 3 })
create a method getOneOrFail, it throw a exeption if it does not have one row
reverse interpolate transform this
user.propertyKey
to"user"."columnName"
|[user].[columnName]
|`user`.`columnName`
, this transformation depends on database typecreate skip
create take
set maxExecutionTime as a option in select, insert, update, delete and transaction
numeric param in
groupBy
,addGroupBy
,orderBy
,addOrderBy
and set select definition internallychange
from({ entity: Entity })
tofrom(Entity, "e")
on documentation and codeorderBy({ "p.passwordOrder": "DESC" })
change param
orderBy
andaddOrderBy
strategic from ... to arrayusing path in Next and After in decorators and query builder
updating database with createConnection
check constraint ending with
*_not_null
should throw a errormake a test by diferences in column quantity and position on reference decorators
adding tinyint in spitype
use IndexDb, very in the future
use a structure equals to indexDB to store entities
whereInIds([ 1, 2, 3, 4 ])
transform toimplement insert into select, update from select, maybe upsert from select
/*update from select*/ await conn.update(User).set({ userDisplay: () => `p."firstName"` }) .from(User, "u").join(Person, "p", `p."person_ID" = u."person_ID"`); /*insert into select*/ await conn.insert(User).values({ userDisplay: () => `p."firstName"` }) .from(User, "u").join(Person, "p", `p."person_ID" = u."person_ID"`);
Make the next code work:
const profile = new Profile(); profile.gender = "male"; profile.photo = "me.jpg"; await conn.update(Profile).set(profile).execute(); const user = new User(); user.name = "Joe Smith"; user.profile = profile; await conn.update(User).set(user).execute();
implementing query builder short form:
await conn.update(User).set(user).execute(); -> await conn.update(user).execute();
,await conn.insert(User).values(user).execute(); -> await conn.insert(user).execute();
andawait conn.upsert(User).values(user).execute(); -> await conn.upsert(user).execute();
escape in insert, update, and upsert like the following code:
const db = await getConnection();
await db.insert(Company)
.values({
companyName: "Timber",
dateFormat: () => `"dateFormat" + :dateFormat`,
})
.params({ dateFormat: "dd/MM/yyyy" })
.execute();
...
const db = await getConnection();
await db.insert(Company)
.values({
companyName: "Timber",
dateFormat: () => [`"dateFormat" + :dateFormat`, { dateFormat: "dd/MM/yyyy" }],
})
.execute();
implementing
db.softDelete
, when you use a@DeleteColumn
decorator in aboolean
orDate
types, it performes a update changing the column's value.implementing
db.restoreDelete
, when you use a@DeleteColumn
decorator in aboolean
orDate
types, it performes a update changing the column's value to maked visible.implementing
@Transaction
decorator as follows:
async function save(conection: Connection, user: User) {
await connection.upsert(User).values(user).execute();
}
- implementing caching result:
- files or memory storage
- timer and query diferences