Comments (65)
I've put together a minimal impl, have a look https://github.com/nappa85/sea-orm-macro/
Inside tests there is a working example.
Sure there is space for improvement, but it can be a starting point
from sea-orm.
@tyt2y3 I spent most of my day yesterday and today creating a PR for this too. It's at a working stage, just need the columntrait to be generated too.
I'll create the PR in a few hours!
from sea-orm.
So based on @nappa85 work, I have had something in mind:
Basic usage
use sea_orm::EntityModel;
#[derive(EntityModel)]
struct Model {
id: u64,
name: String,
}
this will autogenerate the Column enum (omitted here).
Primary key
To autogenerate the PrimaryKey enum too, simply add the attribute like this:
use sea_orm::EntityModel;
#[derive(EntityModel)]
struct Model {
#[sea_orm(primary_key)]
id: u64,
name: String,
}
this will autogenerate the PrimaryKey enum, with implied auto_increment = true
.
If we instead want auto_increment = false
, we can specify:
#[sea_orm(primary_key, auto_increment = false)]
For composite primary key, we can annotate a column multiple times:
struct Model {
#[sea_orm(primary_key)]
id1: i32,
#[sea_orm(primary_key)]
id2: i32,
}
And auto_increment will be false automatically.
Custom types
If your struct uses a non-basic type, you'll have to specify the SQL type for that column:
use sea_orm::EntityModel;
#[derive(EntityModel)]
struct Model {
#[sea_orm(primary_key)]
id: u64,
#[sea_orm(column_type = "String(Some(255))", default_value = "new user")]
name: MyName,
#[sea_orm(default_expr = "gen_random_uuid()", indexed)]
uuid: Uuid,
#[sea_orm(column_type = "Char(Some(1))", unique, nullable)]
admin: Option<MyBool>,
}
These will corresponds to the following column definitions:
ColumnType::String(Some(2555)).def().default_value("new user")
ColumnType::Uuid().def().default_expr("gen_random_uuid()").indexed()
ColumnType::Char(Some(1)).def().unique().nullable()
That said, 3 more methods will be added:
fn default_value(self, v: V) where V: IntoValue { ... }
fn default_expr(self, expr: &str) { ... }
fn nullable(self) { ... }
I think this will also addresses #101
Let's discuss a bit before putting this into implementation.
from sea-orm.
I am thinking, whether DeriveEntityModel should automatically derive DeriveModel and DeriveActiveModel, to make it less verbose.
I've made some tests about it, maybe I'm wrong, but it seems that a derive macro can't edit the original struct, to do so you need a proc-macro.
I've tried with this code, inside DeriveEntityModel macro:
attrs.push(Attribute { pound_token: Pound(Span::call_site()), style: AttrStyle::Outer, bracket_token: Bracket(Span::call_site()), path: Path { leading_colon: None, segments: { let mut temp = Punctuated::new(); temp.push(PathSegment { ident: Ident::new("derive", Span::call_site()), arguments: PathArguments::None, }); temp }, }, tokens: quote! { DeriveModel, DeriveActiveModel }, });
This is crazy loll
from sea-orm.
Yes, I understand your point of view, and it was exactly the reply I thought for the question "why didn't they already made this?".
But, as @acidic9 pointed, there can be default impl via derive macro and custom impl in plain Rust without any problems.
As far as I can see, code completion works with macro-produced code without problems.
Macros aren't made to replace code, but to easy the life of who writes it.
For example, serde has a derive macro for Serialize and Deserialize, but anyone can manually derive the traits for non-standard situations, and there are lots of docs about it.
I would prefer a serde-like approach, where the default is easily reached with a macro, and non-default-fitting situations can be covered in plain Rust.
from sea-orm.
@acidic9 the format you propose already looks good. Perhaps we just need to think about the relations.
from sea-orm.
I've created a PR for this #122
If @nappa85 's version is preferred thats fine with me, just thought I'd share the work as a PR in case it can be used or to share any thoughts.
Let me know what you guys think
from sea-orm.
The problem here is the Entity requires an associated Relation
type:
impl EntityTrait for Entity {
type Model = Model;
type Column = Column;
type PrimaryKey = PrimaryKey;
type Relation = Relation;
}
May be, it's possible for sea_orm to define a NoRelation
enum so Entities with no relation can use that
#[sea_orm(table_name = "posts", no_relation)]
As for ActiveModelBehavior, yes it can already be impl automatically by the DeriveActiveModelBehavior
macro.
from sea-orm.
I'm still thinking deeply about this.
I am sorry @acidic9 but it seems to be a bit off topic for this thread, can you move that post to a new thread and we'll continue discussion there?
from sea-orm.
Thank you everyone for everything!
I am now working on it. Hopefully will have something out soon.
from sea-orm.
I am thinking, whether DeriveEntityModel should automatically derive DeriveModel and DeriveActiveModel, to make it less verbose.
@billy1624 can you help a bit on this?
from sea-orm.
Ah yea you did the same as I explained haha, just call the function directly.
from sea-orm.
This is crazy loll
Yeah, it was a really raw approach
from sea-orm.
Our current
DeriveRelation
is quite 'copy & paste' now.I am thinking if instead of
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { #[sea_orm( belongs_to = "super::bakery::Entity", from = "Column::BakeryId", to = "super::bakery::Column::Id", on_update = "Cascade", on_delete = "Cascade" )] Bakery, }we do
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { #[sea_orm( belongs_to = "bakery", from = "bakery_id", to = "bakery.id", on_update = "cascade", on_delete = "cascade" )] Bakery, }But is this 'too much'?
I think it's becoming too much magic, what if the other entity isn't on the the parent module but it's on another crate?
The first version is better, more explicit
from sea-orm.
I haven't thought of this before, but I think I can agree with you somewhat.
For example, Entity
, Model
, Column
, PrimaryKey
, PrimaryKeyTrait
& ColumnTrait
could be combined into a single struct definition with derives or a single SeaORM
derive.
From:
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
pub struct Entity;
impl EntityName for Entity {
fn schema_name(&self) -> Option<&str> {
Some("public")
}
fn table_name(&self) -> &str {
"users"
}
}
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
pub struct Model {
pub id: Uuid,
pub created_at: DateTimeWithTimeZone,
pub updated_at: DateTimeWithTimeZone,
pub username: String,
pub password: String,
pub email: Option<String>,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
pub enum Column {
Id,
CreatedAt,
UpdatedAt,
Username,
Password,
Email,
}
#[derive(Copy, std::clone::Clone, std::fmt::Debug, EnumIter, DerivePrimaryKey)]
pub enum PrimaryKey {
Id,
}
impl PrimaryKeyTrait for PrimaryKey {
fn auto_increment() -> bool {
false
}
}
#[derive(Copy, Clone, Debug, EnumIter)]
pub enum Relation {}
impl ColumnTrait for Column {
type EntityName = Entity;
fn def(&self) -> ColumnDef {
match self {
Self::Id => ColumnType::Uuid.def(),
Self::CreatedAt => ColumnType::Timestamp.def(),
Self::UpdatedAt => ColumnType::Timestamp.def(),
Self::Username => ColumnType::String(None).def(),
Self::Password => ColumnType::String(None).def(),
Self::Email => ColumnType::String(None).def().null(),
}
}
}
Into:
#[derive(Clone, Debug, PartialEq, SeaORM)]
#[schema_name = "public"]
#[table_name = "coupons"]
pub struct Model {
#[primary_key]
#[auto_increment = false]
pub id: Uuid,
pub created_at: DateTimeWithTimeZone,
pub updated_at: DateTimeWithTimeZone,
pub username: String,
pub password: String,
pub email: Option<String>,
}
I think this wouldn't be too hard as a lot of information could be inferred from the struct.
For example:
- If a field is an
Option<T>
, then.null()
would be added in theColumnTrait
- The Column enum could be generated from the model's fields
Obviously with this comes a lack of customizability. But this could be solved by allowing manual implementations where needed perhaps?
from sea-orm.
Thank you for your interest. I will first talk about the original ideas and choices, and may add more thoughts on later post.
The first thing is, I do not want to invent any DSL or a custom syntax or semantics. It will definitely be much less verbose, but it will be hard to understand and reason about, and people don't want to learn a new micro-language. Sooner or later, someone will have a need to customise the behaviour and hack the thing, and it will be much easier to do so in the plain Rust language.
(Just a small use case, how can I dynamically remap the table name based on environment variables?)
If there are tricks to reduce the verbosity of the Entity file without countering the above, I'll definitely adopt.
A lesser motivation would be code completion. List out the essential symbols and traits will be helpful.
But after all it is about how much information we want to present on plain sight. Too much it is hard to digest, too little it will be hard to see-through.
from sea-orm.
I also think that having to use both CamelCase and snake_case when referring to attributes is slightly awkward.
Is it better or worse if we break the Rust convention and use snake_case enums?
from sea-orm.
I don't think so honestly, I think keeping the enum as CamelCase... and just renaming it through the derive macro. And the derive macro would just generate an implementation of std::string::ToString
from sea-orm.
Serde is a brilliant library and there is definitely a lot to learn and borrow from.
Yes I would prefer to have a more compact form, as long as it is compatible with the longer form.
And that the derive macro should not do too much magic other than providing syntax sugars.
from sea-orm.
Also, it'd be better if we settle on a 'base format' first, and versions afterwards to be backward compatible.
That way, we can incrementally release enhancements towards the 'short format', while the codegen can maintain the capability to generate both formats.
from sea-orm.
I've put together a minimal impl, have a look https://github.com/nappa85/sea-orm-macro/
Inside tests there is a working example.
Sure there is space for improvement, but it can be a starting point
Wow thank you for the quick update. Looks great so far. I was just thinking how to name it (lol) perhaps, AutoEntity
, EntityDef
, or simply Entity
?
from sea-orm.
Wow thank you for the quick update. Looks great so far. I was just thinking how to name it (lol) perhaps,
AutoEntity
,EntityDef
, or simplyEntity
?
I've named it AutoColumn because it's main purpose is to generate Column from Model, but it generates optionally also Entity and PrimaryKey, so maybe a more generic AutoDef?
from sea-orm.
Yeah AutoDef
sounds good too.
from sea-orm.
I feel like AutoDef
is a little ambiguous. For example, serde just has Serialize
and Deserialize
. I like the sound of Schema
or Entity
or Table
from sea-orm.
Well, Entity
is the most almighty I guess.
from sea-orm.
@nappa85 we are releasing 0.2.0
soon.
Since you were working on this, do you think you will be able to contribute a bit in the coming month?
Such that we may incorporate and release in 0.3.0
from sea-orm.
Yes, if you let me know what you want me to edit, I'll do it ASAP
Here we discussed only the derive macro name
from sea-orm.
@tyt2y3 I spent most of my day yesterday and today creating a PR for this too. It's at a working stage, just need the columntrait to be generated too.
I'll create the PR in a few hours!
Thank you. After 0.2.0 we will make our focus on this matter, with 0.3.0 on the horizon of early Oct.
from sea-orm.
Yes, if you let me know what you want me to edit, I'll do it ASAP
Here we discussed only the derive macro name
Great, good to know. Thank you for the suggestion and everything up to now.
from sea-orm.
I've created a PR for this #122
If @nappa85 's version is preferred thats fine with me, just thought I'd share the work as a PR in case it can be used or to share any thoughts.
Let me know what you guys think
Thank you so much for the big PR. I think yours are very promising!
@nappa85 What's your view on this?
@acidic9 Can you show some more examples on the proposed format and annotation syntax (even if they are not implemented yet)?
from sea-orm.
I'm not telling my version in better than @acidic9 one, but I'm already using mine in my projects, it's almost complete, at least for my use cases, and I made almost no changes since I created it 8 days ago
from sea-orm.
@nappa85 I didn't get a chance to get an example working with your code, I'm not sure how exactly to use it. Do you think you could briefly explain what the API looks like for your version?
from sea-orm.
@nappa85 I didn't get a chance to get an example working with your code, I'm not sure how exactly to use it. Do you think you could briefly explain what the API looks like for your version?
you can find a working example in the tests folder of my repo https://github.com/nappa85/sea-orm-macro/blob/master/tests/it_works.rs
I can write some docs once we decided what has to be changed
from sea-orm.
Thank you for everyone's input here. We will think a bit and perhaps draft a design document.
from sea-orm.
I've wrote a little readme to better explain the proc macro: https://github.com/nappa85/sea-orm-macro/blob/master/README.md
from sea-orm.
I've wrote a little readme to better explain the proc macro: https://github.com/nappa85/sea-orm-macro/blob/master/README.md
Thank you, this is extremely helpful!
from sea-orm.
Borrowing ideas from #122,
I think we can enhance the DeriveEntity macro:
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
#[sea_orm(schema_name = "public", table_name = "posts")]
pub struct Entity;
This will generate also the following:
impl EntityName for Entity {
fn schema_name(&self) -> Option<&str> {
Some("public")
}
fn table_name(&self) -> &str {
"posts"
}
}
This design, I think, will decouple the InsertModel
(SimpleInput
) / UpdateModel
(SimpleUpdate
) problem.
from sea-orm.
I like what you've descirbed here @tyt2y3.
The sea-orm-cli generates also:
impl RelationTrait for Relation {
fn def(&self) -> RelationDef {
match self {
_ => panic!("No RelationDef"),
}
}
}
And
impl ActiveModelBehavior for ActiveModel {}
Are these necessary? And should they be expanded from a derive macro also, or manually implemented?
If a table has no relation def, perhaps instead of the panic it should just not implement it? I've seen a few places where panics in the SeaORM source code could be replaced with error types or just adjustments to the types to ensure these are not possible at compile time.
from sea-orm.
Relations
Similarly, we might also be able to simplify Relation definition a bit:
#[derive(EntityRelation)]
pub enum Relation {
#[sea_orm(belongs_to = "super::cake::Entity", from = "Column::CakeId", to = "super::cake::Column::Id")]
Cake,
}
auto generate the following:
impl RelationTrait for Relation {
fn def(&self) -> RelationDef {
match self {
Self::Cake => Entity::belongs_to(super::cake::Entity)
.from(Column::CakeId)
.to(super::cake::Column::Id)
.into(),
}
}
}
from sea-orm.
@nappa85 what's your thought on the proposed design so far?
(may be we should name the macro DeriveEntityModel
to keep the convention with other macros)
from sea-orm.
I've just read everything and I have no objections (aka "looks dope man!").
I've read in another issue (but actually I can't find it) about the ability to generate more than one Relation with the same Entity, maybe we should integrate that too, I've felt this limitation myself
To give an example, just think about a binary tree, you have left and right that are the same Entity, so you'll have
struct Model {
id: u64,
left: u64,
right: u64,
}
enum Relation {
Left,
Right,
}
impl RelationTrait for Relation {
fn def(&self) -> RelationDef {
match self {
Relation::Left => Entity::belongs_to(Entity)
.from(Column::Left)
.to(Column::Id)
.into(),
Relation::Right => Entity::belongs_to(Entity)
.from(Column::Right)
.to(Column::Id)
.into(),
}
}
}
impl Related<Entity> for Entity {
fn to() -> RelationDef {
Relation::Left.def()
}
}
// ERROR conflicting impl for Related<Entity>
impl Related<Entity> for Entity {
fn to() -> RelationDef {
Relation::Right.def()
}
}
from sea-orm.
@nappa85
That issue is #89, and basically the Linked
trait has been introduced in 0.2.0
Can you open a PR with what you have got in sea-orm-macros for now, so we can work together?
from sea-orm.
Can you open a PR with what you have got in sea-orm-macros for now, so we can work together?
Sure, give me a moment
from sea-orm.
Ok, I've created #128
from sea-orm.
That said, 3 more methods will be added:
fn default_value(self, v: V) where V: IntoValue { ... } fn default_expr(self, expr: &str) { ... } fn nullable(self) { ... }
Here you talk about adding those methods, are those already been added?
from sea-orm.
That said, 3 more methods will be added:
fn default_value(self, v: V) where V: IntoValue { ... } fn default_expr(self, expr: &str) { ... } fn nullable(self) { ... }Here you talk about adding those methods, are those already been added?
Not yet added.
from sea-orm.
@tyt2y3 @billy1624 @nappa85 Please see my updated PR #122.
I've updated the whole thing to match the specs listed here, with few changes such as the attribute being #[sea( ... )]
instead of #[sea_orm( ... )]
.
Please take a look and let me know your thoughts, I've explained in detail every change made in the PR :)
from sea-orm.
That said, 3 more methods will be added:
fn default_value(self, v: V) where V: IntoValue { ... } fn default_expr(self, expr: &str) { ... } fn nullable(self) { ... }Here you talk about adding those methods, are those already been added?
Not yet added.
Although, there already exists: .unique()
, .null()
, .indexed()
right?
from sea-orm.
@tyt2y3 @billy1624 @nappa85 Please see my updated PR #122.
Sure. I will definitely take a close look.
Although, there already exists: .unique(), .null(), .index() right?
Yes. SeaQuery already has the default_value
but not default_expr
. I think we need to update SeaQuery first.
from sea-orm.
Although, there already exists:
.unique()
,.null()
,.indexed()
right?
So is it the old null
or the new nullable
?
Just to disambiguate...
from sea-orm.
Yes, I think we should use the nullable
method for consistency.
from sea-orm.
Yes, I think we should use the
nullable
method for consistency.
Perfect, so the macro code is already aligned
from sea-orm.
I am done for today. Feel free to peek at the current status.
from sea-orm.
I am thinking, whether DeriveEntityModel should automatically derive DeriveModel and DeriveActiveModel, to make it less verbose.
from sea-orm.
I am thinking, whether DeriveEntityModel should automatically derive DeriveModel and DeriveActiveModel, to make it less verbose.
Could be a good idea
from sea-orm.
I am thinking, whether DeriveEntityModel should automatically derive DeriveModel and DeriveActiveModel, to make it less verbose.
I've made some tests about it, maybe I'm wrong, but it seems that a derive macro can't edit the original struct, to do so you need a proc-macro.
I've tried with this code, inside DeriveEntityModel macro:
attrs.push(Attribute {
pound_token: Pound(Span::call_site()),
style: AttrStyle::Outer,
bracket_token: Bracket(Span::call_site()),
path: Path {
leading_colon: None,
segments: {
let mut temp = Punctuated::new();
temp.push(PathSegment {
ident: Ident::new("derive", Span::call_site()),
arguments: PathArguments::None,
});
temp
},
},
tokens: quote! { DeriveModel, DeriveActiveModel },
});
from sea-orm.
Rather than modifying the derive attribute of the struct itself, it's probably better to just reuse the code of DeriveModel
and DeriveActiveModel
.
For example, if they both use the struct approach, then you could just call expand them directly.
struct DeriveEntityModel {
derive_model: DeriveModel,
derive_active_model: DeriveActiveModel,
...
}
impl DeriveEntityModel {
fn new(input: syn::DeriveInput) -> syn::Result<Self, Error> {
...
Ok(DeriveEntityModel {
derive_model: DeriveModel::new(input)?,
derive_active_model: DeriveActiveModel::new(input)?,
...
})
}
fn expand(&self) -> syn::Result<TokenStream> {
let expanded_derive_model = self.derive_model.expand()?;
let expanded_derive_active_model = self.derive_active_model.expand()?;
...
Ok(TokenStream::from_iter([
expanded_derive_model,
expanded_derive_active_model,
...
]))
}
}
I hope that makes sense.
from sea-orm.
Oh I just committed 54bb358 for this, feel free to comments :)
from sea-orm.
Oh I just committed 54bb358 for this, feel free to comments :)
Are we ok with the macro always deriving the other macros?
All other features, like deriving PrimaryKey, were controlled by an attribute.
from sea-orm.
sea-orm/tests/common/bakery_chain/customer.rs
Lines 5 to 11 in 9885029
@nappa85 I discovered a strange behavior. when column_type
is specified, nullable
can no longer be inferred from the Option<_>
type
So the following is correct:
#[sea_orm(column_type = "Text", nullable)]
pub notes: Option<String>,
But the following is wrong:
#[sea_orm(column_type = "Text")]
pub notes: Option<String>,
from sea-orm.
sea-orm/tests/common/bakery_chain/baker.rs
Lines 13 to 23 in 9885029
Our current DeriveRelation
is quite 'copy & paste' now.
I am thinking if instead of
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::bakery::Entity",
from = "Column::BakeryId",
to = "super::bakery::Column::Id",
on_update = "Cascade",
on_delete = "Cascade"
)]
Bakery,
}
we do
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "bakery",
from = "bakery_id",
to = "bakery.id",
on_update = "cascade",
on_delete = "cascade"
)]
Bakery,
}
But is this 'too much'?
from sea-orm.
@nappa85 I discovered a strange behavior. when
column_type
is specified,nullable
can no longer be inferred from theOption<_>
type
Yes, it's kind-of wanted, IMHO if you're specifying the type, you've to specify it entirely
from sea-orm.
I agree that it's becoming a little bit too much magic. Perhaps the entire DeriveRelation
can just be scrapped as it just implements RelationTrait
..? I think it just makes sense at this point to let the user write their own implementation of it.
from sea-orm.
Yes, it's kind-of wanted, IMHO if you're specifying the type, you've to specify it entirely
Understood
I agree that it's becoming a little bit too much magic. Perhaps the entire
DeriveRelation
can just be scrapped as it just implementsRelationTrait
..? I think it just makes sense at this point to let the user write their own implementation of it.
um... it does save a few lines and another impl block, innit?
I think it's becoming too much magic, what if the other entity isn't on the the parent module but it's on another crate?
The first version is better, more explicit
Great, then seemingly everything is set now
from sea-orm.
🎉 Released In 0.12.1 🎉
Thank you everyone for the contribution!
This feature is now available in the latest release. Now is a good time to upgrade!
Your participation is what makes us unique; your adoption is what drives us forward.
You can support SeaQL 🌊 by starring our repos, sharing our libraries and becoming a sponsor ⭐.
from sea-orm.
Related Issues (20)
- Missing primary_key attributes when generating from a DB with partitions HOT 2
- doc: code blocks looks weird in light mode HOT 7
- Incorrect Route Matching Behavior in Actix Example Code HOT 1
- no column found for name: A_
- Missing okapi support HOT 1
- Insert to mysql, can find data inserted in mysql but the method returns with Err(RecordNotFound("Failed to find inserted item")).
- Issues with tables that do not have primary/unique keys
- Insert an active model and get back the last insert id doesn't work with autoincrement
- Enum column named "model" generates code that conflicts with the struct Model
- ambiguous associated type when access Entity::Column HOT 5
- TimestampWithTimeZone returned as array
- Allow Defaulting `string_value` For ActiveEnum Based On Renaming Rules On Variants HOT 1
- transaction use probelm with state
- Sea-ORM still includes sqlx-mysql dependency even when no mysql feature is enabled
- sea-orm-migration - Compile error using most recent version of rc2 HOT 12
- Missing downward feature `runtime-tokio`. HOT 4
- Mock Auto Increment ID Not Working for Postgres Backend Complaining About Null HOT 1
- sea-orm-cli generate error HOT 1
- .money_len type creates invalid SQL HOT 1
- Compilation error when building with sqlx-sqlite and runtime-async-std-rustls HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from sea-orm.