Giter Site home page Giter Site logo

diesel-rs / diesel Goto Github PK

View Code? Open in Web Editor NEW
11.9K 105.0 992.0 53.45 MB

A safe, extensible ORM and Query Builder for Rust

Home Page: https://diesel.rs

License: Apache License 2.0

Rust 99.83% Shell 0.10% PLpgSQL 0.07%
rust query-builder orm postgresql sqlite mysql

diesel's Introduction

diesel logo

A safe, extensible ORM and Query Builder for Rust

Build Status Gitter Crates.io

API Documentation: latest release โ€“ master branch

Homepage

Diesel gets rid of the boilerplate for database interaction and eliminates runtime errors without sacrificing performance. It takes full advantage of Rust's type system to create a low overhead query builder that "feels like Rust."

Supported databases:

  1. PostgreSQL
  2. MySQL
  3. SQLite

You can configure the database backend in Cargo.toml:

[dependencies]
diesel = { version = "<version>", features = ["<postgres|mysql|sqlite>"] }

Getting Started

Find our extensive Getting Started tutorial at https://diesel.rs/guides/getting-started. Guides on more specific features are coming soon.

Getting help

If you run into problems, Diesel has a very active Gitter room. You can come ask for help at gitter.im/diesel-rs/diesel. For help with longer questions and discussion about the future of Diesel, open a discussion on GitHub Discussions.

Usage

Simple queries

Simple queries are a complete breeze. Loading all users from a database:

users::table.load(&mut connection)

Executed SQL:

SELECT * FROM users;

Loading all the posts for a user:

Post::belonging_to(user).load(&mut connection)

Executed SQL:

SELECT * FROM posts WHERE user_id = 1;

Complex queries

Diesel's powerful query builder helps you construct queries as simple or complex as you need, at zero cost.

let versions = Version::belonging_to(krate)
  .select(id)
  .order(num.desc())
  .limit(5);
let downloads = version_downloads
  .filter(date.gt(now - 90.days()))
  .filter(version_id.eq_any(versions))
  .order(date)
  .load::<Download>(&mut conn)?;

Executed SQL:

SELECT version_downloads.*
  WHERE date > (NOW() - '90 days')
    AND version_id = ANY(
      SELECT id FROM versions
        WHERE crate_id = 1
        ORDER BY num DESC
        LIMIT 5
    )
  ORDER BY date

Less boilerplate

Diesel codegen generates boilerplate for you. It lets you focus on your business logic, not mapping to and from SQL rows.

That means you can write this:

#[derive(Queryable, Selectable)]
#[diesel(table_name = downloads)]
pub struct Download {
    id: i32,
    version_id: i32,
    downloads: i32,
    counted: i32,
    date: SystemTime,
}

Instead of this without Diesel:

pub struct Download {
    id: i32,
    version_id: i32,
    downloads: i32,
    counted: i32,
    date: SystemTime,
}

impl Download {
    fn from_row(row: &Row) -> Download {
        Download {
            id: row.get("id"),
            version_id: row.get("version_id"),
            downloads: row.get("downloads"),
            counted: row.get("counted"),
            date: row.get("date"),
        }
    }
}

Inserting data

It's not just about reading data. Diesel makes it easy to use structs for new records.

#[derive(Insertable)]
#[diesel(table_name = users)]
struct NewUser<'a> {
    name: &'a str,
    hair_color: Option<&'a str>,
}

let new_users = vec![
    NewUser { name: "Sean", hair_color: Some("Black") },
    NewUser { name: "Gordon", hair_color: None },
];

insert_into(users)
    .values(&new_users)
    .execute(&mut connection);

Executed SQL:

INSERT INTO users (name, hair_color) VALUES
  ('Sean', 'Black'),
  ('Gordon', DEFAULT)

If you need data from the rows you inserted, just change execute to get_result or get_results. Diesel will take care of the rest.

let new_users = vec![
    NewUser { name: "Sean", hair_color: Some("Black") },
    NewUser { name: "Gordon", hair_color: None },
];

let inserted_users = insert_into(users)
    .values(&new_users)
    .get_results::<User>(&mut connection);

Executed SQL:

INSERT INTO users (name, hair_color) VALUES
  ('Sean', 'Black'),
  ('Gordon', DEFAULT)
  RETURNING *

Updating data

Diesel's codegen can generate several ways to update a row, letting you encapsulate your logic in the way that makes sense for your app.

Modifying a struct:

post.published = true;
post.save_changes(&mut connection);

One-off batch changes:

update(users.filter(email.like("%@spammer.com")))
    .set(banned.eq(true))
    .execute(&mut connection)

Using a struct for encapsulation:

update(Settings::belonging_to(current_user))
    .set(&settings_form)
    .execute(&mut connection)

Raw SQL

There will always be certain queries that are just easier to write as raw SQL, or can't be expressed with the query builder. Even in these cases, Diesel provides an easy to use API for writing raw SQL.

#[derive(QueryableByName)]
#[diesel(table_name = users)]
struct User {
    id: i32,
    name: String,
    organization_id: i32,
}

// Using `include_str!` allows us to keep the SQL in a
// separate file, where our editor can give us SQL specific
// syntax highlighting.
sql_query(include_str!("complex_users_by_organization.sql"))
    .bind::<Integer, _>(organization_id)
    .bind::<BigInt, _>(offset)
    .bind::<BigInt, _>(limit)
    .load::<User>(&mut conn)?;

Code of conduct

Anyone who interacts with Diesel in any space, including but not limited to this GitHub repository, must follow our code of conduct.

License

Licensed under either of these:

Contributing

Before contributing, please read the contributors guide for useful information about setting up Diesel locally, coding style and common abbreviations.

Unless you explicitly state otherwise, any contribution you intentionally submit for inclusion in the work, as defined in the Apache-2.0 license, shall be dual-licensed as above, without any additional terms or conditions.

