wovalle / fireorm Goto Github PK
View Code? Open in Web Editor NEWORM for firestore 🔥
Home Page: https://fireorm.js.org
License: MIT License
ORM for firestore 🔥
Home Page: https://fireorm.js.org
License: MIT License
This library was meant to be used as a Firestore ORM. Right now, Google's Cloud Firestore is not supported while Firebase's Cloud Firestore is (and Firebase's Firestore is only a frontend for Google's Firestore). Update: Fireorm works with Google's Firestore! 🎉
Acceptance Criteria:
examples
) with a tiny application (maybe just copy/pasting 1- Simple todo example) and documenting how to initialize fireorm in the README file.Since implementing semantic-release in #22, every commit that land should trigger a release and we don't want to do that for each commit. We wen't ahead and created a new branch called next
that will hold the last version of the code, and doing pull-requests to master will trigger releases.
AC:
You can access SubCollections of collections initialized by find
or findById
, but if you try to access Subcollections of collections initialized by create
it will result in an error.
Subcollections are initialized by extractTFromDocSnap and that method is not being called when the document is created by BaseFirestoreRepository Create method.
class Message {
id: string;
text: string;
date: Date;
}
@Collection()
class User {
id: string;
@SubCollection(Message)
messages?: ISubCollection<Message>
}
const userRepository = GetRepository(User);
const user = new User();
user.id = 'test';
const createdUser = await userRepository.create(user);
await createdUser.messages.find() // will result in an error because `messages` subcollection was not initialized
Create
methodTo be able to query SubCollections of an entity, the entity must contain at least one field in firestore (without counting the subcollection).
Because Fireorm is using firestore-admin's collection.get(id) to get the User
collection and it returns ``collection.exist === false``` for collections that doesn't contain any fields
class Message {
id: string;
text: string;
date: Date;
}
@Collection()
class User {
id: string;
@SubCollection(Message)
messages?: ISubCollection<Message>
}
const userRepository = GetRepository(User);
const user = await userRepository.findById('id');
const messages = await user.messages.find();
/*
if `user` doesn't contain any fields, firestore-admin will set user.exists = false
and subcollections won't be initialized due to this line: https://github.com/wovalle/fireorm/blob/master/src/BaseFirestoreRepository.ts#L60-L62
*/
Note: for collections created with fireorm, this won't ever happen since fireorm's automatically set's an id
field to every document.
Hello, how can I create a new ProdutorDadosAdicionais with a referencied property produtor of Produtor class?
@Collection()
export class Produtor {
id: string
nome?: string;
}
@Collection()
export class ProdutorDadosAdicionais {
id: string;
nome: string;
produtor: Produtor;
}
I tried this, but no gave me a error:
let doc = new ProdutorDadosAdicionais();
doc.nome = "Teste";
doc.produtor = await prod.findById("ITXaj7Gss5dt1cOpT0qf");
await repo.create(doc);
I'm interested in working on the limit
feature , as mentioned by the 1.0 Roadmap.
Firestore supports some pagination cursors such as startAt
, endAt
and startAfter
(the use of offset is uncouraged by google.
I find the naming confusing and non-generic. Let's use this issue to discuss how an implementation of those function would look like in fireorm and from there create issues to do the actual implementation
There seems to be a mixture of camel case and pascal case used for functions across the project. Not sure if there's a reason for this? Classes all seem to be pascal case but then functions mix the two, which is confusing to use!
When running example 1, I get this error:
Error: Value for argument "documentPath" is not a valid resource path. Path must be a non-empty string.
at Object.validateResourcePath (/Users/nathanjones/Projects/fireorm/node_modules/@google-cloud/firestore/build/src/path.js:407:15)
at CollectionReference.doc (/Users/nathanjones/Projects/fireorm/node_modules/@google-cloud/firestore/build/src/reference.js:1724:20)
at BaseFirestoreRepository.<anonymous> (/Users/nathanjones/Projects/fireorm/src/BaseFirestoreRepository.ts:161:38)
at step (/Users/nathanjones/Projects/fireorm/src/BaseFirestoreRepository.ts:56:23)
at Object.next (/Users/nathanjones/Projects/fireorm/src/BaseFirestoreRepository.ts:37:53)
at /Users/nathanjones/Projects/fireorm/src/BaseFirestoreRepository.ts:31:71
at new Promise (<anonymous>)
at __awaiter (/Users/nathanjones/Projects/fireorm/src/BaseFirestoreRepository.ts:27:12)
at BaseFirestoreRepository.create (/Users/nathanjones/Projects/fireorm/src/BaseFirestoreRepository.ts:165:16)
at Object.<anonymous> (/Users/nathanjones/Projects/fireorm/examples/1-simple_todo_repository/index.ts:33:43)
This is probably due to the way fireorm creates a new doc without an id.
const doc = this.firestoreColRef.doc(item.id || undefined);
This should probably be updated to use the add()
method if the id was not provided (relevant docs)
Hi there.
Custom repository, instantiated somewhere (in another file) apart from it's declaration, does not work. I mean, his custom methods (not inherited from BaseFirestoreRepository
) don't work (got error "CustomeRepository.customMethod is not a funcytion")
This happens because @CustomRepository()
decorator is not invoked in this case.
Also, we have GetCustomRepository()
function, but it is not used (even in examples). How can we use it?
This project is being used in several production apps. It's time to actually use a real Firestore db to ensure we don't break anything on each release 😄
Acceptance Criteria:
Recently got my first contribution from external sources, is only fair to recognise the hard work of everybody
AC:
FireORM requires that my collection class's constructor have no parameters, so I can't pass in the data needed to initialize the class. This means that I have to add the 'undefined' type to all my class attributes, and initialize them after the class has been created, otherwise TS will complain (assuming TS strict mode).
But 'undefined' is an invalid value in the datastore. If an entity doesn't have a value for an attribute it needs to set it to null, not undefined, so I have to add null as a valid type for each non-mandatory attribute too.
But even then, those attributes get written to the DS (with value 'null') so the potential to save storage by omitting unused values is lost.
Have I got this right?
If I do, here are some thoughts/suggestions... would it be possible for
Fireorm to allow constructor parameters? (The parameters would be undefined when the constructor is invoked by fireform and the constructor implementation would have to handle that.)
for undefined values to not be written to the datastore (rather than causing an error). BTW, the error message I got for this was very informative - thanks!.
Hi,
First of all thank you soo much for this framework and the documentation is really good as well.
But one example I am unable to find is inserting a 'Subcollection'.
Can you please provide one?
Thank you
Since I'm the only developer working in FireORM at the moment, I use this issue to track what to do with this project :)
Collaborations are welcome! If you want to start working on a feature that is listed below, please create another issue to start the discussion. This issue is only meant to be used as a placeholder.
Fireorm's .find
always return an array of elements (even if only one document matches the query), but there are situations when we want to do a query and just take the first result. We could do something in the line of (await query.limit(1).find())[0]
but that's cumbersome and prone to error.
Implement a findOne
function in fireorm repositories to support this use case.
Acceptance Criteria:
findOne
in IQueryBuilder
execute
in IQueryExecutor
to receive a single: bool
propAbstractFirestoreRepository
and BatchFirestoreRepository
to implement the new functionsimple_repository
fileWhen trying to find the collection with various other attributes, the id inside the collection is not being populated.
In the "1-simple_todo_repository" when added the following code.
const todoText = 'my super todo';
const myAnotherSuperTodo: Todo[] = await todoRepository.whereEqualTo('text' as 'id', todoText).find();
console.log('Got todo with name ', todoText);
console.table(myAnotherSuperTodo);
The o/p that I am getting is
| (index) │ text │ done │
│ 0 │ 'my super todo' │ false │
│ 1 │ 'my super todo' │ false │
Where as the actual expected output is
| (index) │ text │ done │ id |
│ 0 │ 'my super todo' │ false │ idGeneratedByFirebase |
│ 1 │ 'my super todo' │ false │ idGeneratedByFirebase |
Thank you,
Giridhar.D
This repo uses semantic release to release to npm and github releases. The API documentation is hosted in github pages and is rdeployed using gh-pages-deploy
package (see deploy:documentation
script in package.json
).
Right now we have a bug in which each merge pull request (to a non-release branch, like next
) is triggering a deploy of the documentation. Instead of fixing that issue, let's release the documentation with the same tool we release our npm package.
Acceptance criteria:
gh-pages-deploy
from the projectIn firestore you can pass a document reference to a where method as the value in order to query by references tied to documents. If we had a collection of todos and each document had a user reference tied to it who owned the todo, I might write something like this.
todoCollection.where("user", "==", userRef).get();
Per our discussion of Twitter, it seems that this should be as simple as updating the typings and writing some tests.
Hi,
Iam getting the following error when upgraded to 0.6.2 from 0.6.0
"Error:Argument "documentPath" is not a valid ResourcePath. Path must be a non-empty
string"
When I searched more about the root cause I found the below link, in which the solution being provided is
admin.firestore().collection('whatever').doc(""+id);
firebase/firebase-admin-node#320
When I rolled back to 0.6.0 application is working as expected.
Is this an issue? or should I change anything in my code ?
Thank you,
Giridhar Duggirala
First off - this has been a great experience! Thanks for building fireorm. Has anyone had experience with testing/mocking a repository? Could we add a mock repository type? Currently trying to use this in my app and am unable to run tests that import Collection
annotated models.
Is there currently any way to run transactions or batched writes across multiple collections?
Take the following example: when a user deletes their account, any posts that they have made should also be deleted.
The way FireORM currently stands, it looks like there would need to be multiple transactions.
Is there a general rule on how to do this? Would the transactions be nested? Would a nested transaction still succeed and make writes if the parent failed?
I know that there is a plan to add relationship support to Fireorm (#32), however I noticed that adding a reference to a document causes an error.
I copied the example from this Medium article as follows which works fine:
@Collection()
class Band {
id!: string;
name!: string;
formationYear!: number;
genres!: Array<string>;
}
// Create a band
const band = new Band();
band.name = "A Perfect Circle";
band.formationYear = 1999;
band.genres = ['alternative-rock', 'hard-rock']
const bandDocument = await bandRepository.create(band);
console.log(`Created band with id: ${band.id}`);
As soon as I go into the Firebase Console, locate this document and then add a new field which is a reference to another collection I get the following error:
TypeError: Cannot read property '_settings' of undefined
at new Serializer (/node_modules/@google-cloud/firestore/build/src/serializer.js:46:23)
at TransformOperationExecutor.transform
Is this right, or is there any easy way to fix it? I have an existing Firestore database that contains references so I need Fireorm to fail gracefully with references until it's fully supported.
P.S I assume you are using TypeORM as a reference for adding entity relations?
I am having an issue with the latest version since class-transformer was introduced. I have a document that has a GeoPoiont field. Whenever I try to read one of these documents, I get the following error message.
Error: Value for argument "latitude" is not a valid number.
Stack Trace:
[1] > at TransformOperationExecutor.transform (C:\MaxxInnova\workspaces\pilotcar\node_modules\fireorm\node_modules\class-transformer\TransformOperationExecutor.js:260:17)
[1] > at ClassTransformer.plainToClass (C:\MaxxInnova\workspaces\pilotcar\node_modules\fireorm\node_modules\class-transformer\ClassTransformer.js:17:25)
[1] > at Object.plainToClass (C:\MaxxInnova\workspaces\pilotcar\node_modules\fireorm\node_modules\class-transformer\index.js:20:29)
[1] > at BaseFirestoreRepository.extractTFromDocSnap (C:\MaxxInnova\workspaces\pilotcar\node_modules\fireorm\lib\src\BaseFirestoreRepository.js:79:46)
[1] > at Array.map ()
[1] > at BaseFirestoreRepository.extractTFromColSnap (C:\MaxxInnova\workspaces\pilotcar\node_modules\fireorm\lib\src\BaseFirestoreRepository.js:96:27)
Example:
https://github.com/dietrichwestbrooks/fireorm-geopoint
I propose that there be a mechanism by which to indicate that certain properties/attributes of a @Collection class - which would normally all get written to (and updated from) the datastore - are not intended as datastore fields, so they would be ignored for all datastore operations.
Two possible ways to mark these properties come to mind...
Perhaps this could also be achieved by creating a subclass of the collection class, and putting these non-datastore properties in the subclass, but I think that would be awkward and wouldn't be suitable.
My use case for this is that I want to have a property called 'status' with which I would track whether the entity had been loaded from the DS, whether the instance data was dirty and needed to be written, etc.
For the record, I first brought this up in fireorm's gitter here.
He there!
We need some workaround for documents that created without id
inside js object - see example.
import * as admin from 'firebase-admin'
@Collection()
class Band {
id: string;
name: string;
}
async function createBand(band: Band): string {
const doc = await admin.firestore().collection('bands').add(band);
return doc.id;
}
async function getById(id: string): Promise<Band> {
const doc = await admin.firestore().collection('bands').doc(id);
return {id: doc.id, ...doc.data()};
}
// Assume, that we used firestore native sdk to create doc:
const band = new Band();
band.name = 'Nirvana';
const bandId = await createBand(band);
// then we decided to use fireorm
const bandFromFirestore = await getRepository(Band).findById(bandId);
expect(bandFromFirestore).to.be.instanceof(Band); // true
expect(bandFromFirestore.id).not.to.be.undefined; // error!
I've created pull request (/w tests) that resolved this - #120
Hello,
On an existing document:
{
id: 'rush'
a: 'a',
b: 'b'
}
if made this:
const bandRepository = GetRepository(Band);
const rush = await bandRepository.findById('rush');
delete rush.a // remove the a entry
await bandRepository.update(rush);
the document should be:
{
id: 'rush'
b: 'b'
}
But actually it keeps the a
entry...
On Firestore we have the merge
option to define if we want to merge or replace:
set(
rush,
{merge: true}
)
What is the equivalent for fireorm
? I can't find it on the documentation.
Thanks!
Configure Semantic Release to automate the release of the package.
Note: Might be a good idea to look at the state of the art, I might be biased :)
I noticed that when watching the tests, the number of objects stored in Metadata Storage keeps growing even if we have not edited the entities. This is making subsequently builds fail after #56 because the reference of the stored collections gets updated and tests fail.
Acceptance Criteria:
This package is automatically deployed with semantic-release and for it to work properly, we should use semantic commit messages
Acceptance Criteria:
IQueryExecutor
to encapsulate firestore collection and firebase callerI am getting the exception below when updating an entity with a subcollection.
Version:
0.5.2
Example:
https://github.com/dietrichwestbrooks/fireorm-subcol
Exception:
Error: Update() requires either a single JavaScript object or an alternating list of field/value pairs that can be followed by an optional precondition. Value for argument "dataOrField" is not a valid Firestore document. Couldn't serialize object of type "BaseFirestoreRepository" (found in field users). Firestore doesn't support JavaScript objects with custom prototypes (i.e. objects that were created via the "new" operator).
at WriteBatch.update (C:\temp\fireorm-subcol\node_modules@google-cloud\firestore\build\src\write-batch.js:358:23)
at DocumentReference.update (C:\temp\fireorm-subcol\node_modules@google-cloud\firestore\build\src\reference.js:367:14)
at BaseFirestoreRepository. (C:\temp\fireorm-subcol\node_modules\fireorm\lib\src\BaseFirestoreRepository.js:170:80)
at step (C:\temp\fireorm-subcol\node_modules\fireorm\lib\src\BaseFirestoreRepository.js:43:23)
at Object.next (C:\temp\fireorm-subcol\node_modules\fireorm\lib\src\BaseFirestoreRepository.js:24:53)
at C:\temp\fireorm-subcol\node_modules\fireorm\lib\src\BaseFirestoreRepository.js:18:71
at new Promise ()
at __awaiter (C:\temp\fireorm-subcol\node_modules\fireorm\lib\src\BaseFirestoreRepository.js:14:12)
at BaseFirestoreRepository.update (C:\temp\fireorm-subcol\node_modules\fireorm\lib\src\BaseFirestoreRepository.js:165:16)
at eval (webpack:///./index.ts?:41:49)
Hi everybody,
looks like with .NET API is not possible to add a Deal(Opportunity) with tags.
I also tried with "tags":["Tag1", "Tag2"], the deal was created but withou tags. This is strange becouse the JSON back has the tags.
For subcollections, we only test findById
. Add more tests including:
I'll start the design process for the Relationships feature. So far the idea is to express explicit relationships between two collection using the provided decorators.
@OnetoOne
@OneToMany
@manytomany
Also, the relationships should provide a way to declare them as Lazy or Eager (and Lazy will be the default). Fireorm will retrieve all the eager relationships when doing a query and will return (non-evaluated) Promises for the lazy ones.
Open Questions:
Now that we're approaching v1 release (yeah!) we need to start thinking of writing some type of documentation if we want people to use this library.
I will divide this task in three subtasks which will be worked individually:
reflect-metadata
should be moved from devDependency to dependency as it's being imported here
Is there planned support for querying collections using subfields, as is possible in raw Firestore?
For example:
@Collection()
class Person {
name: {
first: string,
last: string
}
age: number
}
const Persons = GetRepository(Person)
... snip ...
const result = await Persons('name.first', 'Sanjay').find()
It looks like the challenge here is type-checking the first argument against all the possible object paths (since fireorm
is currently using keyof T
to type-check against top-level fields).
TypeScript doesn't have any built-in type for object paths, but there's projects like ts-object-path
that allow you to construct a proxy type for all the valid paths in an object.
Using that library, the example above might look like:
const p = createProxy<Person>() // Has type `ObjPathProxy<Person, Person>`.
// Works!
const result = await Persons.whereEqualTo(p.name.first, 'Sanjay')
// Will not compile.
const bad = await Persons.whereEqualTo(p.height, 'Sanjay')
Internally, fireorm
would use the getPath
function from ts-object-path
to turn the path variable (p.name.first
) into a path array (['name', 'first']
), then join the path array to get 'name.first'
for the query.
For brevity, it might even be desirable to export a short alias for createProxy
like path
, and usage would look like:
// The type parameter of `path` can be inferred from the typing of `whereEqualTo`.
const result = await Persons.whereEqualTo(path().name.first, 'Sanjay')
Please let me know your thoughts!
By the way, super excited about this project. It already looks quite powerful, and with transactions/batch writes on the roadmap for 1.0.0
, it'll only become more robust.
Hello there,
When I launch firebase serve --only functions
, i have this error message:
[1] Error: Application has not been initialized. Call Initialize() method
[1] at Object.exports.getMetadataStorage (E:\Work\www\lbdc-firebase\back\functions\node_modules\fireorm\lib\src\MetadataStorage.js:56:15)
[1] at E:\Work\www\lbdc-firebase\back\functions\node_modules\fireorm\lib\src\Decorators\Collection.js:7:27
[1] at DecorateConstructor (E:\Work\www\lbdc-firebase\back\functions\node_modules\reflect-metadata\Reflect.js:541:33)
[1] at Object.decorate (E:\Work\www\lbdc-firebase\back\functions\node_modules\reflect-metadata\Reflect.js:130:24)
[1] at __decorate (E:\Work\www\lbdc-firebase\back\functions\lib\models\band.js:4:92)
[1] at Object.<anonymous> (E:\Work\www\lbdc-firebase\back\functions\lib\models\band.js:12:8)
And I don't understand because Initialize is called.
index.ts
// tslint:disable-next-line: no-import-side-effect
import "reflect-metadata";
import * as fireorm from "fireorm";
import * as admin from "firebase-admin";
import * as functions from "firebase-functions";
import * as onCall from "./onCall"
admin.initializeApp(functions.config().firebase);
const firestore = admin.firestore();
firestore.settings({
timestampsInSnapshots: true
});
fireorm.Initialize(firestore);
export = {
...onCall
}
band.model.ts
import { Collection } from "fireorm";
@Collection("Bands")
export default class Band {
id: string;
name: string;
}
band.ts
import { GetRepository } from "fireorm";
import Band from "./band.model";
const create = async (payload: Band) => {
const bandRepository = GetRepository(Band);
let band = new Band();
band = { ...band, ...payload };
await bandRepository.create(band);
};
onCall.ts
import * as functions from "firebase-functions";
import band from "./band";
import Band from "./band.model";
export const createBand = functions.https.onCall(
async (payload: Band, context) => {
await band.create(payload);
}
);
Thanks for your help!
In #56 we started re-exporting class-transformer's @Type Decorator to be able to cast Firestore GeoPoint fields. That solution is far from final and was only meant as a temporary workaround.
The way Typescript works, types are not available at runtime. If you want to cast Firestore's complex types into your custom classes, you need to tell Typescript the class it should cast it to... via a Decorator.
This issue is more of an exploration in this topic. More information is needed to fully implement a flexible solution.
Acceptance criteria:
latitude
and longitude
fieldsIf you run yarn test
everything is ok and green, but when using test:watch
test start failing after a couple of saves.
So far, these tests are failing:
1) BaseFirestoreRepository
findById
must find by id:
AssertionError: expected { Object (id, name, ...) } to be an instance of Band
at /Users/willyovalle/dev/own/fireorm/src/BaseFirestoreRepository.spec.ts:163:18
at step (src/BaseFirestoreRepository.spec.ts:46:23)
at Object.next (src/BaseFirestoreRepository.spec.ts:27:53)
at fulfilled (src/BaseFirestoreRepository.spec.ts:18:58)
2) BaseFirestoreRepository
findOne
must return T:
AssertionError: expected { Object (id, name, ...) } to be an instance of Band
at /Users/willyovalle/dev/own/fireorm/src/BaseFirestoreRepository.spec.ts:343:28
at step (src/BaseFirestoreRepository.spec.ts:46:23)
at Object.next (src/BaseFirestoreRepository.spec.ts:27:53)
at fulfilled (src/BaseFirestoreRepository.spec.ts:18:58)
3) BaseFirestoreRepository
miscellaneous
should correctly parse geopoints:
AssertionError: expected { Object (latitude, longitude) } to be an instance of Coordinates
at /Users/willyovalle/dev/own/fireorm/src/BaseFirestoreRepository.spec.ts:371:44
at step (src/BaseFirestoreRepository.spec.ts:46:23)
at Object.next (src/BaseFirestoreRepository.spec.ts:27:53)
at fulfilled (src/BaseFirestoreRepository.spec.ts:18:58)
4) BaseFirestoreTransactionRepository
findById
must find by id:
AssertionError: expected { Object (id, name, ...) } to be an instance of Band
at /Users/willyovalle/dev/own/fireorm/src/BaseFirestoreTransactionRepository.spec.ts:57:20
at step (src/BaseFirestoreTransactionRepository.spec.ts:46:23)
at Object.next (src/BaseFirestoreTransactionRepository.spec.ts:27:53)
at fulfilled (src/BaseFirestoreTransactionRepository.spec.ts:18:58)
I had this error before and I remember the fix was related to the way the entities were declared. It seems that in the last PR's a regression was introduced.
Hi there!
Awesome work with that library, that was really missed!
I'm interested in using the ORM in cloud functions DB trigger and I was wondering, is it possible to retrieve a Model from the DocumentSnapshot
provided by the trigger?
Cheers! :)
To create the Transaction unit tests I had to monkey patch the library fireorm uses to mock firestore in unit tests.
Last week I created a PR in that library adding the runTransaction
method. Let's replace our local implementation with the one provided by the library.
Acceptance Criteria:
mock-cloud-firestore
to last versionmonkeyPatchFirestoreTransaction.ts
filerunTransaction
function provided by Firestore constructor directly from mock-cloud-firestore
I think we are mature enough to have some test coverage in our project.
Let's take some time to plan the tooling around it:
Initially, I'd like NOT to block pull requests if the coverage goes down, but I want a way for the coverage to be visible. Maybe an automated comment in the PR?
From travis documentation:
Pull requests sent from forked repositories do not have access to encrypted variables or data even if these are defined in the fork source project.
Acceptance Criteria
Recently, we shipped the ability to use Firestore's OrderBy feature in fireorm. It doesn't makes sense for a query to have two orderBy clauses and may lead to confusion.
Acceptance criteria:
Recently, we shipped the ability to use Firestore's Limit feature in fireorm. It doesn't makes sense for a query to have two limit clauses and may lead to confusion.
Acceptance criteria
I knew several orms support transactions (ex. typeorm).
Do you have any idea with transactions?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.