Comparing version 3.5.0 to 3.5.1
import { Service } from "./connect"; | ||
declare const cds : cds_facade | ||
export = cds | ||
export default cds | ||
@@ -6,0 +6,0 @@ |
@@ -0,6 +1,5 @@ | ||
import { ReflectedDefinitions, ReflectedDefinition, reflected } from "./reflect"; | ||
import { ParsedModel, Definition } from "./specs/CSN"; | ||
import { ParsedQuery } from "./specs/CQN"; | ||
import { ParsedModel, Definition } from "./specs/CSN"; | ||
import { LocalService } from "./connect"; | ||
import { ReflectedDefinitions, ReflectedDefinition, reflected } from "./reflect"; | ||
import { rejects } from "assert"; | ||
@@ -12,3 +11,3 @@ export function serve (service : string | ParsedModel) : Fluent | ||
at (path: string) : this | ||
in (app: Express.Application) : this | ||
in (app: express.app) : this | ||
with (impl: ServiceImpl | string) : this | ||
@@ -19,2 +18,6 @@ then (next: ()=> void) : Promise<ServiceProvider | ServiceProviders> | ||
declare namespace express { | ||
interface app {} | ||
} | ||
export const service : { | ||
@@ -21,0 +24,0 @@ impl: (impl: ServiceImpl) => typeof impl |
@@ -0,3 +1,5 @@ | ||
const fs = require('fs-extra') | ||
const path = require('path') | ||
const BuildTaskHandler = require('../buildTaskHandler') | ||
const URL = require('url') | ||
@@ -9,2 +11,8 @@ class FioriAppModuleBuilder extends BuildTaskHandler { | ||
/** | ||
* This version only creates a odata representation for the 'mainService' data source | ||
* as defined by the fiori wizard - everything else is currently not supported. | ||
* Therefore errors are only logged, the build does not fail in case a the service | ||
* cannot be resolved based on the defined service URI | ||
*/ | ||
build() { | ||
@@ -28,3 +36,6 @@ const { | ||
return this.cds.load(modelPaths).then(model => { | ||
return this._compileEdmx(model, src, dest) | ||
return Promise.all([ | ||
this._compileEdmx(model, src, dest), | ||
this._copyNativeContent(src, dest) | ||
]) | ||
}) | ||
@@ -37,32 +48,66 @@ } | ||
_copyNativeContent(src, dest) { | ||
return super._copyNativeContent(src, dest, (entry) => { | ||
const extname = path.extname(entry) | ||
return ((fs.statSync(entry).isDirectory() && path.dirname !== dest) || extname !== '.cds') | ||
}) | ||
} | ||
_compileEdmx(model, src, dest) { | ||
const manifestJson = path.resolve(src, 'webapp/manifest.json') | ||
let manifest; //= filled in below... | ||
const manifestPath = path.join(src, 'webapp', 'manifest.json') | ||
let manifest | ||
try { | ||
manifest = require(manifestJson) | ||
manifest = require(manifestPath) | ||
} catch (error) { | ||
this.logger.log(`UI module does not contain a manifest.json - ${manifestJson}`) | ||
this.logger.log(`UI module does not contain a manifest.json [${manifestPath}] - skip build`) | ||
return Promise.resolve() | ||
} | ||
// this version only supports mainService data source as generated by fiori wizard | ||
const mainService = this._property(manifest, 'sap.app', 'dataSources', 'mainService') | ||
const localUri = this._property(mainService, 'settings', 'localUri') | ||
const uri = this._property(mainService, 'uri') | ||
if (!localUri || !uri) { | ||
if (!mainService) { | ||
// no mainService defined - not supported | ||
this.logger.log(`UI module does not contain a mainService [${manifestPath}] - skip build`) | ||
return Promise.resolve() | ||
} | ||
const serviceName = uri.split('/').reverse().find(segment => { | ||
return !!segment | ||
}) | ||
if (!serviceName) { | ||
return Promise.resolve() | ||
const localUri = this._property(mainService, 'settings', 'localUri') | ||
const uri = mainService.uri | ||
if (localUri && uri) { | ||
try { | ||
const edmx = this._compileEdmxForUri(model, uri) | ||
const edmxPath = path.resolve(path.join(dest, 'webapp'), this._strippedUrlPath(localUri)) | ||
return this.write(edmx).to(edmxPath) | ||
} catch (error) { | ||
this.logger.error(`Failed to compile edmx representation for service uri ${uri}, data source [mainService]`) | ||
this.logger.error(error.stack) | ||
} | ||
} else { | ||
this.logger.error(`Failed to compile odata representation for data source [mainService], [${manifestPath}]`) | ||
} | ||
const edmx = this.cds.compile.to.edmx(model, { | ||
service: serviceName | ||
}) | ||
return this.write(edmx).to(path.join(dest, 'webapp', localUri)) | ||
// ignoring errors | ||
return Promise.resolve(`Failed to build odata representation for [mainService] for UI module [${path.relative(this.buildOptions.root, src)}]`) | ||
} | ||
_compileEdmxForUri(model, uri) { | ||
const uriSegments = this._strippedUrlPath(uri).split('/') | ||
// one segment of the URI has to match a service name | ||
let service = this.cds.reflect(model).find(service => uriSegments.find(segment => service.name === segment)) | ||
if (service) { | ||
return this.cds.compile.to.edmx(model, { | ||
service: service.name | ||
}) | ||
} | ||
throw new Error(`Failed to resolve service name from URI ${uri} as defined in manfifest.json`) | ||
} | ||
_strippedUrlPath(urlString) { | ||
const url = URL.parse(urlString) | ||
return url.pathname.replace(/^(\/|\\)/, '').replace(/(\/|\\)$/, '') // strip leading and trailing slash or backslash) | ||
} | ||
_property(src, ...segments) { | ||
@@ -69,0 +114,0 @@ return segments.reduce((p, n) => p && p[n], src) |
@@ -28,3 +28,3 @@ module.exports = Object.assign(deploy, { | ||
.then (() => cds.disconnect())) | ||
.then(url && !no_save && (() => registerDatasource(o))) | ||
.then (url && !no_save && (() => registerDatasource(o))) | ||
.catch (e => { | ||
@@ -36,3 +36,2 @@ if (!model && e.code === 'MODEL_NOT_FOUND') { | ||
if (url && !no_save) registerDatasource(o) | ||
} | ||
@@ -39,0 +38,0 @@ |
@@ -9,2 +9,16 @@ # Change Log | ||
## Version 3.5.1 - 2019-02-14 | ||
### Fixed | ||
- In `cds serve` service providers where added twice to the express app. This is fixed. | ||
- In the logs of `cds serve` false warnings on fiori requests are now gone. | ||
- `cds serve` no longer fails on localization for unbound actions. | ||
- The project template was fixed to properly wire up the connection to SAP HANA. | ||
### Also see | ||
- Changes of `@sap/cds-compiler` 1.8.1 | ||
- Changes of `@sap/cds-ql` 1.5.1 | ||
- Changes of `@sap/cds-services` 1.5.2 | ||
- Changes of `@sap/generator-cds` 2.3.7 | ||
## Version 3.5.0 - 2019-02-07 | ||
@@ -24,6 +38,10 @@ | ||
- Unclear documentation of `cds deploy` on where it looks up the data source. | ||
- An issue where service providers where added twice to the express app. | ||
- `cds env` to load configuration profiles in lower-prio files (`.cdsrc.json`) with higher precedence than default configuration in higher-prio files (`package.json`). | ||
### Removed | ||
### Also see | ||
- Changes of `@sap/cds-compiler` 1.8.0 | ||
- Changes of `@sap/cds-reflect` 2.3.0 | ||
- Changes of `@sap/cds-ql` 1.5.0 | ||
- Changes of `@sap/cds-services` 1.5.0 | ||
- Changes of `@sap/generator-cds` 2.3.6 | ||
@@ -30,0 +48,0 @@ ## Version 3.4.1 - 2019-01-24 |
const cds = require('../index') | ||
const {default_language} = cds.env.i18n || 'en' | ||
const _4sqlite = ['de','fr'] | ||
const _noop = x=>x | ||
if (!cds.env.features.localized) return module.exports = { | ||
unfold: _noop, | ||
serve: _noop, | ||
} | ||
/////////////////////////////////////////////////////////// | ||
// cds-compiler part | ||
// | ||
// Rewrites DDL output of 2sql | ||
const unfold = function _unfold_localized_entities_in (ddl, csn) { // NOSONAR | ||
csn = cds.compile.for.sql (csn) | ||
const m = cds.linked (csn), entities = m.entities | ||
for (let each in entities) { | ||
const d = entities [each] | ||
if (_has_localized_elements (entities [each])) { | ||
if (d.own('abstract')) continue | ||
if (d.query || d.source) { | ||
const cv = `CREATE VIEW ${each.replace(/\./g,'_')}` | ||
const m = cds.linked (csn) | ||
const services = RegExp (Object.keys (m.services).map(n => '^'+n+'\\.').join('|')) | ||
for (let each of m.each('entity')) { | ||
if (_has_localized_elements (each)) { | ||
if (each.own('abstract')) continue | ||
if (each.query || each.source) { | ||
const sql_name = `${each.name.replace(/\./g,'_')}` | ||
const cv = `CREATE VIEW ${sql_name}` | ||
const k = ddl.findIndex (x => x.startsWith(cv)) | ||
if (k<0) continue | ||
const sql = ddl[k] | ||
if (each.includes('localized_')) { | ||
if (each.name.includes('localized_')) { | ||
// localized_Books > Books_localized | ||
const entity = sql_name.replace('localized_','') | ||
ddl[k] = sql | ||
.replace (cv, cv.replace('localized_','')+'_localized') | ||
.replace (sql_name, `${entity}_localized`) | ||
.replace (/\.locale = 'EN'/, `.locale = '${default_language}'`) | ||
for (let each of _4sqlite) ddl.push (sql | ||
.replace (cv, cv.replace('localized_','')+`_localized_${each}`) | ||
.replace (sql_name, `${entity}_localized_${each}`) | ||
.replace (/\.locale = 'EN'/, `.locale = '${each}'`) | ||
@@ -34,9 +36,10 @@ ) | ||
else { | ||
// Service.Books > + Service.Books_localized | ||
const inService = services.test (each.name) | ||
// Service.Books > + localized_Service.Books | ||
ddl.push (sql | ||
.replace (cv, cv+'_localized') | ||
.replace (sql_name, inService ? `localized_${sql_name}` : `${sql_name}_localized`) | ||
.replace (/FROM (\w+) AS/, 'FROM $1_localized AS') | ||
) | ||
for (let each of _4sqlite) ddl.push (sql | ||
.replace (cv, cv+`_localized_${each}`) | ||
.replace (sql_name, inService ? `localized_${each}_${sql_name}` : `${sql_name}_localized_${each}`) | ||
.replace (/FROM (\w+) AS/, `FROM $1_localized_${each} AS`) | ||
@@ -51,2 +54,9 @@ ) | ||
/////////////////////////////////////////////////////////// | ||
// cds.services part | ||
// | ||
const serve = function _serve_localized_entities_in (srv) { | ||
@@ -60,16 +70,11 @@ const entities = srv.entities | ||
function _has_localized_elements (d) { | ||
return d.elements.localized | ||
// for (let any in d.elements) { | ||
// if (d.elements[any].localized) return true | ||
// } | ||
} | ||
// Decorator for cds.service.for(...) | ||
function _serve_localized (srv, entity) { | ||
_add_placebos4 (srv,entity) | ||
srv.on ('READ', entity, req => { | ||
const locale = _canonic_locale_from (req) | ||
const _localized = '_localized' + ( _4sqlite.includes(locale) ? '_'+locale : '' ) | ||
const locale = req.user.locale | ||
const localized_ = `localized_${_4sqlite.includes(locale) ? `${locale}_` : ''}` | ||
const {SELECT} = req.query, {ref} = SELECT.from | ||
if (!ref[0].endsWith(_localized)) ref[0] += _localized | ||
if (!ref[0].startsWith(localized_)) ref[0] = localized_+ref[0] | ||
//> we check that to avoid interfering with other/prior redirects | ||
@@ -82,14 +87,25 @@ }) | ||
const d = srv.entities [entity] | ||
srv.model.definitions [d.name+'_localized'] = d | ||
srv.model.definitions [`localized_${d.name}`] = d | ||
for (let each of _4sqlite) | ||
srv.model.definitions [d.name+'_localized_'+each] = d | ||
srv.model.definitions [`localized_${each}_${d.name}`] = d | ||
} | ||
function _canonic_locale_from ({_:{req}}) { | ||
const locale = req.query['sap-language'] || req.header ('accept-language') | ||
return locale ? locale.split('_')[0] : default_language | ||
/////////////////////////////////////////////////////////// | ||
// shared | ||
// | ||
function _has_localized_elements (d) { | ||
return d.elements && d.elements.localized | ||
// for (let any in d.elements) { | ||
// if (d.elements[any].localized) return true | ||
// } | ||
} | ||
module.exports = { unfold, serve } | ||
// pong | ||
if (cds.env.features.localized) { | ||
module.exports = { unfold, serve } | ||
} else { | ||
module.exports = { unfold: x=>x, serve: x=>x } | ||
} |
@@ -15,8 +15,11 @@ const cds = require ('../index'), lib = require ('@sap/cds-ql'); lib.inject (cds) | ||
_ANY_isQuery, | ||
_SELECT_from_valueOf, _SELECT_one, _SELECT_distinct, | ||
_SELECT_from_valueOf, _SELECT_one, _SELECT_distinct, // _SELECT_from_with_key, | ||
_INSERT_into_valueOf, _INSERT_entry_into, | ||
_UPDATE_entity_valueOf, _UPDATE_set_fluent, _UPDATE_with, | ||
_UPDATE_entity_valueOf, _UPDATE_set_fluent, _UPDATE_with, //_UPDATE_with_key, | ||
_DELETE_from_valueOf, | ||
) | ||
DISABLED (_ANY_bound, _ANY_then, _SELECT_foreach) | ||
DISABLED ( | ||
_ANY_bound, _ANY_then, _SELECT_foreach, | ||
_SELECT_from_with_key, _UPDATE_with_key | ||
) | ||
@@ -80,3 +83,16 @@ // Adding support for bound queries, i.e. to entities obtained form a connected datasource | ||
// Add support for SELECT.from('Foo',{ID:11}) | ||
function _SELECT_from_with_key(){ | ||
const { SELECT } = ql, _super=SELECT.from | ||
SELECT.from = (entity, _arg) => { | ||
if (_arg) { | ||
if (Array.isArray(_arg)) return _super (entity) .columns (_arg) | ||
else if (typeof _arg === 'string') entity = {ref:[entity], where: cds.parse.expr(_arg) } | ||
else if (typeof _arg === 'object') entity = {ref:[entity], where: _predicate4(_arg) } | ||
} | ||
return _super(entity) | ||
} | ||
} | ||
// Fix SELECT.one(...) | ||
@@ -155,2 +171,13 @@ function _SELECT_one(){ | ||
// Add support for UPDATE('Foo',{ID:11})... | ||
function _UPDATE_with_key(){ | ||
const { UPDATE } = ql, _super = UPDATE | ||
ql.UPDATE = (entity,_arg) => { | ||
// if (typeof _arg === 'object') return _super (entity) .where (_predicate4(_arg)) | ||
if (_arg) return _super (entity) .where (_arg) | ||
return _super (entity) | ||
} | ||
} | ||
// Add support for UPDATE('Foo') + '... plain sql tail...' | ||
@@ -235,2 +262,14 @@ function _UPDATE_entity_valueOf(){ | ||
/** | ||
* Helper to create a predicate from a feather object | ||
*/ | ||
function _predicate4 (o) { | ||
const predicates = [null] | ||
for (let each in o) { | ||
predicates.push ({ref:each.split('.')}, '=', {val:o[each]}) | ||
} | ||
return predicates.slice(1) | ||
} | ||
module.exports = ql |
@@ -1,2 +0,2 @@ | ||
const {relative, sep} = require ('path') | ||
const { relative, sep } = require ('path') | ||
function _local (filename) { return relative('', filename) } | ||
@@ -11,5 +11,6 @@ const cds = require ('../index') | ||
app.use (express.static(assetDir)) | ||
app.use ((req,res,next)=>{ console.log (req.method, req.url); next() }) | ||
app.get ('/*/webapp/*', (req,res) => res.status(400).send()) | ||
app.get ('/\\$index', (req,res) => res.send (index.html)) | ||
app.get ('/', (req,res) => res.send (index.html)) //> if there is none in ./app | ||
app.use ((req,res,next)=>{ console.log (req.method, req.url); next() }) | ||
@@ -16,0 +17,0 @@ app.listen (PORT, ()=> { |
{ | ||
"name": "@sap/cds", | ||
"version": "3.5.0", | ||
"version": "3.5.1", | ||
"lockfileVersion": 1, | ||
@@ -8,3 +8,3 @@ "requires": true, | ||
"@sap/cds-compiler": { | ||
"version": "1.8.0", | ||
"version": "1.8.1", | ||
"requires": { | ||
@@ -17,13 +17,13 @@ "antlr4": "4.7.1", | ||
"@sap/cds-hana": { | ||
"version": "1.5.0", | ||
"version": "1.5.1", | ||
"requires": { | ||
"@sap/cds-sql": "1.5.0" | ||
"@sap/cds-sql": "1.5.1" | ||
} | ||
}, | ||
"@sap/cds-ql": { | ||
"version": "1.5.0", | ||
"version": "1.5.1", | ||
"requires": { | ||
"@sap/cds-hana": "1.5.0", | ||
"@sap/cds-sql": "1.5.0", | ||
"@sap/cds-sqlite": "1.5.0", | ||
"@sap/cds-hana": "1.5.1", | ||
"@sap/cds-sql": "1.5.1", | ||
"@sap/cds-sqlite": "1.5.1", | ||
"generic-pool": "3.4.2", | ||
@@ -37,5 +37,5 @@ "uuid": "3.3.2" | ||
"@sap/cds-services": { | ||
"version": "1.5.0", | ||
"version": "1.5.2", | ||
"requires": { | ||
"@sap/cds-ql": "1.5.0", | ||
"@sap/cds-ql": "1.5.1", | ||
"@sap/odata-server": "1.0.0" | ||
@@ -45,12 +45,12 @@ } | ||
"@sap/cds-sql": { | ||
"version": "1.5.0" | ||
"version": "1.5.1" | ||
}, | ||
"@sap/cds-sqlite": { | ||
"version": "1.5.0", | ||
"version": "1.5.1", | ||
"requires": { | ||
"@sap/cds-sql": "1.5.0" | ||
"@sap/cds-sql": "1.5.1" | ||
} | ||
}, | ||
"@sap/generator-cds": { | ||
"version": "2.3.6", | ||
"version": "2.3.7", | ||
"requires": { | ||
@@ -57,0 +57,0 @@ "ansi-colors": "3.2.3", |
@@ -1,1 +0,1 @@ | ||
{"bin":{"cds":"bin/cds.js"},"bundleDependencies":false,"dependencies":{"@sap/cds-compiler":"1.8.0","@sap/cds-ql":"1.5.0","@sap/cds-reflect":"2.3.0","@sap/cds-services":"1.5.0","@sap/generator-cds":"2.3.6","fs-extra":"7.0.0"},"deprecated":false,"description":"Entry Point and API Facade for CDS","engines":{"node":">=8.9"},"main":"lib/index.js","name":"@sap/cds","typings":"apis/cds.d.ts","version":"3.5.0","license":"SEE LICENSE IN developer-license-3.1.txt"} | ||
{"bin":{"cds":"bin/cds.js"},"bundleDependencies":false,"dependencies":{"@sap/cds-compiler":"1.8.1","@sap/cds-ql":"1.5.1","@sap/cds-reflect":"2.3.0","@sap/cds-services":"1.5.2","@sap/generator-cds":"2.3.7","fs-extra":"7.0.0"},"deprecated":false,"description":"Entry Point and API Facade for CDS","engines":{"node":">=8.9"},"main":"lib/index.js","name":"@sap/cds","typings":"apis/cds.d.ts","version":"3.5.1","license":"SEE LICENSE IN developer-license-3.1.txt"} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
370671
4564
52
+ Added@sap/cds-compiler@1.8.1(transitive)
+ Added@sap/cds-hana@1.5.1(transitive)
+ Added@sap/cds-ql@1.5.1(transitive)
+ Added@sap/cds-services@1.5.2(transitive)
+ Added@sap/cds-sql@1.5.1(transitive)
+ Added@sap/cds-sqlite@1.5.1(transitive)
+ Added@sap/generator-cds@2.3.7(transitive)
- Removed@sap/cds-compiler@1.8.0(transitive)
- Removed@sap/cds-hana@1.5.0(transitive)
- Removed@sap/cds-ql@1.5.0(transitive)
- Removed@sap/cds-services@1.5.0(transitive)
- Removed@sap/cds-sql@1.5.0(transitive)
- Removed@sap/cds-sqlite@1.5.0(transitive)
- Removed@sap/generator-cds@2.3.6(transitive)
Updated@sap/cds-compiler@1.8.1
Updated@sap/cds-ql@1.5.1
Updated@sap/cds-services@1.5.2
Updated@sap/generator-cds@2.3.7