diesel's People

Contributors

chusteven avatar coriolinus avatar czotomo avatar dbrgn avatar eijebong avatar emm avatar forest1102 avatar h-michael avatar hi-rustin avatar johntitor avatar keens avatar killercup avatar mcasper avatar mfpiccolo avatar neogenie avatar notryanb avatar omid avatar pfernie avatar pickfire avatar pksunkara avatar razican avatar sabify avatar sgrif avatar sytten avatar tako8ki avatar ten0 avatar testpersonal avatar thekuom avatar theredfish avatar weiznich avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

diesel's Issues

Relicense under dual MIT/Apache-2.0

This issue was automatically generated. Feel free to close without ceremony if
you do not agree with re-licensing or if it is not possible for other reasons.
Respond to @cmr with any questions or concerns, or pop over to
#rust-offtopic on IRC to discuss.

You're receiving this because someone (perhaps the project maintainer)
published a crates.io package with the license as "MIT" xor "Apache-2.0" and
the repository field pointing here.

TL;DR the Rust ecosystem is largely Apache-2.0. Being available under that
license is good for interoperation. The MIT license as an add-on can be nice
for GPLv2 projects to use your code.

Why?

The MIT license requires reproducing countless copies of the same copyright
header with different names in the copyright field, for every MIT library in
use. The Apache license does not have this drawback. However, this is not the
primary motivation for me creating these issues. The Apache license also has
protections from patent trolls and an explicit contribution licensing clause.
However, the Apache license is incompatible with GPLv2. This is why Rust is
dual-licensed as MIT/Apache (the "primary" license being Apache, MIT only for
GPLv2 compat), and doing so would be wise for this project. This also makes
this crate suitable for inclusion and unrestricted sharing in the Rust
standard distribution and other projects using dual MIT/Apache, such as my
personal ulterior motive, the Robigalia project.

Some ask, "Does this really apply to binary redistributions? Does MIT really
require reproducing the whole thing?" I'm not a lawyer, and I can't give legal
advice, but some Google Android apps include open source attributions using
this interpretation. Others also agree with
it
.
But, again, the copyright notice redistribution is not the primary motivation
for the dual-licensing. It's stronger protections to licensees and better
interoperation with the wider Rust ecosystem.

How?

To do this, get explicit approval from each contributor of copyrightable work
(as not all contributions qualify for copyright, due to not being a "creative
work", e.g. a typo fix) and then add the following to your README:

## License

Licensed under either of

 * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
 * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)

at your option.

### Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
additional terms or conditions.

and in your license headers, if you have them, use the following boilerplate
(based on that used in Rust):

// Copyright 2016 diesel Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

It's commonly asked whether license headers are required. I'm not comfortable
making an official recommendation either way, but the Apache license
recommends it in their appendix on how to use the license.

Be sure to add the relevant LICENSE-{MIT,APACHE} files. You can copy these
from the Rust repo for a plain-text
version.

And don't forget to update the license metadata in your Cargo.toml to:

license = "MIT OR Apache-2.0"

I'll be going through projects which agree to be relicensed and have approval
by the necessary contributors and doing this changes, so feel free to leave
the heavy lifting to me!

Contributor checkoff

To agree to relicensing, comment with :

I license past and future contributions under the dual MIT/Apache-2.0 license, allowing licensees to chose either at their option.

Or, if you're a contributor, you can check the box in this repo next to your
name. My scripts will pick this exact phrase up and check your checkbox, but
I'll come through and manually review this issue later as well.

Status of DbResult

The README shows it as the return type for insert but the source shows Result as the return type. Is the end goal to use DbResult over Result?

Add some missing common functions

We have max. We don't have min. Or avg, sum, etc. We should add these. They should not use the sql_function! macro, as they need to accept more than one argument type. min should have the same bounds as max. Others might need new bounds. I'm fine with just naming the trait something like CanBePassedToAvg or something, if there's not a good generic name. If you ever need to find the types which can be passed to a function in postgres, just open up psql and run this query:

select typname from pg_type where oid in (select proargtypes::text::oid from pg_proc where proname = 'sum');

License it!

YAQB has no license, which means you currently reserve all rights.

Documentation

This is my biggest call to action for anybody interested. While I will absolutely write all the docs if needed, I do strongly believe that the best flow for this is to have people who didn't implement something ask questions, and find usage that way, as it forces an explanation targeted at people not familiar with the framework.

This is by far the biggest blocker for 0.1, and probably the easiest way to get started. If you're interested in helping, comment here, or shoot me an email (it's on my profile). I will take as much time as is needed to explain usage.

Small questions / propositions

I have several questions/propositions regarding the current implementation:

  1. questions:
    • Row trait: to me, looking at DbRow (only struct implementing it) it looks more like a Value than an entire row ... I am not familiar with postgresql so it might be an implementation detail (to manage tuples?)
    • is_null: IMHO rust traits should not have is_null functions. Some implementations could be 100% rust and as a result can't be null. What do you think?
  2. propositions
    1. change &Vec<_> to &[_] here ... which eventually leads to not creating a Vec here
    2. rename DbResult: ending with ...Result usually means wrapping around rust Result, which is not the case. Proposition: DbOut or DbRows

Merge `Expression` with `SelectableExpression`

I'd like to make this refactoring to clean up parts of our type system. However, I can't seem to figure out how to express tuples with that refactoring, as right now a tuple of (A, B, C) can be expressed in two ways if all 3 of the inner types are nullable, it can be Nullable<(SA, SB, SC)> or (Nullable<SA>, Nullable<SB>, Nullable<SC>).

This is important for the ergonomics of left outer joins. I'd be fine with dropping the second case for joins, but we definitely cannot drop it more generally.

Support for embeded database

To make this useful for more than web-applications that are backed by a database server, for example a dektop application that needs to save some data, it would be nice to have support for at least one embedded database like sqlite, which happens to be following pgs design decisions if in doubt.

