-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: use LB3 models in an LB4 app [SPIKE - DO NOT MERGE] #2274
Closed
Changes from 1 commit
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
3302a9f
feat(v3compat): initial commit
bajtos eb868ee
feat(v3compat): model registration and JavaScript DAO API
bajtos ec441a2
feat(v3compat): add minimum strong-remoting infrastructure
bajtos 4ddb7ab
feat(v3compat): define remoting metadata for some CRUD methods
bajtos 2893a49
docs: add working notes for the spike
bajtos fa06c1c
feat(v3compat): rest adapter
bajtos f9843eb
feat(v3compat): request body parameters
bajtos cee5f84
feat(v3compat): bind datasources in Context
bajtos d1348e8
feat(v3compat): boot LB3 models
bajtos 8309591
fix(v3compat): fail when attaching a model to an unknown datasource
bajtos cb4a147
feat(example-lb3models): initial commit
bajtos e0413f7
feat(v3compat): support callback-based remote methods
bajtos 63f46b5
feat(v3compat): use a more sensible default root for LB3 model booter
bajtos de3529b
docs(v3compat): add developer and spike documentation
bajtos 0465a94
fix: make "npm test" pass
bajtos File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// Copyright IBM Corp. 2018. All Rights Reserved. | ||
// Node module: @loopback/v3compat | ||
// This file is licensed under the MIT License. | ||
// License text available at https://opensource.org/licenses/MIT | ||
|
||
import {Constructor} from '@loopback/context'; | ||
import {Application} from '@loopback/core'; | ||
import {Lb3Application} from './core/lb3-application'; | ||
|
||
/** | ||
* A mixin class for Application that adds `v3compat` property providing | ||
* access to LB3 application-like object. | ||
* | ||
* ```ts | ||
* class MyApplication extends CompatMixin(RestApplication) { | ||
* constructor() { | ||
* const lb3app = this.v3compat; | ||
* const Todo = lb3app.registry.createModel( | ||
* 'Todo', | ||
* {title: {type: 'string', required: true}}, | ||
* {strict: true} | ||
* ); | ||
* lb3app.dataSource('db', {connector: 'memory'}); | ||
* lb3app.model(Todo, {dataSource: 'db'}); | ||
* } | ||
* } | ||
* ``` | ||
* | ||
* TODO: describe "app.v3compat" property, point users to documentation | ||
* for Lb3Application class. | ||
* | ||
*/ | ||
// tslint:disable-next-line:no-any | ||
export function CompatMixin<T extends Constructor<any>>(superClass: T) { | ||
return class extends superClass { | ||
v3compat: Lb3Application; | ||
|
||
// tslint:disable-next-line:no-any | ||
constructor(...args: any[]) { | ||
super(...args); | ||
this.v3compat = new Lb3Application((this as unknown) as Application); | ||
} | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# v3compat/core | ||
|
||
Source code migrated from [loopback](https://github.com/strongloop/loopback). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
// Copyright IBM Corp. 2018. All Rights Reserved. | ||
// Node module: @loopback/v3compat | ||
// This file is licensed under the MIT License. | ||
// License text available at https://opensource.org/licenses/MIT | ||
|
||
export * from './lb3-types'; | ||
export * from './lb3-application'; | ||
export * from './lb3-registry'; | ||
export * from './lb3-model'; | ||
export * from './lb3-persisted-model'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// Copyright IBM Corp. 2018. All Rights Reserved. | ||
// Node module: @loopback/v3compat | ||
// This file is licensed under the MIT License. | ||
// License text available at https://opensource.org/licenses/MIT | ||
|
||
import {Application} from '@loopback/core'; | ||
import * as debugFactory from 'debug'; | ||
import {ModelClass} from './lb3-model'; | ||
import {Lb3Registry} from './lb3-registry'; | ||
import {DataSource, DataSourceConfig, ModelConfig} from './lb3-types'; | ||
|
||
const debug = debugFactory('loopback:v3compat:mixin'); | ||
|
||
export class Lb3Application { | ||
readonly registry: Lb3Registry; | ||
|
||
readonly dataSources: { | ||
[name: string]: DataSource; | ||
}; | ||
|
||
readonly models: { | ||
[name: string]: ModelClass; | ||
}; | ||
|
||
constructor(protected lb4app: Application) { | ||
this.registry = new Lb3Registry(lb4app); | ||
this.dataSources = Object.create(null); | ||
this.models = Object.create(null); | ||
} | ||
|
||
dataSource(name: string, config: DataSourceConfig): DataSource { | ||
debug('registering datasource %s with config %j', name, config); | ||
// TODO: use the implementation from LB3's lib/application.js | ||
const ds = this.registry.createDataSource(name, config); | ||
this.dataSources[name] = ds; | ||
return ds; | ||
} | ||
|
||
model(modelCtor: ModelClass, config: ModelConfig) { | ||
debug('registering model %s with config %s', modelCtor.modelName, config); | ||
// TODO: use the implementation from LB3's lib/application.js | ||
if (typeof config.dataSource === 'string') { | ||
const dataSource = this.dataSources[config.dataSource]; | ||
config = Object.assign({}, config, {dataSource}); | ||
} | ||
this.registry.configureModel(modelCtor, config); | ||
this.models[modelCtor.modelName] = modelCtor; | ||
modelCtor.app = this; | ||
} | ||
|
||
deleteModelByName(modelName: string): void { | ||
throw new Error('Not implemented yet.'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// Copyright IBM Corp. 2018. All Rights Reserved. | ||
// Node module: @loopback/v3compat | ||
// This file is licensed under the MIT License. | ||
// License text available at https://opensource.org/licenses/MIT | ||
|
||
import {ModelBase} from 'loopback-datasource-juggler'; | ||
import { | ||
RemoteMethodOptions, | ||
RemotingErrorHook, | ||
RemotingHook, | ||
} from '../remoting'; | ||
import {Lb3Application} from './lb3-application'; | ||
import {Lb3Registry} from './lb3-registry'; | ||
import {ModelProperties, ModelSettings} from './lb3-types'; | ||
|
||
export type ModelClass = typeof Model; | ||
|
||
export declare class Model extends ModelBase { | ||
static app: Lb3Application; | ||
static registry: Lb3Registry; | ||
// TODO: sharedClass | ||
|
||
static setup(): void; | ||
static beforeRemote(name: string, handler: RemotingHook): void; | ||
static afterRemote(name: string, handler: RemotingHook): void; | ||
static afterRemoteError(name: string, handler: RemotingErrorHook): void; | ||
static remoteMethod(name: string, options: RemoteMethodOptions): void; | ||
static disableRemoteMethodByName(name: string): void; | ||
|
||
// TODO (later) | ||
// - createOptionsFromRemotingContext | ||
// - belongsToRemoting | ||
// - hasOneRemoting | ||
// - hasManyRemoting | ||
// - scopeRemoting | ||
// - nestRemoting | ||
|
||
// TODO fix juggler typings and add this method to ModelBase | ||
static extend<M extends typeof Model = typeof Model>( | ||
modelName: string, | ||
properties?: ModelProperties, | ||
settings?: ModelSettings, | ||
): M; | ||
|
||
// LB3 models allow arbitrary additional properties by default | ||
// NOTE(bajtos) I tried to allow consumers to specify a white-list of allowed | ||
// properties, but failed to find a viable way. Also the complexity of such | ||
// solution was quickly growing out of hands. | ||
// tslint:disable-next-line:no-any | ||
[prop: string]: any; | ||
} | ||
|
||
export function setupModelClass(registry: Lb3Registry): typeof Model { | ||
const ModelCtor = registry.modelBuilder.define('Model') as typeof Model; | ||
ModelCtor.registry = registry; | ||
|
||
// TODO copy implementation of setup, before/after remote hooks, etc. | ||
// from LB3's lib/model.js | ||
|
||
return ModelCtor; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
// Copyright IBM Corp. 2018. All Rights Reserved. | ||
// Node module: @loopback/v3compat | ||
// This file is licensed under the MIT License. | ||
// License text available at https://opensource.org/licenses/MIT | ||
|
||
import {Model} from './lb3-model'; | ||
import {Lb3Registry} from './lb3-registry'; | ||
import { | ||
Callback, | ||
Options, | ||
PlainDataObject, | ||
Filter, | ||
ComplexValue, | ||
Where, | ||
} from './lb3-types'; | ||
|
||
export type PersistedModelClass = typeof PersistedModel; | ||
|
||
export declare class PersistedModel extends Model { | ||
static create( | ||
data: ModelData, | ||
options?: Options, | ||
callback?: Callback<PersistedModel>, | ||
): Promise<PersistedModel>; | ||
|
||
static create( | ||
data: ModelData[], | ||
options?: Options, | ||
callback?: Callback<PersistedModel[]>, | ||
): Promise<PersistedModel[]>; | ||
|
||
static upsert( | ||
data: ModelData, | ||
options?: Options, | ||
callback?: Callback<PersistedModel>, | ||
): Promise<PersistedModel>; | ||
|
||
static updateOrCreate( | ||
data: ModelData, | ||
options?: Options, | ||
callback?: Callback<PersistedModel>, | ||
): Promise<PersistedModel>; | ||
|
||
static patchOrCreate( | ||
data: ModelData, | ||
options?: Options, | ||
callback?: Callback<PersistedModel>, | ||
): Promise<PersistedModel>; | ||
|
||
static upsertWithWhere( | ||
where: Where, | ||
data: ModelData, | ||
options?: Options, | ||
callback?: Callback<PersistedModel>, | ||
): Promise<PersistedModel>; | ||
|
||
static patchOrCreateWithWhere( | ||
where: Where, | ||
data: ModelData, | ||
options?: Options, | ||
callback?: Callback<PersistedModel>, | ||
): Promise<PersistedModel>; | ||
|
||
static replaceOrCreate( | ||
data: ModelData, | ||
options?: Options, | ||
callback?: Callback<PersistedModel>, | ||
): Promise<PersistedModel>; | ||
|
||
static findOrCreate( | ||
filter: Filter, | ||
data: ModelData, | ||
options?: Options, | ||
callback?: Callback<PersistedModel>, | ||
): Promise<PersistedModel>; | ||
|
||
static exists( | ||
id: ComplexValue, | ||
options?: Options, | ||
callback?: Callback<boolean>, | ||
): Promise<boolean>; | ||
|
||
static findById( | ||
id: ComplexValue, | ||
filter?: Filter, | ||
options?: Options, | ||
callback?: Callback<boolean>, | ||
): Promise<PersistedModel>; | ||
|
||
static find( | ||
filter?: Filter, | ||
options?: Options, | ||
callback?: Callback<PersistedModel>, | ||
): Promise<PersistedModel[]>; | ||
|
||
static findOne( | ||
filter?: Filter, | ||
options?: Options, | ||
callback?: Callback<PersistedModel>, | ||
): Promise<PersistedModel>; | ||
|
||
static destroyAll( | ||
where?: Where, | ||
options?: Options, | ||
callback?: Callback<CountResult>, | ||
): Promise<CountResult>; | ||
|
||
static remove( | ||
where?: Where, | ||
options?: Options, | ||
callback?: Callback<CountResult>, | ||
): Promise<CountResult>; | ||
|
||
static deleteAll( | ||
where?: Where, | ||
options?: Options, | ||
callback?: Callback<CountResult>, | ||
): Promise<CountResult>; | ||
|
||
static updateAll( | ||
where?: Where, | ||
data?: ModelData, | ||
options?: Options, | ||
callback?: Callback<CountResult>, | ||
): Promise<CountResult>; | ||
|
||
static update( | ||
where?: Where, | ||
data?: ModelData, | ||
options?: Options, | ||
callback?: Callback<CountResult>, | ||
): Promise<CountResult>; | ||
|
||
static destroyById( | ||
id: ComplexValue, | ||
options?: Options, | ||
callback?: Callback<CountResult>, | ||
): Promise<CountResult>; | ||
|
||
static removeById( | ||
id: ComplexValue, | ||
options?: Options, | ||
callback?: Callback<CountResult>, | ||
): Promise<CountResult>; | ||
|
||
static deleteById( | ||
id: ComplexValue, | ||
options?: Options, | ||
callback?: Callback<CountResult>, | ||
): Promise<CountResult>; | ||
|
||
static replaceById( | ||
id: ComplexValue, | ||
data: ModelData, | ||
options?: Options, | ||
callback?: Callback<PersistedModel>, | ||
): Promise<PersistedModel>; | ||
|
||
static count( | ||
where?: Where, | ||
options?: Options, | ||
callback?: Callback<number>, | ||
): Promise<number>; | ||
|
||
// TODO: describe PersistedModel API | ||
// - prototype.save | ||
// - prototype.isNewRecord | ||
// - prototype.delete | ||
// - prototype.updateAttribute | ||
// - prototype.updateAttributes | ||
// - prototype.replaceAttributes | ||
// - prototype.setId | ||
// - prototype.getId | ||
// - prototype.getIdName | ||
} | ||
|
||
export type ModelData = PlainDataObject | PersistedModel; | ||
|
||
export interface CountResult { | ||
count: number; | ||
} | ||
|
||
export function setupPersistedModelClass( | ||
registry: Lb3Registry, | ||
): typeof PersistedModel { | ||
const ModelCtor = registry.getModel('Model'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question: is the |
||
const PersistedModelCtor = ModelCtor.extend<typeof PersistedModel>( | ||
'PersistedModel', | ||
); | ||
|
||
// TODO copy impl of setup and DAO methods from LB3's lib/persisted-model.js | ||
|
||
return PersistedModelCtor; | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to return the created datasource here? I thought we were adding a datasource definition to the app (like
app.model
below).