Skip to content
GitLab
Projects Groups Topics Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in
  • Angular Template Angular Template
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributor statistics
    • Graph
    • Compare revisions
  • Issues 1
    • Issues 1
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 0
    • Merge requests 0
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • IzeniIzeni
  • Angular TemplateAngular Template
  • Wiki
  • data store

data store · Changes

Page history
progress on data store page authored Sep 22, 2016 by Mikkel Davis's avatar Mikkel Davis
Hide whitespace changes
Inline Side-by-side
data-store.md
View page @ a1c0b0e4
jsdata
crud
* for js data all the old methods that had find now use the word read instead
## Abstract CRUD class
We've made an abstract data model class, which individual models extend. Hopefully, this allows for easier data service replacement, if need be. Right now, the template implements JSData for data needs, which has additional explanation below. Here are the abstract class methods:
* `create`: for POSTing one object at a time. (implements jsdata create method)
* `read`: for GETing one object at a time. (implements jsdata find method)
* `update`: for PUTing one object at a time. (implements jsdata update method)
* `destroy`: for DELETEing one object at a tiem. (implements jsdata destroy method)
So, if you look at the configuration of the UserService, it extends AbscractModelService. And in a component, we inject it as `User: UserService`, and use it like so: `this.User.read(id).subscribe()`
## JSData Models (Mappers)
* extend Record
* name
* endpoint
* for jsdata loadrelations you have to specify what relations to load ex) ` foo.loadrealations('barObj')`
* should we name our model services like BookModelService?
* pagination: where it at? how it do?
OLD STUFF:
[[ Our js-data config plays nice with DRF. It handles the deserialization of responses that contain paginated meta data. Additional resource methods have been defined such as `findAllPaged`, `list`, `patch`, and `paging` (detailed below). Three instance methods have been added as `DSPatch`, `detail`, and `debouncedUpdate`. View `src/common/api.js` to inspect their implementation details. ]] -- need to update
[[ Lastly, a $http response interceptor has been defined which will attempt to parse DRF error responses and create a human readable string, which is attached to the promise rejection as `rejection.error`.
(e.g. `User.patch(changes).catch(err => alert(err.error));`) ]] -- need to update
MORE OLD STUFF:
## Documentation for Custom JS-Data Methods
### `patch` and `DSPatch` instance method
Same as DS.update, but overrides the HTTP Method to use `PATCH`.
### `list`
Used in tandem with DRF's `list_route`. Calling `Resource.list('a_list_route')` yields an object that contains five functions: `get`, `put`, `post`, `patch`, and `paging`.
Calling those commands makes the appropriate request to the resource's endpoint concatenated with `a_list_route`.
### `detail` instance method
Used in tandem with DRF's `detail_route`. Operates in the same manner as the `list` method above.
### `debouncedUpdate`
Will update a model at most once per 500 milliseconds. When `debouncedUpdate` is called, it will return the same promise for each debounce period.
### `paging`
Returns a pagination cursor.
Usage:
```
paging = User.paging(params, options);
paging.init();
paging.meta; // ->
{
currentPage, // int, current page (starting from 1)
fetchingPage, // int, the page currently being fetched
pageCount, // int, number of pages
pageSize, // int, instances per page
totalCount, // int, the total number of instances in all pages
}
// The instances for paging.meta.currentPage
paging.page; // -> [...]
// All instances that have been fetched by the cursor.
paging.all; // -> [...]
// Loads the next page (and prefetches the next page(s))
paging.next(); // -> Promise
// Loads the previous page (and prefetches)
paging.prev(); // -> Promise
// Loads the requested page, and prefetches the pages before and after that page
paging.loadPage(pageNumber, prefetchRadius) // -> Promise
// Fetches all pages. If parallelBool is true, it sends the request for all pages at the same time.
// if parallelBool is false, it fetches a page at a time, but you can also access the results as
// they are retrieved at Promise.results, and you can abort the serial request using Promise.abort()
paging.fetchAll(parallelBool) // -> Promise
// True if the cursor is currently on the first page
paging.start; // -> Boolean
// True if the cursor is currently on the last page
paging.end; // -> Boolean
// True if all instances from all pages have been loaded
paging.allLoaded // -> Boolean
```
Default Options:
```
{
cacheResponse: true,
pageQueryParam: 'page',
fetchAll: false,
prefetch: 1,
}
```
Additional (non default) Options:
{
pageSize, // int
pageSizeQueryParam, // str
list, // str (list_route)
}
### `findAllPaged`
Uses the `paging` method above, but immediately calls `fetchAll` and returns the result.
## Using Oauth
There are two oauth providers configured by default (Facebook and Google) that belong to the goog-dev@izeni.com accounts.
To use oauth, you must first locate the correct Python Social Auth provider name (e.g. 'facebook' or 'google-oauth2')
Then, obtain a client ID and secret from the provider's website (e.g. developers.facebook.com) as well as add a link to the redirect_uri configuration in the format of http(s)://[domain]/oauth/[provider]
e.g.
```
http://local.izeni.net:9000/oauth/facebook
or
https://izeni.com/oauth/facebook
```
Save the client ID in the appropriate config file under the `oauth` key. It should be in the format of
`"provider_name": "client_id"` e.g. `"facebook": "1649988431884827"`
The secret is _not_ saved on the client.
To initiate the oauth process, we have to link to the provider's oauth login page using the correct redirect_uri (and scope, if necessary)
The `oauth` directive can generate those links using configuration which can be found in `src/app/login/login.js`
That configuration requires a `provider` (same as above, e.g. "google-oauth2") a `url`, and optionally a `scope` (which differs with each provider, refer to PSA documentation)
Lastly, after the user initiates the oauth process, they are redirect back to the `redirect_uri`,
which is caught by the `oauth` state. The oauth state then sends a request to the server:
`/social/facebook?code=[code]&state=[state]` which then returns a token. If a user didn't exist for the email that the oauth provider passed along, a new user will be created in that same call.
```typescript
#### JSData Relations Example, using JSData v3, JSDataHttpAdapter v3
##### Django Model
```python
class Book (models.Model):
title = models.CharField(max_length=50)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher, null=True, on_delete=models.SET_NULL)
// JSData v3, JSDataHttpAdapter v3
```
##### JavaScript JSData config
```javascript
DataStore.defineMapper(name, { // 'Book'
// ... endpoint, etc
relations: {
......@@ -137,10 +35,10 @@ DataStore.defineMapper(name, { // 'Book'
},
},
hasMany: {
Author: {
localKeys: 'authors',
localField: 'authorObjs',
}
Author: {
localKeys: 'authors',
localField: 'authorObjs',
}
},
},
});
......@@ -149,24 +47,26 @@ DataStore.defineMapper(name, { // 'Author'
// ... endpoint, etc
relations: {
hasMany: {
Book: {
foreignKeys: 'authors',
localField: 'books',
}
}
Book: {
foreignKeys: 'authors',
localField: 'books',
}
}
},
});
DataStore.defineMapper(name, { // 'Publisher'
// ... endpoint, etc
// This relationship to Book is only necessary if you want Publishers to have the 'books' array (named using localField), listing all books they are related to. But 'publisherObj' can still be loaded onto a Book even without this side of the relationship defined.
// This relationship to Book is only necessary if you want Publishers to have the 'books' array (which
// gets its name from localField), listing all books they are related to. But 'publisherObj' can still be
// loaded onto a Book even without this side of the relationship defined.
relations: {
hasMany: {
Book: {
foreignKey: 'publisher',
localField: 'books',
}
}
Book: {
foreignKey: 'publisher',
localField: 'books',
}
}
},
});
......
Clone repository
  • angular
  • cookbook forms
  • cookbook routing
  • data store
  • gotchas
  • Home
  • modals
  • sass with bem
  • toolbox
  • typescript
  • webpack