Allow selecting multiple aggregate columns

I had hoped that this would just involve adding an Aggregate marker trait, and modifying the tuple impls to allow if all members are aggregate. This causes overlap since any type could implement both NonAggregate and Aggregate. I do not think there is a way to express this currently in the type system currently, without negative bounds (or maybe specialization)

Implement codegen's type lookup in a more extensible fashion

Currently in codegen, when we're attempting to figure out the NativeSqlType to map to for a table, we do the following:

  • Is the first character of the type name an _? If so ::diesel::types::Array<{next step}>
  • ::diesel::types::{type name with capitalized first letter}

This was a wart that was the "absolute minimum that could possibly work" to get 0.1 out the door, but it's time for it to go. (And it'll be nice to get rid of ugly little hacks like https://github.com/sgrif/diesel/blob/3ab23f6d20b4405a8361726fd9212e332b599061/diesel/src/types/mod.rs#L47).

The main constraint here is that the system we replace this with is something that third party crates can hook into. I also do not want to require that the type be in scope, so we need to get the full path (::diesel::types::* is rarely in scope, and I don't want it to be).

In an ideal world, third party crates could just do something like #[diesel_type_lookup(oid = "1234")] pub struct PostGisOrSomething, but I don't think that's possible (especially with the added constraint that I want to potentially take an arbitrary function), as I don't believe that we can have mutable state as part of a compilation unit that crosses crate boundaries.

So I think the best way we can actually do this is to have a database table. This means that other crates will have to actually populate it, but we can have a macro required or a function call required from build.rs. In the simplest case this can be a table that maps oid -> path to type, and we continue to special case arrays (though based on pg_type.typcategory instead of the name). If we don't want to special case arrays, I think we end up with a metadata entry that is an array of SQL function names. Each of these functions would take a pg_type row, and return the path to the modifier and another oid if it matches, or null if it doesn't.

In either case, all of Diesel's lookups should go through this same machinery. It should not be special cased.

#[changeset_for] with postgresql arrays

While I can do this:

table! {
    foo {
        id -> Serial,
        bar -> Array<Integer>,
    }
}

#[derive(Queriable)]
struct Foo {
    bar: Vec<i32>,
}

I can't do that:

#[changeset_for(foo)]
struct Foo {
    bar: Vec<i32>,
}

Is there a way to achieve this?

Infer macros with CI

What's the recommended way of dealing with the infer_* macros and CIs? Say if you have

infer_table_from_schema!(dotenv!("DATABASE_URL"), "users");

You can create the database in a before_script with Travis, but the table still won't exist at compile time. You could obviously also create the table in the before_script section, but that feels like it would get onerous as your number of tables grows.

I realize there may be no easy way of dealing with this since it is a convenience compile-time check, just wanted to see if you had a nice way.

Remove all uses of `unwrap` from our docs

It's a terrible habit, and I agree that we shouldn't have it in our docs. I've gotten rid of a decent number recently, but I'd like to eliminate the rest in favor of try! (this will take some annoying boilerplate in our doctests, but it's probably worth it).

has_many/belongs_to breaks with an underscore

The has_many/belongs_to codegen annotations don't seem to be able to handle a table name consisting of multiple words and underscores, as it smashes all the words together when searching for the module name. The following code fails to compile:

#![feature(plugin, custom_derive)]
#![plugin(diesel_codegen)]

#[macro_use]
extern crate diesel;

fn main() {}

#[has_many(soccer_balls)]
pub struct User {
    id: i32
}

#[belongs_to(user)]
pub struct SoccerBall {
    id: i32,
    user_id: i32
}

table! {
    users {
        id -> Serial,
    }
}

table! {
    soccer_balls {
        id -> Serial,
        user_id -> Integer,
    }
}

Giving the following error:

src/main.rs:1:1: 1:1 error: failed to resolve. Use of undeclared type or module `soccerballs` [E0433]
src/main.rs:1 #![feature(plugin, custom_derive)]
              ^
src/main.rs:14:1: 14:20 note: in this expansion of #[belongs_to] (defined in src/main.rs)
src/main.rs:1:1: 1:1 help: run `rustc --explain E0433` to see a detailed explanation
src/main.rs:1:1: 1:1 error: use of undeclared type name `soccerballs::table` [E0412]
src/main.rs:1 #![feature(plugin, custom_derive)]
              ^
src/main.rs:14:1: 14:20 note: in this expansion of #[belongs_to] (defined in src/main.rs)
src/main.rs:1:1: 1:1 help: run `rustc --explain E0412` to see a detailed explanation
src/main.rs:1:1: 1:1 error: failed to resolve. Use of undeclared type or module `soccerballs` [E0433]
src/main.rs:1 #![feature(plugin, custom_derive)]
              ^
src/main.rs:14:1: 14:20 note: in this expansion of #[belongs_to] (defined in src/main.rs)
src/main.rs:1:1: 1:1 help: run `rustc --explain E0433` to see a detailed explanation
src/main.rs:1:1: 1:1 error: use of undeclared type name `soccerballs::user_id` [E0412]
src/main.rs:1 #![feature(plugin, custom_derive)]
              ^
src/main.rs:14:1: 14:20 note: in this expansion of #[belongs_to] (defined in src/main.rs)
src/main.rs:1:1: 1:1 help: run `rustc --explain E0412` to see a detailed explanation
src/main.rs:1:1: 1:1 error: failed to resolve. Use of undeclared type or module `soccerballs` [E0433]
src/main.rs:1 #![feature(plugin, custom_derive)]
              ^
src/main.rs:14:1: 14:20 note: in this expansion of #[belongs_to] (defined in src/main.rs)
src/main.rs:1:1: 1:1 help: run `rustc --explain E0433` to see a detailed explanation
src/main.rs:1:1: 1:1 error: unresolved name `soccerballs::table` [E0425]
src/main.rs:1 #![feature(plugin, custom_derive)]
              ^
src/main.rs:14:1: 14:20 note: in this expansion of #[belongs_to] (defined in src/main.rs)
src/main.rs:1:1: 1:1 help: run `rustc --explain E0425` to see a detailed explanation
src/main.rs:1:1: 1:1 error: failed to resolve. Use of undeclared type or module `soccerballs` [E0433]
src/main.rs:1 #![feature(plugin, custom_derive)]
              ^
src/main.rs:14:1: 14:20 note: in this expansion of #[belongs_to] (defined in src/main.rs)
src/main.rs:1:1: 1:1 help: run `rustc --explain E0433` to see a detailed explanation
src/main.rs:1:1: 1:1 error: unresolved name `soccerballs::user_id`. Did you mean `self.soccerballs::user_id`? [E0425]
src/main.rs:1 #![feature(plugin, custom_derive)]

// Lots more of those...

src/main.rs:14:1: 14:20 note: in this expansion of #[belongs_to] (defined in src/main.rs)
src/main.rs:1:1: 1:1 help: run `rustc --explain E0412` to see a detailed explanation
error: internal compiler error: ty_is_local invoked on unexpected type: [type error]
note: the compiler unexpectedly panicked. this is a bug.
note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports
note: run with `RUST_BACKTRACE=1` for a backtrace
thread 'rustc' panicked at 'Box<Any>', ../src/libsyntax/errors/mod.rs:469

The expansion is looking for soccerballs::table and friends, when it should be looking for soccer_balls::table and friends.

Name it!

I'm not pushing to crates.io without a name

Support composite primary keys

I believe this should be straightforward. There's a couple of things to consider

Edit: The thoughts in this comment are super outdated, and likely no longer relevant.

  • Right now Table::PrimaryKey has the constraint Column<Table=Self>. Unsure if we want to relax that to SelectableExpression, or if we want to introduce the Columns trait. We could even implement Column for tuples now if we really want to, as there's no longer any automatically added behaviors.
  • With the way our type system is set up, conn.find(&posts_tags, &(1, 1)) would be more likely to generate SELECT * FROM posts_tags WHERE (post_id, tag_id) = $1, instead of SELECT * FROM posts_tags WHERE post_id = $1 AND tag_id = $2. Might be fine for an initial implementation, but we do eventually need to solve this to support other databases.

update/set with Optional fields can lead to an SQL error

How to reproduce the bug:

#[changeset_for(foo)]
struct Foo {
    field1: i64,
    field2: Option<i16>,
    field3: i16,
}

/* ... */

update(
    foo::table.filter(foo::id.eq(&1))
).set(&Foo {
    field1: 0,
    field2: None,
    field3: 0,
}).execute(&conn).unwrap();

This yields the following error:
ERROR: syntax error at or near "field3"
LINE 1: UPDATE "foo" SET "field1" = $1"field3" = $2

It seems that there is a comma missing in the SQL output with patterns like (Something, None, ..., None, Something)

Example from README is not working

I'm trying this example from the README (added some imports from previous one with table! macro):

#![feature(custom_derive)]

#[macro_use]
extern crate diesel;

use diesel::*;

#[derive(Queriable, Debug)]
pub struct User {
    id: i32,
    name: String,
    favorite_color: Option<String>,
}

fn main() {
    let connection = Connection::establish(env!("DATABASE_URL"))
        .unwrap();
    let users: Vec<User> = users::table.load(&connection)
        .unwrap().collect();

    println!("Here are all the users in our database: {:?}", users);
}

Here's my error msg:

   Compiling try_diesel v0.1.0 (file:///home/user/rust/try_diesel)
src/main.rs:18:28: 18:40 error: failed to resolve. Use of undeclared type or module `users` [E0433]
src/main.rs:18     let users: Vec<User> = users::table.load(&connection)
                                          ^~~~~~~~~~~~
src/main.rs:18:28: 18:40 help: run `rustc --explain E0433` to see a detailed explanation
src/main.rs:18:28: 18:40 error: unresolved name `users::table` [E0425]
src/main.rs:18     let users: Vec<User> = users::table.load(&connection)
                                          ^~~~~~~~~~~~
src/main.rs:18:28: 18:40 help: run `rustc --explain E0425` to see a detailed explanation
error: aborting due to 2 previous errors
Could not compile `try_diesel`.

rustc:

rustc 1.6.0-nightly (b7845f93b 2015-11-15)
binary: rustc
commit-hash: b7845f93b54d3e45fcac94e7d7f3111aad90142f
commit-date: 2015-11-15
host: x86_64-unknown-linux-gnu
release: 1.6.0-nightly

Should we have a story for database views?

Do we need one? @derekprior you might have opinions on this. I was just thinking about this, and it might be cool (if we go the DSL migration route) to allow using the query builder DSL for constructing views, and then when the migration is run store the previous version in the schema_migrations table, to get down for free.

Queriable trait codegen breaks on explicit lifetimes

Deriving Queriable for structs with explicit lifetimes blows up with the error message:

   Compiling diesel_test v0.1.0 (file:///Users/mattcasper/code/diesel_test)
src/main.rs:28:18: 28:20 error: use of undeclared lifetime name `'a` [E0261]
src/main.rs:28     first_name: &'a str,
                                ^~
src/main.rs:25:10: 25:19 note: in this expansion of #[derive_Queriable] (defined in src/main.rs)
src/main.rs:28:18: 28:20 help: run `rustc --explain E0261` to see a detailed explanation
src/main.rs:28:18: 28:20 error: use of undeclared lifetime name `'a` [E0261]
src/main.rs:28     first_name: &'a str,
                                ^~
src/main.rs:25:10: 25:19 note: in this expansion of #[derive_Queriable] (defined in src/main.rs)
src/main.rs:28:18: 28:20 help: run `rustc --explain E0261` to see a detailed explanation
error: aborting due to 2 previous errors

for the struct

#[derive(Queriable)]
pub struct User<'a> {
    id: i32,
    first_name: &'a str,
    last_name: String,
    email: String
}

And trying to implement the trait by hand got tricky, I got stuck on what $row_type evaluates to.

Error on large table definitions

This code works:

table! {
    hello {
        id -> Serial,
        hello_a -> Integer,
        hello_b -> Integer,
        hello_c -> Integer,
        hello_d -> Integer,
        hello_e -> Integer,
        hello_f -> Integer,
        hello_g -> Integer,
        hello_h -> Integer,
        hello_i -> Integer,
        hello_j -> Integer,
        hello_k -> Integer,
        hello_l -> Integer,
        hello_m -> Integer,
        hello_n -> Integer,
        hello_o -> Integer,
    }
}

This code doesn't work:

table! {
    hello {
        id -> Serial,
        hello_a -> Integer,
        hello_b -> Integer,
        hello_c -> Integer,
        hello_d -> Integer,
        hello_e -> Integer,
        hello_f -> Integer,
        hello_g -> Integer,
        hello_h -> Integer,
        hello_i -> Integer,
        hello_j -> Integer,
        hello_k -> Integer,
        hello_l -> Integer,
        hello_m -> Integer,
        hello_n -> Integer,
        hello_o -> Integer,
        hello_p -> Integer,
    }
}

It gives this error:

<diesel macros>:16:54: 19:52 error: the trait `diesel::types::NativeSqlType` is not implemented for the type `(diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer)` [E0277]
<diesel macros>:16 out . push_identifier ( stringify ! ( $ name ) ) } } impl AsQuery for table {
<diesel macros>:17 type SqlType = SqlType ; type Query = SelectStatement < SqlType , (
<diesel macros>:18 $ ( $ column_name ) , + ) , Self > ; fn as_query ( self ) -> Self:: Query {
<diesel macros>:19 SelectStatement:: simple ( all_columns , self ) } } impl Table for table {
<diesel macros>:15:1: 17:58 note: in this expansion of table_body! (defined in <diesel macros>)
<diesel macros>:5:1: 6:2 note: in this expansion of table! (defined in <diesel macros>)
<diesel macros>:2:1: 2:64 note: in this expansion of table! (defined in <diesel macros>)
src/main.rs:50:1: 70:2 note: in this expansion of table! (defined in <diesel macros>)
<diesel macros>:16:54: 19:52 help: run `rustc --explain E0277` to see a detailed explanation
<diesel macros>:16:54: 19:52 note: required by `diesel::query_builder::AsQuery`
<diesel macros>:16:54: 19:52 error: the trait `diesel::expression::SelectableExpression<hello::table, (diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer, diesel::types::Integer)>` is not implemented for the type `(hello::columns::id, hello::columns::hello_a, hello::columns::hello_b, hello::columns::hello_c, hello::columns::hello_d, hello::columns::hello_e, hello::columns::hello_f, hello::columns::hello_g, hello::columns::hello_h, hello::columns::hello_i, hello::columns::hello_j, hello::columns::hello_k, hello::columns::hello_l, hello::columns::hello_m, hello::columns::hello_n, hello::columns::hello_o, hello::columns::hello_p)` [E0277]
<diesel macros>:16 out . push_identifier ( stringify ! ( $ name ) ) } } impl AsQuery for table {
<diesel macros>:17 type SqlType = SqlType ; type Query = SelectStatement < SqlType , (
<diesel macros>:18 $ ( $ column_name ) , + ) , Self > ; fn as_query ( self ) -> Self:: Query {
<diesel macros>:19 SelectStatement:: simple ( all_columns , self ) } } impl Table for table {
<diesel macros>:15:1: 17:58 note: in this expansion of table_body! (defined in <diesel macros>)
<diesel macros>:5:1: 6:2 note: in this expansion of table! (defined in <diesel macros>)
<diesel macros>:2:1: 2:64 note: in this expansion of table! (defined in <diesel macros>)
src/main.rs:50:1: 70:2 note: in this expansion of table! (defined in <diesel macros>)
<diesel macros>:16:54: 19:52 help: run `rustc --explain E0277` to see a detailed explanation
<diesel macros>:16:54: 19:52 note: required by `diesel::query_builder::AsQuery`
<diesel macros>:19:53: 23:45 error: the trait `diesel::expression::Expression` is not implemented for the type `(hello::columns::id, hello::columns::hello_a, hello::columns::hello_b, hello::columns::hello_c, hello::columns::hello_d, hello::columns::hello_e, hello::columns::hello_f, hello::columns::hello_g, hello::columns::hello_h, hello::columns::hello_i, hello::columns::hello_j, hello::columns::hello_k, hello::columns::hello_l, hello::columns::hello_m, hello::columns::hello_n, hello::columns::hello_o, hello::columns::hello_p)` [E0277]
<diesel macros>:19 SelectStatement:: simple ( all_columns , self ) } } impl Table for table {
<diesel macros>:20 type PrimaryKey = columns:: $ pk ; type AllColumns = ( $ ( $ column_name ) , +
<diesel macros>:21 ) ; fn name (  ) -> & 'static str { stringify ! ( $ name ) } fn primary_key (
<diesel macros>:22 & self ) -> Self:: PrimaryKey { columns:: $ pk } fn all_columns (  ) -> Self::
<diesel macros>:23 AllColumns { ( $ ( $ column_name ) , + ) } } pub mod columns {
<diesel macros>:15:1: 17:58 note: in this expansion of table_body! (defined in <diesel macros>)
<diesel macros>:5:1: 6:2 note: in this expansion of table! (defined in <diesel macros>)
<diesel macros>:2:1: 2:64 note: in this expansion of table! (defined in <diesel macros>)
src/main.rs:50:1: 70:2 note: in this expansion of table! (defined in <diesel macros>)
<diesel macros>:19:53: 23:45 help: run `rustc --explain E0277` to see a detailed explanation
error: aborting due to 3 previous errors

What is wrong? I'm pretty new on rust. ๐Ÿถ

Refactor our test suite to not be reliant on specific values for ID

As we start to get into things like schema inference and migrations, which mean we want a persistent schema for our tests, we need to stop assuming the ids 1 and 2. Even though our tests will still run in isolated transactions, inserting rows in a transaction will bump the PK counter, regardless of whether or not the transaction is committed. This is fine, but we need to make sure our suite still passes.

Unable to build using modules

I am trying to build using the latest master but a bunch of unimplemented errors now. It was working on master and when I pointed to the newest master on yaqb there was a serde compatibility issue because of quasi. I removed serde and now I am trying to get the same functionality but I am unable to compile.

I can post the code in the issue but it may just be easier to link.

Here are the two files from my try-compile branch:
https://github.com/mfpiccolo/yaqb_test/blob/try-compile/src/models/post.rs
https://github.com/mfpiccolo/yaqb_test/blob/try-compile/src/models/user.rs

Any idea why I would be getting the errors like:

error: the trait `yaqb::query_source::Queriable<(yaqb::types::Integer, yaqb::types::VarChar, yaqb::types::Nullable<yaqb::types::VarChar>)>` is not implemented for the type `models::user::User

Unable to build outside of crate

I was trying to set up another repo to play around with yaqb in another crate but I was unable to build the crate because of a cargo issue rust-lang/cargo#2064.

The error I am getting I think is due to conflicting libc's.

   Compiling yaqb v0.1.0 (file:///Users/mfpiccolo/code/mfpiccolo/yaqb_test)
/Users/mfpiccolo/code/mfpiccolo/yaqb/src/connection/mod.rs:320:23: 320:55 error: mismatched types:
 expected `*mut libc::types::common::c95::c_void`,
    found `*mut connection::libc::c_void`
(expected enum `libc::types::common::c95::c_void`,
    found enum `connection::libc::c_void`) [E0308]
/Users/mfpiccolo/code/mfpiccolo/yaqb/src/connection/mod.rs:320             PQfreemem(self.pg_str as *mut libc::c_void)

Are you able to use the crate as a dependency?

We don't handle or verify the order of the columns

We need to test for this. For example, if we have

table! {
  users {
    id -> Serial,
    name -> VarChar,
    email -> VarChar,
  }
}

There's nothing to prevent

let source = users.select((id, email, name));
connection.query_all::<User>(&source)

which would read the fields into the wrong pieces of the struct. The obvious solution is to access by the name of the fields, but then we have to figure out more concrete aliasing behavior and couple to it which I don't want. Needs further investigation.

Figure out how to allow querying values against a nullable column

I'm debating whether or not to have foo.eq(None) result in foo IS NULL or not. Either way, for ergonomics, we should allow foo.eq("bar") in addition to foo.eq(Some("bar")). At the moment, attempting to write this ToSql implementation results in overlap both with the impl for Option<T>, and for &'a T. I think we need specialization for this to work.

Clarification on `update`

So far update is the hardest to wrap my head around, and I was hoping for some clarification/guidance.

In the context of an HTTP API, with a users table that looks like:

table! {
    users {
        id -> Serial,
        first_name -> VarChar,
        last_name -> VarChar,
        email -> VarChar,
    }
}

how would you go about implementing a Users#update action?

My first instinct is to have something like:

#[changeset_for(users)]
pub struct UserChanges {
    id: i32,
    first_name: Option<String>,
    last_name: Option<String>,
    email: Option<String>,
}

fn update(req: SomeHTTPReq) -> SomeHTTPRes {
  let changeset = UserChanges {
    first_name: req.body.get("first_name"),
    // etc
  }

  changeset.save_changes(&connection)
}

Such that you end up updating whatever valid params the user sends, but that requires having Nullable columns in the table macro, when the columns aren't actually nullable.

Keep up all the great work!

Add `is_null` and `is_not_null` to `Expression`

Documenting in case anyone out there happens to want to get involved, these should be easy to add. We need a trivial test case for this. "users"."hair_color" is nullable in our normal schema.

JSON data type

So let's talk borderline absurd features. I'm trying to figure out how we can support this type, while still being useful. I feel like this is harder to do than in dynamic languages where we're just an arbitrary map or array. However, I think we can do something moderately useful with serde integration (I am unsure if this should be in core, or a separate trait)

However, I am fairly convinced that we can do impl<T> ToSql<Json> for T where T: serde::ser::Serialize and impl<T> FromSql<Json> for T where T: serde::de::Deserialize (note: As written, those two almost certainly require specialization. We can work around this with boilerplate macros to implement for individual types in the short term).

The following operators exist for the JSON data types:

  • ->: Query DSL should just implement Index for Json expressions. Output should be Expression<SqlType=Json>. We might need to do some hackery since Index requires returning a reference. A Copy constraint will likely be involved as well. Might need to be a method if we really can't work with Index, but boy it would be amazing to write filter(json_column["foo"].eq("bar"))
  • ->>: Unsure if we should support. If so, will need to be a method. Unclear on the right name.
  • #>: Unsupported
  • #>>: Unsupported
  • @>: Implemented as method contains. Argument should be AsExpression<Json>, return type is Bool`
  • <@: Unsupported
  • ?: Implemented as method has_key. Argument should be AsExpression<VarChar>, return type is Bool
  • ?| and ?&: Same as above. Don't have an opinion on the method names.

We should also support as many functions as possible from http://www.postgresql.org/docs/9.4/static/functions-json.html. As I write this, I'm fairly convinced this should be a separate crate. If anyone wants to tackle this, let me know and I'll add a new repo for it. I do want this to be supported under the general Diesel umbrella though, even if it's not in the core crate.

#[changeset_for] codegen issue

Trying to use #[changeset_for] for the struct:

#[changeset_for(users)]
pub struct UserChanges {
    id: i32,
    first_name: Option<String>,
    last_name: Option<String>,
    email: Option<String>,
}

Produces the error:

src/main.rs:33:24: 33:24 error: the trait `diesel::query_source::Queriable<(diesel::types::Integer, diesel::types::VarChar, diesel::types::VarChar, diesel::types::VarChar)>` is not implemented for the type `UserChanges` [E0277]
src/main.rs:33 #[changeset_for(users)]
                                      ^
src/main.rs:33:1: 33:24 note: in this expansion of try! (defined in <std macros>)
src/main.rs:33:24: 33:24 help: run `rustc --explain E0277` to see a detailed explanation
error: aborting due to previous error

However, adding #[derive(Queriable)] to the struct annotation raises the error:

src/main.rs:34:24: 34:24 error: the trait `diesel::types::FromSqlRow<(diesel::types::Integer, diesel::types::VarChar, diesel::types::VarChar, diesel::types::VarChar)>` is not implemented for the type `(i32, core::option::Option<collections::string::String>, core::option::Option<collections::string::String>, core::option::Option<collections::string::String>)` [E0277]
src/main.rs:34 #[changeset_for(users)]
                                      ^
src/main.rs:34:1: 34:24 note: in this expansion of try! (defined in <std macros>)
src/main.rs:34:24: 34:24 help: run `rustc --explain E0277` to see a detailed explanation
error: aborting due to previous error

Halp

Implement diesel Expression for more types

error: the trait `diesel::expression::Expression` is not implemented for the type `u64` 

I got this error.
I solved it with this:

let game = games.filter(id.eq(params.find("id").unwrap().as_u64().unwrap() as i32 )).first(&connection);

This is a bit ugly. Could there be more types supported than just i32?
Any other suggestion than moving this cast to a function?

Generate table by deriving Queriable

In issue #36 I was trying to get example with #[derive(Queriable)] to work and one of the things that confused me is that you still have to make a table! call and hand-write all the column types.
Here I'm proposing to make Queriable smart enough to generate appropriate table stuff or even table! call so you won't have to do it manually. For some cases you might want to manually set the type of the column, e.g

#[derive(Queriable, Debug)]
pub struct User {
    #[column_type = Serial]
    id: i32,
    #[column_type = VarChar]
    name: String,
}

P.S @sgrif thanks for all the great work you've done! I'm very excited about query builder/ORM in Rust.

#insert error: unable to infer enough type information about `_`

@sgrif I am setting up a simple server with yaqb and I am running into a problem with insert that I cannot get past. I ultimately keep running into this error when trying to use insert with a NewUser struct.

src/models/user.rs:41:10: 41:49 error: unable to infer enough type information about `_`; type annotations or generic parameter binding required [E0282]
src/models/user.rs:41     conn.insert(&self::users::table, &new_users);

If I switch to insert_returning_count it works fine.

Here is the line causing the error:

https://github.com/mfpiccolo/yaqb_test/blob/master/src/models/user.rs#L40

The `changeset` macro should be a compiler annotation

Documenting in case anyone wants to get involved. This is the last macro being invoked from our integration tests that needs to go away for 0.1 I intend for this to be #[can_update="users"]. This annotation should basically do what the macro does today, including all columns, but should specifically exclude the primary key of the table from the changeset.

As part of this, I think we should group all our non-derive annotations into a single namespace with each just being a key/value pair. e.g. #[yaqb(inserable_into("users"), can_update("users"))]. That change should affect #[column_name] as well. That can be a separate PR that pre-dates this change, part of this change, or just not done at all. It's not a 0.1 blocker.

debug_sql!

It would be really great if you could debug sql commands at compile time. Something like:

debug_sql!(users.filter(id.eq(1));

would output:

SELECT * FROM users WHERE id = 1

Or:

debug_sql!(update(users::table.filter(id.eq(id))).set(changed_user));

prints to console:

UPDATE "users" SET "name" = $1, "email" = $2 WHERE "users"."id" = $3 RETURNING "users"."id", "users"."name", "users"."email"

`insert` is inconsistent, and should be changed to match other operations

This is just an artifact of the fact that I implemented this before everything other than the most basic forms of select. This should be changed to match update and delete. This is the API I'm imagining:

insert_into(table).values(records)

This would return a command that can be used in the same way the return values of update and delete, which will be less painful with #29.

Since this represents a breaking change in one of the most common APIs, we should do this sooner rather than later.

Schema inference fails on array columns

This is due to the (very naive) type lookup that we do right now. The name of a string array in Postgres is _varchar. We need to be much more sophisticated.

MySQL support in 0.x

I've read you are going to add support of other databases only after 1.0, but differences between Postgre and MySQL are not so big, so please consider to support MySQL in 0.x. Then it will be well-tested for 1.0 :)

#[has_many(posts)] multiple applicable items in scope

Using #[has_many(posts)] on a User struct throws this error:

src/models/user.rs:12:19: 12:19 error: multiple applicable items in scope [E0034]
src/models/user.rs:12 #[has_many(posts)]
                                        ^
src/models/user.rs:12:1: 12:19 note: in this expansion of #[has_many] (defined in src/models/user.rs)
src/models/user.rs:12:19: 12:19 help: run `rustc --explain E0034` to see a detailed explanation
src/models/user.rs:12:19: 12:19 note: candidate #1 is defined in an impl of the trait `diesel::expression::Expression` for the type `diesel::expression::predicates::Eq<_, _>`
src/models/user.rs:12 #[has_many(posts)]
                                        ^
src/models/user.rs:12:1: 12:19 note: in this expansion of #[has_many] (defined in src/models/user.rs)
src/models/user.rs:12:19: 12:19 note: candidate #2 is defined in an impl of the trait `diesel::query_builder::update_statement::changeset::Changeset` for the type `diesel::expression::predicates::Eq<_, _>`
src/models/user.rs:12 #[has_many(posts)]
                                        ^
src/models/user.rs:12:1: 12:19 note: in this expansion of #[has_many] (defined in src/models/user.rs)
src/models/user.rs:12:19: 12:19 note: candidate #3 is defined in an impl of the trait `diesel::expression::Expression` for the type `&_`
src/models/user.rs:12 #[has_many(posts)]
                                        ^
src/models/user.rs:12:1: 12:19 note: in this expansion of #[has_many] (defined in src/models/user.rs)
src/models/user.rs:12:19: 12:19 note: candidate #4 is defined in an impl of the trait `diesel::query_builder::QueryFragment` for the type `_`
src/models/user.rs:12 #[has_many(posts)]
                                        ^
src/models/user.rs:12:1: 12:19 note: in this expansion of #[has_many] (defined in src/models/user.rs)
error: aborting due to previous error

Figure out migrations and persistent schema

These are both blockers in my mind. As with rails, the schema file should be auto generated, but I would like to have a usage story that doesn't require a DSL for every possible database feature. In my mind this was going to be Schema.toml, but I think this might just end up being structure.sql from Rails. The main benefit of schema.rb over structure.sql in the Rails world is that the former is often easier to solve merge conflicts for. This is not an issue for 0.1, or really 0.x, as it's easy to work around, but we need to figure out our story for this

Get core working on stable and beta

This does not include the codegen or integration test crates. This issue is tracking the fact that core only builds on nightly. This is due to the fact that the way I implemented the interval DSL requires From<i32>. I've implemented the interval dsl for i64 and f64, which only implement From<i32> on nightly. We just need to copy paste the defaulted methods. Should be straight forward.

The litmus test for this issue is the yaqb directory passing cargo test on stable. codegen and yaqb_tests do not need to pass on stable.

`connection.query_one/all` with `update` and `delete` are a bit annoying to use

It used to be the case that everything had to go through Connection#query_all and Connection#query_one. I found it was annoying, and added too many parenthesis, which is why load and first were added. (connection.query_all(users.filter(name.eq("Sean"))) vs users.filter(name.eq("Sean")).load(&connection).

I want to give the same treatment to these (technically load actually works fine, but I think that update(users.filter(id.eq(1))).set(name.eq("Sean")).load(&connection) reads really strangely). We should add some new methods (the names are up for debate):

  • run(&connection): We often know that we will return exactly one row. The should return QueryResult<T>, and will basically be load(&connection).map(|mut r| r.nth(0).unwrap()).
  • run_all(&connection): Alias for load. Probably a better name for this, but I want it to imply that we're doing a command that happens to return.
  • execute(&connection): Alias for Connection#execute_returning_count

TODO

Note: All items should be implemented in a way that works on stable rust, unless otherwise specified. Compiler plugins are probably the most preferable for codegen, but we'll see what's possible.

  • Insert
    • type safe API for inserting
    • returning new values
    • type signature verifying no constraints are violated
      • null in not null (e.g. not including a column in the query, when the column has no default)
      • foreign key violations (Within reason. Maybe newtype up serial columns)
  • Update
    • type safe API for updating
    • returning new values
    • type signature verifying no constraints are violated
  • Select
    • type safe API for simple usage
    • ^---- Revisit that once we flesh out where
    • Types that fully understand logical rules for aggregation
      • Disallow selecting a non-aggregate and aggregate without group by
      • Allow selecting multiple aggregates without group by
      • Disallow selecting non-aggregate with group by
      • Disallow selecting non-aggregate and aggregate with group by (presumably this is free)
      • Allow selecting grouped columns
      • Allow selecting grouped columns and aggregate functions with group by
    • unsafe API for arbitrary SQL
    • CODEGEN: type safe API for arbitrary SQL Not 0.1
  • From
    • type safe API for single tables
    • type safe API for inner joins
    • type safe API for left joins
    • type safe API for right joins
    • ability to query more than two tables (should in theory be the same code for all join types)
    • type safe API for one to many associations
    • type safe API for optional one to one associations
    • type safe API for required one to one associations (must differentiate at the type level)
    • join clauses with complex ON
    • unsafe API for arbitrary SQL
    • CODEGEN: type safe API for arbitrary SQL (is this actually needed?) Not 0.1
  • Where
    • type safe API for most usage (macros allowed, but still needs stable)
      • ensure all referenced columns are on a table being selected
      • equality
      • inequality
      • numeric comparison operators
      • string comparison operators (e.g. LIKE)
      • in I don't think we need to support IN statements, since we have = ANY
      • audit any other reasonably generic kinds to handle in a DSL
      • consider support for complex data type queries (array, json, etc)
        • Would be cool to do things like filter(json_col["foo"].eq("bar")), might be hard to support arbitrary data types.
      • IS NULL (does this need to be separate from equality?)
        • Yes, it should be, which also means we need special handling for optional RHS. I want to write thing.eq("foo"), not thing.eq(Some("foo")), which means the pattern for AR style equality will look like:
        • match value {
            Some(x) => thing.eq(x),
            None => thing.is_null(),
          }
    • unsafe API for arbitrary SQL
    • CODEGEN: type safe API for arbitrary SQL Not 0.1
  • Having
    • type safe API allowing predicates with arbitrary aggregate expressions (0.2)
    • unsafe API for arbitrary SQL
    • Maybe? CODEGEN: type safe API for arbitrary SQL Not 0.1
  • Limit, Offset, etc
    • type safe API
  • Order
    • type safe API
    • unsafe API for arbitrary SQL
  • Anything else we think we need for 0.1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.