New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

feathers-solr

Package Overview
Dependencies
Maintainers
1
Versions
90
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

feathers-solr - npm Package Compare versions

Comparing version 1.1.16 to 2.1.0

adapter.ts

430

lib/index.js

@@ -1,392 +0,76 @@

'use strict';
// const { _ } = require('@feathersjs/commons');
const { AdapterService } = require('@feathersjs/adapter-commons');
const Client = require('./client');
// const errors = require('@feathersjs/errors');
Object.defineProperty(exports, "__esModule", {
value: true
});
// const errorHandler = require("./error-handler");
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
// const debug = require('debug')('feathers-solr');
exports.default = init;
var _utils = require('./utils');
var _feathersErrors = require('feathers-errors');
var _feathersErrors2 = _interopRequireDefault(_feathersErrors);
var _solr = require('./client/solr');
var _solr2 = _interopRequireDefault(_solr);
var _debug = require('debug');
var _debug2 = _interopRequireDefault(_debug);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var debug = (0, _debug2.default)('feathers-solr');
var Service = function () {
function Service() {
var _this = this;
var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
_classCallCheck(this, Service);
this.options = Object.assign({}, {
host: 'http://localhost:8983/solr',
core: '/gettingstarted',
schema: false,
migrate: 'safe',
adminKey: false,
idfield: 'id',
managedScheme: true,
/*commitStrategy softCommit: true, commit: true, commitWithin: 50000*/
commitStrategy: {
softCommit: true,
commitWithin: 50000,
overwrite: true
}
}, opt);
this.Solr = new _solr2.default({
host: this.options.host,
core: this.options.core,
managedScheme: this.options.managedScheme,
commitStrategy: this.options.commitStrategy
});
this.status().then(function () {
_this.describe().then(function () {
_this.define().catch(function (err) {
debug('Service.define Error:', err);
});
}).catch(function (err) {
debug('Service.describe Error:', err);
});
}).catch(function (err) {
debug('Service.status Error:', err);
});
}
/**
* Describe Solr Schema
* @return {object]} Solr Schema
*/
_createClass(Service, [{
key: 'describe',
value: function describe() {
return (0, _utils.describeSchema)(this);
// Create the service.
class Service extends AdapterService {
constructor (options) {
if (!options || !options.Model) {
throw new Error('You must provide a Model (the initialized knex object)');
}
/**
* Define Sole Schema
* @param {object} params Schema Filds
* @return {[type]}
*/
}, {
key: 'define',
value: function define(schema) {
this.options.schema = Object.assign({}, this.options.schema, schema);
return (0, _utils.defineSchema)(this);
if (typeof options.name !== 'string') {
throw new Error('No table name specified.');
}
const { whitelist = [] } = options;
/**
* Solr Status
* @return {object} Solr Status
*/
super(
Object.assign(
{
id: 'id'
},
options,
{
whitelist: whitelist.concat(['$like', '$notlike', '$ilike', '$and'])
}
)
);
}, {
key: 'status',
value: function status() {
var _this2 = this;
this.table = options.name;
this.schema = options.schema;
}
return new Promise(function (resolve, reject) {
_this2.Solr.coreAdmin().status().then(function (res) {
resolve(res);
}).catch(function (err) {
return reject(new _feathersErrors2.default.BadRequest(err));
});
});
}
get Model () {
return this.options.Model;
}
/**
* Adapter Find Method
* @param {[type]} params User Query
* @return {[type]} Promise
*/
get client () {
return this.Model;
}
}, {
key: 'find',
value: function find(params) {
if (!_utils._.has(params.query, '$suggest')) {
return this.search(params);
} else {
return this.suggest(params);
}
}
_find (params = {}) {
return this.Model.get('query', params);
}
/**
* Adapter Custom Search Method
* @param {object} params User Query
* @return {object} Promise
*/
_get (id, params = {}) {
return this.Model.get(`query/${id}`, params);
}
}, {
key: 'search',
value: function search(params) {
var _this3 = this;
_create (data, params = {}) {
return this.Model.post('update', data, params);
}
var _self = this;
return new Promise(function (resolve, reject) {
_this3.Solr.json((0, _utils.queryJson)(params, _self.options)).then(function (res) {
debug('Service.find', params, res);
resolve((0, _utils.responseFind)(params, _self.options, res));
}).catch(function (err) {
debug('Service.find ERROR:', err);
return reject(new _feathersErrors2.default.BadRequest(err));
});
});
}
_patch (id, data, params = {}) {
return this.Model.post('update', data, params);
}
/**
* Adapter Custom Suggest Method
* @param {object} params Query Object
* @return {object} Promise
*/
_remove (id, params = {}) {
return this.Model.post('update', params);
}
}, {
key: 'suggest',
value: function suggest(params) {
var _this4 = this;
_update (id, data, params = {}) {
return this.Model.post('update', data, params);
}
}
var _self = this;
return new Promise(function (resolve, reject) {
_this4.Solr.suggest((0, _utils.querySuggest)(params, _self.options)).then(function (res) {
debug('Service.suggest', params, res);
resolve(res);
}).catch(function (err) {
debug('Service.suggest ERROR:', err);
return reject(new _feathersErrors2.default.BadRequest(err));
});
});
}
/**
* Adapter Get Method
* @param {[type]} params User Query
* @return {[type]} Promise
*/
}, {
key: 'get',
value: function get(id, params) {
var _this5 = this;
var _self = this;
params = Object.assign({ query: {} }, params, { $limit: 1, $skip: 0 });
params.query[_self.options.idfield] = id;
return new Promise(function (resolve, reject) {
_this5.Solr.json((0, _utils.queryJson)(params, _self.options)).then(function (res) {
var docs = (0, _utils.responseGet)(res);
if (typeof docs !== 'undefined') {
return resolve(docs);
} else {
return reject(new _feathersErrors2.default.NotFound('No record found for id \'' + id + '\''));
}
}).catch(function (err) {
console.log('err', err);
return reject(new _feathersErrors2.default.NotFound('No record found for id \'' + id + '\''));
});
});
}
/**
* Adapter Create Method
* @param {[type]} params User Query
* @return {[type]} Promise
*/
}, {
key: 'create',
value: function create(data) {
var _this6 = this;
return new Promise(function (resolve, reject) {
_this6.Solr.update(data).then(function (res) {
if (res.responseHeader.status === 0) {
resolve(data);
} else {
console.log('res', res);
return reject(new _feathersErrors2.default.BadRequest(res));
}
}).catch(function (err) {
console.log('err', err);
return reject(new _feathersErrors2.default.BadRequest(err));
});
});
}
/**
* Adapter Find Method
* adapter.update(id, data, params) -> Promise
*
* @param {mixed} id [description]
* @param {object} data Update Data
* @param {object} params User Query
* @return {object} Promise
*/
}, {
key: 'update',
value: function update(id, data) {
if (id === null || Array.isArray(data)) {
return Promise.reject(new _feathersErrors2.default.BadRequest('You can not replace multiple instances. Did you mean \'patch\'?'));
}
var _self = this;
data[_self.options.idfield] = id;
return new Promise(function (resolve, reject) {
_self.create(data).then(function () {
resolve(data);
}).catch(function (err) {
debug('Service.update ERROR:', err);
return reject(new _feathersErrors2.default.BadRequest(err));
});
});
}
/**
* adapter.patch(id, data, params) -> Promise
* Using update / overide the doc instead of atomic
* field update http://yonik.com/solr/atomic-updates/
* @param {[type]} id [description]
* @param {[type]} data [description]
* @param {[type]} params [description]
* @return {[type]} [description]
*/
/**
* adapter.patch(id, data, params) -> Promise
* Atomic Field Update http://yonik.com/solr/atomic-updates/
* set – set or replace a particular value, or remove the value if null is specified as the new value
* add – adds an additional value to a list
* remove – removes a value (or a list of values) from a list
* removeregex – removes from a list that match the given Java regular expression
* inc – increments a numeric value by a specific amount (use a negative value to decrement)
* @param {mixed} id ID Optional for single update
* @param {object} data Patch Data
* @param {mixed} query Query Optional for Multiple Updates
* @return {object} Status
*/
}, {
key: 'patch',
value: function patch(id, data, params) {
var _self = this;
return new Promise(function (resolve, reject) {
if (id === null && (!_utils._.isObject(params) || _utils._.isEmpty(params))) {
return reject(new _feathersErrors2.default.BadRequest('Missing Params'));
}
var patchData = (0, _utils.queryPatch)(data);
var createData = [];
if (id !== null) {
patchData[_self.options.idfield] = id;
createData.push(patchData);
_self.create(createData).then(function (res) {
return resolve(createData);
}).catch(function (err) {
return reject(new _feathersErrors2.default.BadRequest(err));
});
} else {
var query = params.query || {};
query.$select = [_self.options.idfield];
_self.Solr.json((0, _utils.queryJson)({ query: query }, _self.options)).then(function (response) {
response = (0, _utils.responseFind)(query, _self.options, response);
if (response.data.length > 0) {
response.data.forEach(function (doc, index) {
var ref = {};
ref[_self.options.idfield] = doc[_self.options.idfield];
createData.push(Object.assign({}, patchData, ref));
});
_self.create(createData).then(function (res) {
return resolve(createData);
}).catch(function (err) {
return reject(new _feathersErrors2.default.BadRequest(err));
});
} else {
return resolve(createData);
}
}).catch(function (err) {
debug('Service.patch find ERROR:', err);
return reject(new _feathersErrors2.default.BadRequest(err));
});
}
});
}
/**
* Remove Data
* - .remove('*') = {"delete": {"query": "*:*"},"commit": {}}
* - .remove('*:*') = {"delete": {"query": "*:*"},"commit": {}}
* - .remove('987987FGHJSD') = {"delete": "262","commit": {}}
* - .remove(['987987FGHJSD','987987FGHJSD']) = {"delete": ["262"],"commit": {}}
* - .remove(null,{'*':'*'}) = {"delete": {"query": "*:*"},"commit": {}}
* - .remove(null,{id:257}) = {"delete": {"query": "id:257"},"commit": {}}
* - .remove(null,{id:*}) = {"delete": {"query": "id:*"},"commit": {}}
* - .remove(null,{other:*}) = {"delete": {"query": "other:257"},"commit": {}}
* @param {[type]} id [description]
* @param {[type]} params [description]
* @return {[type]} [description]
*/
}, {
key: 'remove',
value: function remove(id, params) {
var _this7 = this;
return new Promise(function (resolve, reject) {
_this7.Solr.delete((0, _utils.queryDelete)(id, params || null)).then(function (res) {
resolve(res);
}).catch(function (err) {
debug('Service.remove ERROR:', err);
return reject(new _feathersErrors2.default.BadRequest(err));
});
});
}
/**
* Get Solr Client and use additional functions
* @return {[type]} [description]
*/
}, {
key: 'client',
value: function client() {
return this.Solr;
}
}]);
return Service;
}();
function init(options) {
module.exports = function init (options) {
return new Service(options);
}
};
init.Service = Service;
module.exports = exports.default;
module.exports.Service = Service;
module.exports.Client = Client;
{
"name": "feathers-solr",
"description": "Solr Adapter for Feathersjs",
"version": "1.1.16",
"description": "A service plugin for Solr",
"version": "2.1.0",
"homepage": "https://github.com/sajov/feathers-solr",
"main": "lib/",
"keywords": [
"feathers",
"feathers-plugin",
"solr",
"client",
"adapter",
"feathers",
"feathers-plugin"
"solr-client"
],
"license": "MIT",
"licenses": [
{
"type": "MIT",
"url": "https://github.com/sajov/feathers-solr/blob/master/LICENSE"
}
],
"repository": {

@@ -20,5 +23,3 @@ "type": "git",

"author": {
"name": "sajov",
"email": "info@sajo-media.de",
"url": "https://feathersjs.com"
"name": "Sascha Jovanoski"
},

@@ -30,24 +31,24 @@ "contributors": [],

"engines": {
"node": ">= 4.6.0"
"node": ">= 6"
},
"main": "lib/",
"types": "types",
"scripts": {
"prepublish": "npm run compile",
"NOpublish": "git push origin && git push origin --tags",
"publish": "git push origin --tags && npm run changelog && git push origin",
"changelog": "github_changelog_generator && git add CHANGELOG.md && git commit -am \"Updating changelog\"",
"release:patch": "npm version patch && npm publish",
"release:minor": "npm version minor && npm publish",
"release:major": "npm version major && npm publish",
"compile": "rimraf lib/ && babel -d lib/ src/",
"watch": "babel --watch -d lib/ src/",
"jshint": "jshint src/. test/. --config",
"mocha": "mocha --recursive test/ --require babel-core/register",
"test": "npm run compile && npm run jshint && npm run mocha",
"test1": "npm run compile && npm run jshint && mocha --recursive test/adapter.test.js --require babel-core/register",
"test2": "npm run compile && npm run jshint && mocha --recursive test/adapter.test.js --require babel-core/register",
"test3": "npm run compile && npm run jshint && mocha --recursive test/client/configApi.test.js --require babel-core/register",
"test4": "npm run compile && npm run jshint && mocha --recursive test/client/schemaApi.test.js --require babel-core/register",
"test5": "npm run compile && npm run jshint && mocha --recursive test/query.test.js --require babel-core/register",
"start": "npm run compile && node example/app",
"test-cov": "node_modules/.bin/istanbul cover node_modules/mocha/bin/_mocha -- --require babel-core/register --colors test/*",
"travis": "node_modules/.bin/istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --require babel-core/register --colors --reporter spec test/"
"lint": "semistandard --fix",
"dtslint": "dtslint types",
"mocha": "mocha --opts mocha.opts",
"test": "npm run lint && npm run dtslint && npm run coverage",
"example": "babel-node example/app",
"coverage": "shx rm -rf *.sqlite && istanbul cover node_modules/mocha/bin/_mocha -- --opts mocha.opts"
},
"semistandard": {
"env": [
"mocha"
]
},
"directories": {

@@ -57,40 +58,24 @@ "lib": "lib"

"dependencies": {
"@feathersjs/adapter-commons": "^4.3.8",
"@feathersjs/commons": "^4.3.0",
"@feathersjs/errors": "^4.3.4",
"debug": "^4.1.1",
"feathers-errors": "^2.9.2",
"request": "^2.88.0",
"request-promise": "^4.2.4"
"is-plain-object": "^3.0.0",
"node-fetch": "^2.6.0",
"qs": "^6.9.1",
"req-fast": "^0.2.19"
},
"babel": {
"presets": [
"es2015"
]
},
"eslintConfig": {
"parser": "babel-eslint"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-core": "^6.26.3",
"babel-eslint": "^10.0.3",
"babel-plugin-add-module-exports": "^1.0.2",
"babel-preset-es2015": "^6.24.1",
"@feathersjs/adapter-tests": "^4.3.4",
"@feathersjs/express": "^4.3.5",
"@feathersjs/feathers": "^4.3.4",
"body-parser": "^1.19.0",
"chai": "^4.2.0",
"coveralls": "^3.0.6",
"faker": "^4.1.0",
"feathers": "^2.2.4",
"feathers-hooks": "^2.1.2",
"feathers-rest": "^1.8.1",
"feathers-socketio": "^2.0.1",
"ink-docstrap": "^1.3.2",
"istanbul": "1.0.0-alpha.2",
"jsdoc-to-markdown": "^5.0.1",
"jshint": "^2.10.2",
"mocha": "^6.2.0",
"mocha-coveralls-reporter": "^0.0.5",
"mocha-lcov-reporter": "^1.3.0",
"nsp": "^3.2.1",
"rimraf": "^3.0.0",
"supertest": "^4.0.2"
"chai-as-promised": "^7.1.1",
"dtslint": "^2.0.2",
"istanbul": "^1.1.0-alpha.1",
"loud-rejection": "^2.2.0",
"mocha": "^6.2.1",
"semistandard": "^14.2.0"
}
}

@@ -1,544 +0,354 @@

# feathers-solr
# feathers-knex
[![Build Status](https://travis-ci.org/sajov/feathers-solr.png?branch=master)](https://travis-ci.org/sajov/feathers-solr)
[![Coverage Status](https://coveralls.io/repos/github/sajov/feathers-solr/badge.svg?branch=master)](https://coveralls.io/github/sajov/feathers-solr?branch=master)
[![dependencies Status](https://david-dm.org/sajov/feathers-solr/status.svg)](https://david-dm.org/sajov/feathers-solr)
[![Known Vulnerabilities](https://snyk.io/test/npm/feathers-solr/badge.svg)](https://snyk.io/test/npm/feathers-solr)
> Solr Adapter for Feathersjs. Can also used as a Solr-client. See [additional-client-methods](https://github.com/sajov/feathers-solr/blob/master/README.md#additional-client-methods)
> Require >= Solr 5.x
[![Greenkeeper badge](https://badges.greenkeeper.io/feathersjs-ecosystem/feathers-knex.svg)](https://greenkeeper.io/)
## Online Demo
[feather-solr](http://feathers-solr.sajo-media.de/)
This demonstrate ease of a single query
[![Build Status](https://travis-ci.org/feathersjs-ecosystem/feathers-knex.png?branch=master)](https://travis-ci.org/feathersjs-ecosystem/feathers-knex)
[![Dependency Status](https://img.shields.io/david/feathersjs-ecosystem/feathers-knex.svg?style=flat-square)](https://david-dm.org/feathersjs-ecosystem/feathers-knex)
[![Download Status](https://img.shields.io/npm/dm/feathers-knex.svg?style=flat-square)](https://www.npmjs.com/package/feathers-knex)
## Installation
A database adapter for [KnexJS](http://knexjs.org/), an SQL query builder for Postgres, MSSQL, MySQL, MariaDB, SQLite3, and Oracle.
```bash
npm install --save mysql knex feathers-knex
```
npm install feathers-solr --save
```
## Documentation
> __Important:__ `feathers-knex` implements the [Feathers Common database adapter API](https://docs.feathersjs.com/api/databases/common.html) and [querying syntax](https://docs.feathersjs.com/api/databases/querying.html).
Please refer to the [Feathers database adapter documentation](http://docs.feathersjs.com/databases/readme.html) for more details or directly at:
<!-- -->
- [Service methods](https://docs.feathersjs.com/api/databases/common.html#service-methods) - How to use a database adapter
- [Pagination and Sorting](https://docs.feathersjs.com/api/databases/common.html#pagination) - How to use pagination and sorting for the database adapter
- [Querying](https://docs.feathersjs.com/api/databases/querying.html) - The common adapter querying mechanism
- [Extending](https://docs.feathersjs.com/api/databases/common.html#extending-adapters) - How to extend a database adapter
> **Note:** You also need to [install the database driver](http://knexjs.org/#Installation-node) for the DB you want to use.
## Getting Started
## API
### Install Solr
### `service(options)`
```
bin/solr start -e schemaless
```
Returns a new service instance initialized with the given options.
Use feathers-solr/bin/install-solr.sh for a kickstart installation.
```js
const knex = require('knex');
const service = require('feathers-knex');
const db = knex({
client: 'sqlite3',
connection: {
filename: './db.sqlite'
}
});
## Options
// Create the schema
db.schema.createTable('messages', table => {
table.increments('id');
table.string('text');
});
| Option | Default | Description |
| ---------------- | ---------------------------------------------------------- | ------------------------------------------------------------------ |
| host | http://localhost:8983/solr | |
| core | /gettingstarted | |
| schema | false | {title: {type:"string"}} |
| migrate | alter | *safe*, *alter* and *drop* (delete all data and reset schema) |
| idfield | 'id' | Unique Document identifier |
| commitStrategy | {softCommit: true, commitWithin: 50000, overwrite: true} | |
| paginate | {default: 10, max: 100} | |
## Managed Schema
[Schemaless Mode](https://lucene.apache.org/solr/guide/6_6/schemaless-mode.html) is recommended.
Use [Solr Field Types](https://cwiki.apache.org/confluence/display/solr/Solr+Field+Types) and [Field Type Definitions and Properties](https://cwiki.apache.org/confluence/display/solr/Field+Type+Definitions+and+Properties) to define Model properties
```javascript
{
title: {
type: "text_general", // For more flexible searching. Default type is 'string'
stored: true, // default, keep value visible in results
indexed: true, // default, make it searchable
multiValued: false, // default, true becomes an array field
}
}
app.use('/messages', service({
Model: db,
name: 'messages'
}));
app.use('/messages', service({ Model, name, id, events, paginate }));
```
See your current schema definition
__Options:__
```
http://localhost:8983/solr/gettingstarted/schema/
```
- `Model` (**required**) - The KnexJS database instance
- `name` (**required**) - The name of the table
- `schema` (*optional*) - The name of the schema table prefix (example: `schema.table`)
- `id` (*optional*, default: `'id'`) - The name of the id field property.
- `events` (*optional*) - A list of [custom service events](https://docs.feathersjs.com/api/events.html#custom-events) sent by this service
- `paginate` (*optional*) - A [pagination object](https://docs.feathersjs.com/api/databases/common.html#pagination) containing a `default` and `max` page size
- `multi` (*optional*) - Allow `create` with arrays and `update` and `remove` with `id` `null` to change multiple items. Can be `true` for all methods or an array of allowed methods (e.g. `[ 'remove', 'create' ]`)
- `whitelist` (*optional*) - A list of additional query parameters to allow (e..g `[ '$regex', '$geoNear' ]`). Default is the supported `operators`
### `adapter.createQuery(query)`
Returns a KnexJS query with the [common filter criteria](https://docs.feathersjs.com/api/databases/querying.html) (without pagination) applied.
## Complete Example
### params.knex
Here's an example of a Feathers server that uses `feathers-solr`.
When making a [service method](https://docs.feathersjs.com/api/services.html) call, `params` can contain an `knex` property which allows to modify the options used to run the KnexJS query. See [customizing the query](#customizing-the-query) for an example.
```javascript
const feathers = require('feathers');
const rest = require('feathers-rest');
const hooks = require('feathers-hooks');
const bodyParser = require('body-parser');
const errorHandler = require('feathers-errors/handler');
const solr = require('feathers-solr');
## Example
const Service = new solr.Service({
host: 'http://localhost:8983/solr',
core: '/gettingstarted',
schema:{
name: 'text_general',
company: 'text_general',
email: 'text_general',
age: 'int',
gender: 'string',
color: {
type: 'string',
multiValued: true,
},
address: {
type: 'string',
default: 'Düsseldorf'
}
},
paginate: {
default: 10,
max: 100
});
Here's a complete example of a Feathers server with a `messages` SQLite service. We are using the [Knex schema builder](http://knexjs.org/#Schema) and [SQLite](https://sqlite.org/) as the database.
const app = feathers()
.configure(rest())
.configure(hooks())
.use(bodyParser.json())
.use(bodyParser.urlencoded({ extended: true }))
.use('/solr', Service())
.use(errorHandler());
```
$ npm install @feathersjs/feathers @feathersjs/errors @feathersjs/express @feathersjs/socketio feathers-knex knex sqlite3
```
In `app.js`:
app.listen(3030);
```js
const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
const socketio = require('@feathersjs/socketio');
console.log('Feathers app started on 127.0.0.1:3030');
const service = require('feathers-knex');
const knex = require('knex');
```
const db = knex({
client: 'sqlite3',
connection: {
filename: './db.sqlite'
}
});
// Create a feathers instance.
const app = express(feathers());
// Turn on JSON parser for REST services
app.use(express.json());
// Turn on URL-encoded parser for REST services
app.use(express.urlencoded({ extended: true }));
// Enable REST services
app.configure(express.rest());
// Enable Socket.io services
app.configure(socketio());
// Create Knex Feathers service with a default page size of 2 items
// and a maximum size of 4
app.use('/messages', service({
Model: db,
name: 'messages',
paginate: {
default: 2,
max: 4
}
}))
app.use(express.errorHandler());
### Run Demo App
// Clean up our data. This is optional and is here
// because of our integration tests
db.schema.dropTableIfExists('messages').then(() => {
console.log('Dropped messages table');
```
node /example/app.js
```
// Initialize your table
return db.schema.createTable('messages', table => {
console.log('Creating messages table');
table.increments('id');
table.string('text');
});
}).then(() => {
// Create a dummy Message
app.service('messages').create({
text: 'Message created on server'
}).then(message => console.log('Created message', message));
});
## Support all Feathers Queries
See [Feathers querying](https://docs.feathersjs.com/api/databases/querying.html) for more detail
// Start the server.
const port = 3030;
## Supported Solr Queries
### $search
Simple query
```javascript
query: {
$search: "John"
}
app.listen(port, () => {
console.log(`Feathers server listening on port ${port}`);
});
```
'$search' will try to match against Solr default search field '_text_' [Schemaless Mode](https://cwiki.apache.org/confluence/display/solr/Schemaless+Mode)
Run the example with `node app` and go to [localhost:3030/messages](http://localhost:3030/messages).
## Querying
In addition to the [common querying mechanism](https://docs.feathersjs.com/api/databases/querying.html), this adapter also supports:
More complex query with a default Solr configuration.
### $and
```javascript
query: {
$search: "John !Doe +age:[80 TO *]", // Search in default field _text_. See Solr copy field `copy:* to _text_`
// $params: {
// qf: "name^10 friends" define explicit fields to query and boost
// }
// or $search: "name:John^10 AND !name:Doe AND age:[80 TO *]",
// or $search: "joh*",
// or $search: '"john doe"',
 // or $search: 'jon~',
}
```
Find all records that match all of the given criteria. The following query retrieves all messages that have foo and bar attributes as true.
### $params
Add all kind of Solr query params!
Combine huge Solr Features like *facets*, *stats*, *ranges*, *grouping* and more with the default response.
This example will group the result.
```javascript
query: {
$params: {
group : true,
"group.field" : "country",
"group.format" : "simple",
}
}
```js
app.service('messages').find({
query: {
$and: [
{foo: true},
{bar: true}
]
}
});
```
Feathers Rest query
Through the REST API:
```
http://localhost:3030/solr?$params[group]=true&$params[group.field]=gender&$params[group.field]=age&$params[group.limit]=1&$params[group.format]=grouped&$select=id,age,gender
/messages?$and[][foo]=true&$and[][bar]=true
```
Feathers Result
### $like
```javascript
{
"QTime": 0,
"total": 0,
"limit": 10,
"skip": 0,
"data": {
"gender": {
"matches": 50,
"groups": [
{
"groupValue": "male",
"doclist": {
"numFound": 24,
"start": 0,
"docs": [
{
"id": "59501959f2786e0207a8b29f",
"age": "45",
"gender": "male"
}
]
}
},
{
"groupValue": "female",
"doclist": {
"numFound": 26,
"start": 0,
"docs": [
{
"id": "595019590a8632fecd292592",
"age": "51",
"gender": "female"
}
]
}
}
]
},
"age": {
"matches": 50,
"groups": [
{
"groupValue": "45",
"doclist": {
"numFound": 3,
"start": 0,
"docs": [
{
"id": "59501959f2786e0207a8b29f",
"age": "45",
"gender": "male"
}
]
}
},
{
"groupValue": "51",
"doclist": {
"numFound": 2,
"start": 0,
"docs": [
{
"id": "595019590a8632fecd292592",
"age": "51",
"gender": "female"
}
]
}
}
]
Find all records where the value matches the given string pattern. The following query retrieves all messages that start with `Hello`:
```js
app.service('messages').find({
query: {
text: {
$like: 'Hello%'
}
}
}
});
```
Through the REST API:
### $facet Functions and Analytics
See [Solr Facet Functions and Analytics](http://yonik.com/solr-facet-functions/)
```
/messages?text[$like]=Hello%
```
|Aggregation|Example|Effect|
|--- |--- |--- |
|sum|sum(sales)|summation of numeric values|
|avg|avg(popularity)|average of numeric values|
|sumsq|sumsq(rent)|sum of squares|
|min|min(salary)|minimum value|
|max|max(mul(price,popularity))|maximum value|
|unique|unique(state)|number of unique values (count distinct)|
|hll|hll(state)|number of unique values using the HyperLogLog algorithm|
|percentile|percentile(salary,50,75,99,99.9)|calculates percentiles|
### $notlike
The opposite of `$like`; resulting in an SQL condition similar to this: `WHERE some_field NOT LIKE 'X'`
```javascript
query: {
$facet: {
age_avg : "avg(age)",
age_sum : "sum(age)"
```js
app.service('messages').find({
query: {
text: {
$notlike: '%bar'
}
}
}
});
```
### $facet Ranges
Add a facet type range
Through the REST API:
```javascript
query: {
$facet: {
age_ranges: {
type: "range",
field: "age",
start: 0,
end: 100,
gap: 25
}
}
}
```
/messages?text[$notlike]=%bar
```
Feathers Rest query
### $ilike
```
http://localhost:3030/solr?&$facet[age_ranges][type]=range&$facet[age_ranges][field]=age&$facet[age_ranges][start]=0&$facet[age_ranges][end]=100&$facet[age_ranges][gap]=25&$facet[age_avg]=avg(age)&$facet[age_sum]=sum(age)
```
For PostgreSQL only, the keywork $ilike can be used instead of $like to make the match case insensitive. The following query retrieves all messages that start with `hello` (case insensitive):
Feathers Result
```javascript
{
QTime: 0,
total: 50,
limit: 10,
skip: 0,
data: [...],
facet: {
age_avg: 29.44,
age_sum: 1472,
count: 54,
age_ranges: {
buckets: [{
val: 0,
count: 4
}, {
val: 25,
count: 17
}, {
val: 50,
count: 15
}, {
val: 75,
count: 14
}]
}
```js
app.service('messages').find({
query: {
text: {
$ilike: 'hello%'
}
}
}
});
```
See more query variants [JSON Facet API](http://yonik.com/json-facet-api/),[Solr Facet Functions and Analytics](http://yonik.com/solr-facet-functions/), [Solr Subfacets](http://yonik.com/solr-subfacets/), [Multi-Select Faceting](http://yonik.com/multi-select-faceting/)
Through the REST API:
### $suggest
A custom response object for autocompleter suggestions.
See example *app.js* for creating a custom searchcomponent and requesthandler including a spellcheck component
```
query: {
$suggest: 'Handmake',
$params: {} // to plain solr parameter
}
/messages?text[$ilike]=hello%
```
Feathers Rest query
```
http://localhost:3030/solr?&$suggest=Handmake
```
## Transaction Support
Feathers Result
This is a plain solr response
The Knex adapter comes with three hooks that allows to run service method calls in a transaction. They can be used as application wide (`app.hooks.js`) hooks or per service like this:
```javascript
{
{
"responseHeader": {
"status": 0,
"QTime": 1
},
"spellcheck": {
"suggestions": [
"handmake", {
"numFound": 1,
"startOffset": 0,
"endOffset": 8,
"origFreq": 0,
"suggestion": [{
"word": "handmade",
"freq": 1
}]
}
],
"correctlySpelled": false,
"collations": [
"collation",
"handmade"
]
},
"suggest": {
"suggest": {
"Handmake": {
"numFound": 1,
"suggestions": [{
"term": "Handmade Wooden Keyboard",
"weight": 0,
"payload": ""
}]
}
}
}
}
}
// A common hooks file
const { hooks } = require('feathers-knex');
```
const { transaction } = hooks;
### $spellcheck
This feature add a spellcheck component to the default find result
```
query: {
$search: "Handmake",
$spellcheck:1,
color: "sky blue",
$limit: 10,
module.exports = {
before: {
all: [ transaction.start() ],
find: [],
get: [],
create: [],
update: [],
patch: [],
remove: []
},
}
after: {
all: [ transaction.end() ],
find: [],
get: [],
create: [],
update: [],
patch: [],
remove: []
},
error: {
all: [ transaction.rollback() ],
find: [],
get: [],
create: [],
update: [],
patch: [],
remove: []
}
};
```
Feathers Rest query
To use the transactions feature, you must ensure that the three hooks (start, end and rollback) are being used.
```
http://localhost:3030/solr?$search=Handmake&color=Handmke&color="sky blue"&$limit=10&$spellcheck
```
At the start of any request, a new transaction will be started. All the changes made during the request to the services that are using the `feathers-knex` will use the transaction. At the end of the request, if sucessful, the changes will be commited. If an error occurs, the changes will be forfeit, all the `creates`, `patches`, `updates` and `deletes` are not going to be commited.
Feathers Result
```javascript
{
"QTime": 0,
"total": 6,
"limit": 10,
"skip": 0,
"data": [...],
"spellcheck": {
"suggestions": [
"handmake", {
"numFound": 1,
"startOffset": 0,
"endOffset": 8,
"origFreq": 0,
"suggestion": [{
"word": "handmade",
"freq": 1
}]
}
],
"correctlySpelled": false,
"collations": [
"collation",
"handmade"
]
},
```
The object that contains `transaction` is stored in the `params.transaction` of each request.
### Adapter.patch
> __Important:__ If you call another Knex service within a hook and want to share the transaction you will have to pass `context.params.transaction` in the parameters of the service call.
Support simple usage [Feathers Docs](https://docs.feathersjs.com/api/services.html#patchid-data-params)
```
data: {views: 1};
Adapter.patch(id, data, params);
```
## Customizing the query
Support also advanced Solr Atomic Field Update [Solr Docs](https://lucene.apache.org/solr/guide/6_6/updating-parts-of-documents.html)
In a `find` call, `params.knex` can be passed a KnexJS query (without pagination) to customize the find results.
```
data: {views: {inc:1}}; // inc, set, add, remove, removeregex
Adapter.patch(id, data, params);
```
Combined with `.createQuery({ query: {...} })`, which returns a new KnexJS query with the [common filter criteria](https://docs.feathersjs.com/api/databases/querying.html) applied, this can be used to create more complex queries. The best way to customize the query is in a [before hook](https://docs.feathersjs.com/api/hooks.html) for `find`.
```js
app.service('messages').hooks({
before: {
find(context) {
const query = context.service.createQuery(context.params);
| ------
// do something with query here
query.orderBy('name', 'desc');
## Additional Client Methods
context.params.knex = query;
return context;
}
}
});
```
## Configuring migrations
| Solr Api's | Returns a Promise | ./client/requestHandler/ |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | ------------------------- |
| Ping | Adapter.client().ping() | Ping.js |
| [JSON Request API](https://cwiki.apache.org/confluence/display/solr/JSON+Request+API) | Used by Adapter .find() .get() | JsonRequestApi.js |
| [Update](https://cwiki.apache.org/confluence/display/solr/Uploading+Data+with+Index+Handlers#UploadingDatawithIndexHandlers-UpdateRequestHandlerConfiguration) | Used by Adapter .create(), .update() and .patch() | UpdateRequestHandlers.js |
| [SearchHandlers]() | Adapter.client().search() | SearchHandlers.js |
| [Schema API](https://cwiki.apache.org/confluence/display/solr/Managed+Resources) | Adapter.client().schema.method | SchemaApi.js |
| [Config API](https://cwiki.apache.org/confluence/display/solr/Config+API#ConfigAPI-CreatingandUpdatingRequestHandlers) | | ConfigApi.js |
| [CoreAdmin API](https://cwiki.apache.org/confluence/display/solr/CoreAdmin+API) | Adapter.client().coreAdmin.method | CoreAdminApi.js |
| [Solr ConfigSets API](https://cwiki.apache.org/confluence/display/solr/ConfigSets+API) | Adapter.client().configSets.method | ConfigSetsApi.js |
| [Solr Collections API](https://cwiki.apache.org/confluence/display/solr/Collections+API) | Adapter.client().collections.method | CollectionsApi.js |
| [Solr Managed Resources](https://cwiki.apache.org/confluence/display/solr/Managed+Resources) | Adapter.client().resources.method | ManagedResources.js |
| [Request Parameters API](https://cwiki.apache.org/confluence/display/solr/Request+Parameters+API) | Adapter.client().requestParameters.method | RequestParametersAPI.js |
| ~~[Parallel SQL Interface](https://cwiki.apache.org/confluence/display/solr/Parallel+SQL+Interface)~~ | | ParalellSQL.js |
| ~~[ReplicationHandlers](ReplicationHandlers)~~ | | ReplicationHandlers.js |
| ~~[RealTime Get](https://cwiki.apache.org/confluence/display/solr/RealTime+Get)~~ | | RealTime.js |
| ~~[ShardHandlers](https://cwiki.apache.org/confluence/display/solr/RequestHandlers+and+SearchComponents+in+SolrConfig)~~ | | ShardHandlers.js |
| ~~[Solr BolbStore API](https://cwiki.apache.org/confluence/display/solr/Blob+Store+API)~~ | | BlobStoreApi.js |
For using knex's migration CLI, we need to make the configuration available by the CLI. We can do that by providing a `knexfile.js` in the root folder with the following contents:
Not all Solr API's implemented at the moment
```js
const app = require('./src/app')
module.exports = app.get('postgres')
```
## TODO
* Write more Tests
* Write more Docs
* Implement Parallel SQL Interface
* Implement ReplicationHandlers
* Implement RealTime Get
* Implement ShardHandlers
* Implement Solr BolbStore API
You will need to replace the `postgres` part with the adapter you are using. You will also need to add a `migrations` key to your feathersjs config under your database adapter. Optionally, add a `seeds` key if you will be using [seeds](http://knexjs.org/#Seeds-CLI).
## Changelog
```js
// src/config/default.json
...
"postgres": {
"client": "pg",
"connection": "postgres://user:password@localhost:5432/database",
"migrations": {
"tableName": "knex_migrations"
},
"seeds": {
"directory": "../src/seeds"
}
}
```
__1.1.15__
- add support $between param
- add support for auth
Then, by running: `knex migrate:make create-users`, a `migrations` directory will be created, with the new migration.
__1.1.14__
- ...
### Error handling
__1.1.13__
- refactor describe
- refactor define
- add schema tests
- edit docs
As of version 4.0.0 `feathers-knex` only throws [Feathers Errors](https://docs.feathersjs.com/api/errors.html) with the message. On the server, the original error can be retrieved through a secure symbol via `error[require('feathers-knex').ERROR]`
__1.1.12__
- refactor patch method
```js
const { ERROR } = require('feathers-knex');
try {
await knexService.doSomething();
} catch(error) {
// error is a FeathersError with just the message
// Safely retrieve the Knex error
const knexError = error[ERROR];
}
```
...
## License
Copyright (c) 2015
Copyright (c) 2019
Licensed under the [MIT license](LICENSE).
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc