remult 0.14.4 → 0.14.7-esm.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/LICENSE +21 -0
  2. package/{readme.md → README.md} +68 -30
  3. package/esm/assign.d.ts +1 -0
  4. package/esm/assign.js +5 -0
  5. package/esm/classType.d.ts +3 -0
  6. package/esm/classType.js +1 -0
  7. package/esm/graphql.d.ts +5 -0
  8. package/esm/graphql.js +102 -0
  9. package/esm/index.d.ts +35 -0
  10. package/esm/index.js +29 -0
  11. package/esm/inputTypes.d.ts +9 -0
  12. package/esm/inputTypes.js +9 -0
  13. package/esm/postgres/index.d.ts +1 -0
  14. package/esm/postgres/index.js +1 -0
  15. package/esm/postgres/postgres-data-provider.d.ts +40 -0
  16. package/esm/postgres/postgres-data-provider.js +194 -0
  17. package/esm/postgres/postgresColumnSyntax.d.ts +2 -0
  18. package/esm/postgres/postgresColumnSyntax.js +30 -0
  19. package/esm/remult-express.d.ts +5 -0
  20. package/esm/remult-express.js +16 -0
  21. package/esm/remult-knex/index.d.ts +51 -0
  22. package/esm/remult-knex/index.js +381 -0
  23. package/esm/remult-middleware.d.ts +2 -0
  24. package/esm/remult-middleware.js +63 -0
  25. package/esm/remult-mongo.d.ts +9 -0
  26. package/esm/remult-mongo.js +220 -0
  27. package/esm/server/JsonEntityFileStorage.d.ts +7 -0
  28. package/esm/server/JsonEntityFileStorage.js +20 -0
  29. package/esm/server/expressBridge.d.ts +140 -0
  30. package/esm/server/expressBridge.js +668 -0
  31. package/esm/server/index.d.ts +4 -0
  32. package/esm/server/index.js +4 -0
  33. package/esm/server/register-actions-on-server.d.ts +3 -0
  34. package/esm/server/register-actions-on-server.js +24 -0
  35. package/esm/server/register-entities-on-server.d.ts +3 -0
  36. package/esm/server/register-entities-on-server.js +15 -0
  37. package/esm/src/__EntityValueProvider.d.ts +10 -0
  38. package/esm/src/__EntityValueProvider.js +1 -0
  39. package/esm/src/__RowsOfDataForTesting.d.ts +3 -0
  40. package/esm/src/__RowsOfDataForTesting.js +1 -0
  41. package/esm/src/backend-tests/backend-database-test-setup.backend-spec.d.ts +5 -0
  42. package/esm/src/backend-tests/backend-database-test-setup.backend-spec.js +113 -0
  43. package/esm/src/backend-tests/my-test.backend-spec.d.ts +1 -0
  44. package/esm/src/backend-tests/my-test.backend-spec.js +49 -0
  45. package/esm/src/column-interfaces.d.ts +95 -0
  46. package/esm/src/column-interfaces.js +7 -0
  47. package/esm/src/column.d.ts +49 -0
  48. package/esm/src/column.js +133 -0
  49. package/esm/src/context.d.ts +124 -0
  50. package/esm/src/context.js +285 -0
  51. package/esm/src/data-api.d.ts +33 -0
  52. package/esm/src/data-api.js +204 -0
  53. package/esm/src/data-interfaces.d.ts +37 -0
  54. package/esm/src/data-interfaces.js +12 -0
  55. package/esm/src/data-providers/array-entity-data-provider.d.ts +22 -0
  56. package/esm/src/data-providers/array-entity-data-provider.js +264 -0
  57. package/esm/src/data-providers/in-memory-database.d.ts +9 -0
  58. package/esm/src/data-providers/in-memory-database.js +16 -0
  59. package/esm/src/data-providers/json-data-provider.d.ts +12 -0
  60. package/esm/src/data-providers/json-data-provider.js +52 -0
  61. package/esm/src/data-providers/rest-data-provider.d.ts +35 -0
  62. package/esm/src/data-providers/rest-data-provider.js +188 -0
  63. package/esm/src/data-providers/sql-database.d.ts +16 -0
  64. package/esm/src/data-providers/sql-database.js +261 -0
  65. package/esm/src/data-providers/web-sql-data-provider.d.ts +18 -0
  66. package/esm/src/data-providers/web-sql-data-provider.js +121 -0
  67. package/esm/src/entity.d.ts +82 -0
  68. package/esm/src/entity.js +1 -0
  69. package/esm/src/filter/filter-consumer-bridge-to-sql-request.d.ts +50 -0
  70. package/esm/src/filter/filter-consumer-bridge-to-sql-request.js +139 -0
  71. package/esm/src/filter/filter-consumer-bridge-to-url-builder.d.ts +1 -0
  72. package/esm/src/filter/filter-consumer-bridge-to-url-builder.js +1 -0
  73. package/esm/src/filter/filter-interfaces.d.ts +85 -0
  74. package/esm/src/filter/filter-interfaces.js +467 -0
  75. package/esm/src/id-entity.d.ts +4 -0
  76. package/esm/src/id-entity.js +8 -0
  77. package/esm/src/remult3/RepositoryImplementation.d.ts +326 -0
  78. package/esm/src/remult3/RepositoryImplementation.js +1806 -0
  79. package/esm/src/remult3/index.d.ts +2 -0
  80. package/esm/src/remult3/index.js +2 -0
  81. package/esm/src/remult3/remult3.d.ts +312 -0
  82. package/esm/src/remult3/remult3.js +1 -0
  83. package/esm/src/server-action.d.ts +70 -0
  84. package/esm/src/server-action.js +365 -0
  85. package/esm/src/shared-tests/db-tests-setup.d.ts +23 -0
  86. package/esm/src/shared-tests/db-tests-setup.js +66 -0
  87. package/esm/src/shared-tests/db-tests.db-tests.d.ts +26 -0
  88. package/esm/src/shared-tests/db-tests.db-tests.js +723 -0
  89. package/esm/src/shared-tests/deleteAll.d.ts +2 -0
  90. package/esm/src/shared-tests/deleteAll.js +4 -0
  91. package/esm/src/shared-tests/entityWithValidations.d.ts +14 -0
  92. package/esm/src/shared-tests/entityWithValidations.js +53 -0
  93. package/esm/src/shared-tests/index.d.ts +4 -0
  94. package/esm/src/shared-tests/index.js +4 -0
  95. package/esm/src/shared-tests/test-custom-id-column.spec.d.ts +1 -0
  96. package/esm/src/shared-tests/test-custom-id-column.spec.js +62 -0
  97. package/esm/src/shared-tests/test-special-value.spec.d.ts +10 -0
  98. package/esm/src/shared-tests/test-special-value.spec.js +88 -0
  99. package/esm/src/shared-tests/test-update-with-null.spec.d.ts +1 -0
  100. package/esm/src/shared-tests/test-update-with-null.spec.js +47 -0
  101. package/esm/src/sort.d.ts +15 -0
  102. package/esm/src/sort.js +82 -0
  103. package/esm/src/sql-command.d.ts +15 -0
  104. package/esm/src/sql-command.js +1 -0
  105. package/esm/src/tests/Done.d.ts +5 -0
  106. package/esm/src/tests/Done.js +11 -0
  107. package/esm/src/tests/TestDataApiResponse.d.ts +10 -0
  108. package/esm/src/tests/TestDataApiResponse.js +22 -0
  109. package/esm/src/tests/c.d.ts +8 -0
  110. package/esm/src/tests/c.js +22 -0
  111. package/esm/src/tests/createData.d.ts +7 -0
  112. package/esm/src/tests/createData.js +22 -0
  113. package/esm/src/tests/d.d.ts +6 -0
  114. package/esm/src/tests/d.js +19 -0
  115. package/esm/src/tests/dWithPrefilter.d.ts +7 -0
  116. package/esm/src/tests/dWithPrefilter.js +32 -0
  117. package/esm/src/tests/entityForCustomFilter.d.ts +16 -0
  118. package/esm/src/tests/entityForCustomFilter.js +44 -0
  119. package/esm/src/tests/entityWithValidationsOnColumn.d.ts +5 -0
  120. package/esm/src/tests/entityWithValidationsOnColumn.js +21 -0
  121. package/esm/src/tests/frontend-database-tests-setup.spec.d.ts +4 -0
  122. package/esm/src/tests/frontend-database-tests-setup.spec.js +38 -0
  123. package/esm/src/tests/h.d.ts +6 -0
  124. package/esm/src/tests/h.js +35 -0
  125. package/esm/src/tests/remult-3-entities.d.ts +23 -0
  126. package/esm/src/tests/remult-3-entities.js +72 -0
  127. package/esm/src/tests/tasks.d.ts +6 -0
  128. package/esm/src/tests/tasks.js +24 -0
  129. package/esm/src/tests/testHelper.spec.d.ts +34 -0
  130. package/esm/src/tests/testHelper.spec.js +217 -0
  131. package/esm/src/tests/testModel/models.d.ts +16 -0
  132. package/esm/src/tests/testModel/models.js +31 -0
  133. package/esm/src/validators.d.ts +14 -0
  134. package/esm/src/validators.js +33 -0
  135. package/esm/urlBuilder.d.ts +6 -0
  136. package/esm/urlBuilder.js +19 -0
  137. package/esm/valueConverters.d.ts +12 -0
  138. package/esm/valueConverters.js +169 -0
  139. package/package.json +14 -5
  140. package/postgres/postgres-data-provider.d.ts +4 -1
  141. package/postgres/postgres-data-provider.js +2 -2
  142. package/postgres/postgresColumnSyntax.d.ts +1 -1
  143. package/remult-knex/index.d.ts +5 -2
  144. package/remult-knex/index.js +8 -8
  145. package/remult-middleware.js +0 -1
  146. package/server/expressBridge.d.ts +4 -2
  147. package/server/expressBridge.js +17 -16
  148. package/src/backend-tests/my-test.backend-spec.js +3 -3
  149. package/src/data-providers/web-sql-data-provider.js +4 -3
  150. package/src/entity.d.ts +9 -2
  151. package/src/filter/filter-consumer-bridge-to-sql-request.d.ts +1 -1
  152. package/src/remult3/RepositoryImplementation.js +11 -3
  153. package/src/shared-tests/test-update-with-null.spec.js +38 -0
  154. package/src/validators.js +2 -2
  155. package/valueConverters.js +4 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Noam Honig, Yoni Rapoport and contributors.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -25,51 +25,40 @@
25
25
  <img alt="Twitter Follow" src="https://img.shields.io/twitter/follow/remultjs?style=social">
26
26
  </a>
27
27
  </div>
28
+ <hr/>
29
+
30
+ [Getting Started](#getting-started) | [Documentation](#documentation) | [Example App](#example-app)
28
31
 
29
32
  ## What is Remult?
30
33
 
31
- **Remult** is a full-stack CRUD framework that uses your TypeScript model types to provide:
34
+ **Remult** is a full-stack CRUD framework that uses your **TypeScript entities as a single source of truth for your API, frontend type-safe API client and backend ORM**.
32
35
 
33
- * Secure REST API (highly configurable)
34
- * Type-safe frontend API client
35
- * Type-safe backend query builder
36
+ ### Status
36
37
 
37
- #### Remult :heart: Code Sharing
38
+ Remult is **production-ready** and, in fact, used in production apps since 2017. However, we’re keeping the major version at zero so we can use community feedback to finalize the v1 API.
38
39
 
39
- With model types shared between frontend and backend code, Remult can **enforce data validation and constraints, defined once, both in the front-end and within back-end API routes**.
40
+ ## Motivation
40
41
 
41
- ## Getting started
42
- The best way to learn Remult is by following a tutorial of a simple Todo web app with a Node.js Express backend.
42
+ Full-stack web development is (still) too complicated. **Simple CRUD, a common requirement of any business application, should be simple to build, maintain, and extend** when the need arises.
43
43
 
44
- * [Tutorial with React](https://remult.dev/tutorials/react/)
45
- * [Tutorial with Angular](https://remult.dev/tutorials/angular/)
46
- * [Tutorial with Vue](https://remult.dev/tutorials/vue/)
47
- * [Tutorial with Next.js](https://remult.dev/tutorials/react-next/)
44
+ Remult abstracts away repetitive, boilerplate, error-prone, and poorly designed code on the one hand, and enables total flexibility and control on the other. **Remult let you write TypeScript code you can follow and safely refactor**, and fits nicely into any existing or new project by being minimalistic and completely unopinionated regarding the developer’s choice of other frameworks and tools.
45
+
46
+ Other frameworks tend to fall into either too much abstraction (no-code, low-code, BaaS) or partial abstraction (MVC frameworks, GraphQL, ORMs, API generators, code generators), and tend to be opinionated regarding the development tool-chain, deployment environment, configuration/conventions or DSL. Remult attempts to strike a better balance.
48
47
 
49
48
  ## Installation
49
+
50
+ The *remult* package is one and the same for both the frontend bundle and the backend. Install it once for a monolith project or per-repo in a monorepo.
51
+
50
52
  ```sh
51
53
  npm i remult
52
54
  ```
53
55
 
54
56
  ## Usage
55
57
 
56
- ### Setup API backend using a Node.js Express middleware
57
- ```ts
58
- import express from 'express';
59
- import { remultExpress } from 'remult/remult-express';
60
-
61
- const port = 3001;
62
- const app = express();
63
-
64
- app.use(remultExpress());
65
-
66
- app.listen(port, () => {
67
- console.log(`Example API listening at http://localhost:${port}`);
68
- });
69
- ```
70
-
71
58
  ### Define model classes
72
59
  ```ts
60
+ // shared/product.ts
61
+
73
62
  import { Entity, Fields } from 'remult';
74
63
 
75
64
  @Entity('products', {
@@ -84,6 +73,26 @@ export class Product {
84
73
  }
85
74
  ```
86
75
 
76
+ ### Setup API backend using an Express middleware
77
+ ```ts
78
+ // backend/index.ts
79
+
80
+ import express from 'express';
81
+ import { remultExpress } from 'remult/remult-express';
82
+ import { Product } from '../shared/product';
83
+
84
+ const port = 3001;
85
+ const app = express();
86
+
87
+ app.use(remultExpress({
88
+ entities: [Product]
89
+ }));
90
+
91
+ app.listen(port, () => {
92
+ console.log(`Example API listening at http://localhost:${port}`);
93
+ });
94
+ ```
95
+
87
96
  ### :rocket: API Ready
88
97
  ```sh
89
98
  > curl http://localhost:3001/api/products
@@ -93,12 +102,19 @@ export class Product {
93
102
 
94
103
  ### Find and manipulate data in type-safe frontend code
95
104
  ```ts
105
+ // frontend/code.ts
106
+
107
+ import { Remult } from 'remult';
108
+ import { Product } from '../shared/product';
109
+
110
+ const remult = new Remult();
111
+
96
112
  async function increasePriceOfTofu(priceIncrease: number) {
97
113
  const productsRepo = remult.repo(Product);
98
114
 
99
- const product = await productsRepo.findFirst({ name: 'Tofu' });
115
+ const product = await productsRepo.findFirst({ name: 'Tofu' }); // filter is passed through API request all the way to the db
100
116
  product.unitPrice += priceIncrease;
101
- productsRepo.save(product);
117
+ productsRepo.save(product); // mutation request updates the db with no boilerplate code
102
118
  }
103
119
  ```
104
120
 
@@ -108,7 +124,7 @@ async function increasePriceOfTofu(priceIncrease: number) {
108
124
  static async increasePriceOfTofu(priceIncrease: number, remult?: Remult) {
109
125
  const productsRepo = remult!.repo(Product);
110
126
 
111
- const product = await productsRepo.findFirst({ name: 'Tofu' });
127
+ const product = await productsRepo.findFirst({ name: 'Tofu' }); // use Remult in the backend as an ORM
112
128
  product.unitPrice += priceIncrease;
113
129
  productsRepo.save(product);
114
130
  }
@@ -184,6 +200,28 @@ export class Article {
184
200
  }
185
201
  ```
186
202
 
203
+ ## What about complex CRUD?
204
+
205
+ While simple CRUD shouldn’t require any backend coding, using Remult means having the ability to handle any complex scenario by controlling the backend in numerous ways:
206
+
207
+ * Backend computed (read-only) fields - from simple [expressions](https://remult.dev/docs/ref_field.html#serverexpression) to complex data lookups or even direct db access (SQL)
208
+ * Custom side-effects with [entity lifecycle hooks](https://remult.dev/docs/ref_entity.html#saving) (before/after saving/deleting)
209
+ * Backend only updatable fields (e.g. “last updated at”)
210
+ * Many-to-one [relations](https://remult.dev/docs/entity-relations.html) with [lazy/eager loading](https://remult.dev/docs/lazy-loading-of-related-entities.html)
211
+ * Roll-your-own type-safe endpoints with [Backend Methods](https://remult.dev/docs/backendMethods.html)
212
+ * Roll-your-own low-level endpoints (Express, Fastify, koa, others…)
213
+
214
+ ## Getting started
215
+ The best way to learn Remult is by following a tutorial of a simple Todo web app with a Node.js Express backend.
216
+
217
+ * [Tutorial with React](https://remult.dev/tutorials/react/)
218
+ * [Tutorial with Angular](https://remult.dev/tutorials/angular/)
219
+ * [Tutorial with Vue](https://remult.dev/tutorials/vue/)
220
+ * [Tutorial with Next.js](https://remult.dev/tutorials/react-next/)
221
+
222
+ ## Documentation
223
+ The [documentation](https://remult.dev/docs) covers the main features of Remult. However, it is still a work-in-progress.
224
+
187
225
  ## Example App
188
226
 
189
227
  [CRM demo](https://github.com/remult/crm-demo) with a React + [MUI](https://mui.com) front-end and Postgres database.
@@ -0,0 +1 @@
1
+ export declare function assign<T>(item: T, valuesToSet: Partial<T>): T;
package/esm/assign.js ADDED
@@ -0,0 +1,5 @@
1
+ export function assign(item, valuesToSet) {
2
+ if (valuesToSet)
3
+ Object.assign(item, valuesToSet);
4
+ return item;
5
+ }
@@ -0,0 +1,3 @@
1
+ export declare type ClassType<T> = {
2
+ new (...args: any[]): T;
3
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ import { RemultExpressBridge } from "./server/expressBridge";
2
+ export declare function remultGraphql(api: RemultExpressBridge): {
3
+ rootValue: {};
4
+ schema: string;
5
+ };
package/esm/graphql.js ADDED
@@ -0,0 +1,102 @@
1
+ import { Remult } from ".";
2
+ import { allEntities } from "./src/context";
3
+ import { getEntityKey } from "./src/remult3";
4
+ import { DataApi } from "./src/data-api";
5
+ export function remultGraphql(api) {
6
+ let r = new Remult();
7
+ let types = '';
8
+ let query = '';
9
+ let root = {};
10
+ for (const e of allEntities) {
11
+ let meta = r.repo(e).metadata;
12
+ let fields = '';
13
+ let filterFields = '';
14
+ let key = getEntityKey(e);
15
+ if (key) {
16
+ for (const f of meta.fields) {
17
+ {
18
+ let type = "String";
19
+ switch (f.valueType) {
20
+ case Boolean:
21
+ type = "Boolean";
22
+ case Number:
23
+ {
24
+ if (f.valueConverter?.fieldTypeInDb == 'integer')
25
+ type = "Int";
26
+ else
27
+ type = "Float";
28
+ }
29
+ }
30
+ fields += "\n\t" + f.key + ":" + type;
31
+ for (const operator of ["", "_ne"]) {
32
+ filterFields += "\n\t" + f.key + operator + ":" + type;
33
+ }
34
+ if (f.valueType === String || f.valueType === Number)
35
+ for (const operator of ["_gt", "_gte", "_lt", "_lte"]) {
36
+ filterFields += "\n\t" + f.key + operator + ":" + type;
37
+ }
38
+ if (f.valueType === String)
39
+ for (const operator of ["_st", "_contains"]) {
40
+ filterFields += "\n\t" + f.key + operator + ":" + type;
41
+ }
42
+ if (f.allowNull)
43
+ filterFields += "\n\t" + f.key + "_null:Boolean";
44
+ filterFields += "\n\t" + f.key + "_in:[" + type + "]";
45
+ }
46
+ }
47
+ types += "type " + key + "{" + fields + "\n}\n";
48
+ types += "input " + key + "Filter{" + filterFields + "\n\tOR:[" + key + "Filter]\n}\n";
49
+ query += "\n\t" + key + "(options: options, filter:" + key + "Filter): [" + key + "]";
50
+ root[key] = async ({ options, filter }, req) => {
51
+ let remult = await api.getRemult(req);
52
+ let repo = remult.repo(e);
53
+ let dApi = new DataApi(repo, remult);
54
+ let result;
55
+ let err;
56
+ await dApi.getArray({
57
+ success: x => result = x,
58
+ created: undefined,
59
+ deleted: undefined,
60
+ error: x => err = x,
61
+ forbidden: () => err = 'forbidden',
62
+ notFound: () => err = 'not found',
63
+ progress: undefined
64
+ }, {
65
+ get: key => {
66
+ if (options)
67
+ switch (key) {
68
+ case "_limit":
69
+ return options.limit;
70
+ case "_page":
71
+ return options.page;
72
+ case "_sort":
73
+ return options.sort;
74
+ case "_order":
75
+ return options.order;
76
+ }
77
+ }
78
+ }, filter);
79
+ if (err)
80
+ throw err;
81
+ return result;
82
+ };
83
+ }
84
+ }
85
+ if (query.length > 0) {
86
+ query = `type Query {${query}
87
+ }`;
88
+ }
89
+ return {
90
+ rootValue: root,
91
+ schema: `
92
+ input options{
93
+ limit:Int
94
+ page:Int
95
+ sort:String
96
+ order:String
97
+ }
98
+ ${types}
99
+ ${query}
100
+ `
101
+ };
102
+ }
package/esm/index.d.ts ADDED
@@ -0,0 +1,35 @@
1
+ export { Field, Fields, StringFieldOptions, FieldsMetadata, Entity, BuildEntity, EntityBase, ControllerBase, FieldRef, IdFieldRef, FieldsRef, EntityMetadata, EntityOrderBy, EntityFilter, FindOptions, QueryResult, QueryOptions, Repository, FieldType, FindFirstOptions, ComparisonValueFilter, ValueFilter, IdFilter, ContainsStringValueFilter, getFields, EntityRef, getEntityRef, SortSegments, ValueListFieldType, getValueList, ValueListFieldOptions, ValueListInfo, OmitEB, Paginator, CaptionTransformer } from './src/remult3';
2
+ export { EntityOptions } from './src/entity';
3
+ export { DataProvider, EntityDataProvider, EntityDataProviderFindOptions, ErrorInfo, RestDataProviderHttpProvider } from './src/data-interfaces';
4
+ export { SqlCommand, SqlImplementation, SqlResult } from './src/sql-command';
5
+ export { FieldMetadata, FieldOptions, FieldValidator, ValueConverter, ValueListItem, // reconsider, maybe it should go to remult angular as the abstraction ?
6
+ ValueOrExpression } from './src/column-interfaces';
7
+ export { RestDataProvider } from './src/data-providers/rest-data-provider';
8
+ export { InMemoryDataProvider } from './src/data-providers/in-memory-database';
9
+ export { ArrayEntityDataProvider } from './src/data-providers/array-entity-data-provider';
10
+ export { WebSqlDataProvider } from './src/data-providers/web-sql-data-provider';
11
+ export { SqlDatabase } from './src/data-providers/sql-database';
12
+ export { JsonDataProvider, JsonEntityStorage } from './src/data-providers/json-data-provider';
13
+ export { Controller, BackendMethodOptions, BackendMethod, ProgressListener } from './src/server-action';
14
+ export { Allowed, Allow, Remult, isBackend, AllowedForInstance, EventDispatcher, EventSource, HttpProvider, Unobserve, UserInfo } from './src/context';
15
+ export { IdEntity } from './src/id-entity';
16
+ export { SortSegment, Sort } from './src/sort';
17
+ export { OneToMany, CompoundIdField } from './src/column';
18
+ export { Filter } from './src/filter/filter-interfaces';
19
+ export { FilterConsumerBridgeToSqlRequest } from './src/filter/filter-consumer-bridge-to-sql-request';
20
+ export { UrlBuilder } from './urlBuilder';
21
+ export { Validators } from './src/validators';
22
+ export { ValueConverters } from './valueConverters';
23
+ export { ClassType } from "./classType";
24
+ export { allEntities } from "./src/context";
25
+ export { serializeError } from "./src/data-api";
26
+ export { DataApiRequest } from "./src/data-api";
27
+ export { DataApiResponse } from "./src/data-api";
28
+ export { DataApi } from "./src/data-api";
29
+ export { getEntityKey } from "./src/remult3/index";
30
+ export { jobWasQueuedResult } from "./src/server-action";
31
+ export { queuedJobInfoResponse } from "./src/server-action";
32
+ export { Action, classBackendMethodsArray, serverActionField } from "./src/server-action";
33
+ export { actionInfo } from "./src/server-action";
34
+ export { registerActionsOnServer } from './server/register-actions-on-server';
35
+ export { registerEntitiesOnServer } from './server/register-entities-on-server';
package/esm/index.js ADDED
@@ -0,0 +1,29 @@
1
+ /*
2
+ * Public API Surface of remult
3
+ */
4
+ export { Field, Fields, Entity, BuildEntity, EntityBase, ControllerBase, FieldType, getFields, getEntityRef, ValueListFieldType, getValueList, ValueListInfo, CaptionTransformer } from './src/remult3';
5
+ export { RestDataProvider } from './src/data-providers/rest-data-provider'; //V
6
+ export { InMemoryDataProvider } from './src/data-providers/in-memory-database'; //V
7
+ export { ArrayEntityDataProvider } from './src/data-providers/array-entity-data-provider'; //V
8
+ export { WebSqlDataProvider } from './src/data-providers/web-sql-data-provider'; //V
9
+ export { SqlDatabase } from './src/data-providers/sql-database'; //V
10
+ export { JsonDataProvider } from './src/data-providers/json-data-provider'; //V
11
+ //export * from './src/data-api'; //reconsider if to make internal
12
+ export { Controller, BackendMethod, ProgressListener } from './src/server-action';
13
+ export { Allow, Remult, isBackend, EventSource } from './src/context';
14
+ export { IdEntity } from './src/id-entity';
15
+ export { Sort } from './src/sort';
16
+ export { OneToMany, CompoundIdField } from './src/column';
17
+ export { Filter } from './src/filter/filter-interfaces';
18
+ export { FilterConsumerBridgeToSqlRequest } from './src/filter/filter-consumer-bridge-to-sql-request';
19
+ export { UrlBuilder } from './urlBuilder';
20
+ export { Validators } from './src/validators';
21
+ export { ValueConverters } from './valueConverters';
22
+ export { allEntities } from "./src/context";
23
+ export { serializeError } from "./src/data-api";
24
+ export { DataApi } from "./src/data-api";
25
+ export { getEntityKey } from "./src/remult3/index";
26
+ export { Action, classBackendMethodsArray, serverActionField } from "./src/server-action";
27
+ export { actionInfo } from "./src/server-action";
28
+ export { registerActionsOnServer } from './server/register-actions-on-server';
29
+ export { registerEntitiesOnServer } from './server/register-entities-on-server';
@@ -0,0 +1,9 @@
1
+ export declare class InputTypes {
2
+ static number: string;
3
+ static date: string;
4
+ static checkbox: string;
5
+ static password: string;
6
+ static email: string;
7
+ static tel: string;
8
+ static time: string;
9
+ }
@@ -0,0 +1,9 @@
1
+ export class InputTypes {
2
+ }
3
+ InputTypes.number = 'number';
4
+ InputTypes.date = 'date';
5
+ InputTypes.checkbox = 'checkbox';
6
+ InputTypes.password = 'password';
7
+ InputTypes.email = 'email';
8
+ InputTypes.tel = 'tel';
9
+ InputTypes.time = "time";
@@ -0,0 +1 @@
1
+ export * from './postgres-data-provider';
@@ -0,0 +1 @@
1
+ export * from './postgres-data-provider';
@@ -0,0 +1,40 @@
1
+ import { PoolConfig, QueryResult } from 'pg';
2
+ import { Remult } from '../src/context';
3
+ import { EntityMetadata } from '../src/remult3';
4
+ import { SqlCommand, SqlImplementation } from '../src/sql-command';
5
+ import { SqlDatabase } from '../src/data-providers/sql-database';
6
+ import { FieldMetadata } from '../src/column-interfaces';
7
+ export interface PostgresPool extends PostgresCommandSource {
8
+ connect(): Promise<PostgresClient>;
9
+ }
10
+ export interface PostgresClient extends PostgresCommandSource {
11
+ release(): void;
12
+ }
13
+ export declare class PostgresDataProvider implements SqlImplementation {
14
+ private pool;
15
+ entityIsUsedForTheFirstTime(entity: EntityMetadata): Promise<void>;
16
+ getLimitSqlSyntax(limit: number, offset: number): string;
17
+ createCommand(): SqlCommand;
18
+ constructor(pool: PostgresPool);
19
+ transaction(action: (dataProvider: SqlImplementation) => Promise<void>): Promise<void>;
20
+ }
21
+ export interface PostgresCommandSource {
22
+ query(queryText: string, values?: any[]): Promise<QueryResult>;
23
+ }
24
+ export declare function verifyStructureOfAllEntities(db: SqlDatabase, remult: Remult): Promise<void>;
25
+ export declare class PostgresSchemaBuilder {
26
+ private pool;
27
+ verifyStructureOfAllEntities(remult: Remult): Promise<void>;
28
+ createIfNotExist(entity: EntityMetadata): Promise<void>;
29
+ addColumnIfNotExist<T extends EntityMetadata>(entity: T, c: ((e: T) => FieldMetadata)): Promise<void>;
30
+ verifyAllColumns<T extends EntityMetadata>(entity: T): Promise<void>;
31
+ additionalWhere: string;
32
+ constructor(pool: SqlDatabase, schema?: string);
33
+ }
34
+ export declare function preparePostgresQueueStorage(sql: SqlDatabase): Promise<import("../server/expressBridge").EntityQueueStorage>;
35
+ export declare function createPostgresConnection(options?: {
36
+ connectionString?: string;
37
+ sslInDev?: boolean;
38
+ configuration?: "heroku" | PoolConfig;
39
+ autoCreateTables?: boolean;
40
+ }): Promise<SqlDatabase>;
@@ -0,0 +1,194 @@
1
+ import { Pool } from 'pg';
2
+ import { allEntities, Remult } from '../src/context';
3
+ import { postgresColumnSyntax } from './postgresColumnSyntax';
4
+ import { getDbNameProvider } from '../src/filter/filter-consumer-bridge-to-sql-request';
5
+ import { isAutoIncrement } from '../src/remult3';
6
+ import { SqlDatabase } from '../src/data-providers/sql-database';
7
+ export class PostgresDataProvider {
8
+ constructor(pool) {
9
+ this.pool = pool;
10
+ }
11
+ async entityIsUsedForTheFirstTime(entity) {
12
+ }
13
+ getLimitSqlSyntax(limit, offset) {
14
+ return ' limit ' + limit + ' offset ' + offset;
15
+ }
16
+ createCommand() {
17
+ return new PostgresBridgeToSQLCommand(this.pool);
18
+ }
19
+ async transaction(action) {
20
+ let client = await this.pool.connect();
21
+ try {
22
+ await client.query('BEGIN');
23
+ await action({
24
+ createCommand: () => new PostgresBridgeToSQLCommand(client),
25
+ entityIsUsedForTheFirstTime: this.entityIsUsedForTheFirstTime,
26
+ transaction: () => { throw "nested transactions not allowed"; },
27
+ getLimitSqlSyntax: this.getLimitSqlSyntax
28
+ });
29
+ await client.query('COMMIT');
30
+ }
31
+ catch (err) {
32
+ await client.query('ROLLBACK');
33
+ throw err;
34
+ }
35
+ finally {
36
+ await client.release();
37
+ }
38
+ }
39
+ }
40
+ class PostgresBridgeToSQLCommand {
41
+ constructor(source) {
42
+ this.source = source;
43
+ this.values = [];
44
+ }
45
+ addParameterAndReturnSqlToken(val) {
46
+ this.values.push(val);
47
+ return '$' + this.values.length;
48
+ }
49
+ execute(sql) {
50
+ return this.source.query(sql, this.values).then(r => new PostgresBridgeToSQLQueryResult(r));
51
+ }
52
+ }
53
+ class PostgresBridgeToSQLQueryResult {
54
+ constructor(r) {
55
+ this.r = r;
56
+ this.rows = r.rows;
57
+ }
58
+ getColumnKeyInResultForIndexInSelect(index) {
59
+ return this.r.fields[index].name;
60
+ }
61
+ }
62
+ export async function verifyStructureOfAllEntities(db, remult) {
63
+ return await new PostgresSchemaBuilder(db).verifyStructureOfAllEntities(remult);
64
+ }
65
+ export class PostgresSchemaBuilder {
66
+ constructor(pool, schema) {
67
+ this.pool = pool;
68
+ this.additionalWhere = '';
69
+ if (schema) {
70
+ this.additionalWhere = ' and table_schema=\'' + schema + '\'';
71
+ }
72
+ }
73
+ async verifyStructureOfAllEntities(remult) {
74
+ console.log("start verify structure");
75
+ for (const entityClass of allEntities) {
76
+ let entity = remult.repo(entityClass).metadata;
77
+ let e = await getDbNameProvider(entity);
78
+ try {
79
+ if (!entity.options.sqlExpression) {
80
+ if ((await e.entityName).toLowerCase().indexOf('from ') < 0) {
81
+ await this.createIfNotExist(entity);
82
+ await this.verifyAllColumns(entity);
83
+ }
84
+ }
85
+ }
86
+ catch (err) {
87
+ console.log("failed verify structure of " + e.entityName + " ", err);
88
+ }
89
+ }
90
+ }
91
+ async createIfNotExist(entity) {
92
+ var c = this.pool.createCommand();
93
+ let e = await getDbNameProvider(entity);
94
+ await c.execute("select 1 from information_Schema.tables where table_name=" + c.addParameterAndReturnSqlToken((e.entityName).toLowerCase()) + this.additionalWhere).then(async (r) => {
95
+ if (r.rows.length == 0) {
96
+ let result = '';
97
+ for (const x of entity.fields) {
98
+ if (!e.isDbReadonly(x) || isAutoIncrement(x)) {
99
+ if (result.length != 0)
100
+ result += ',';
101
+ result += '\r\n ';
102
+ if (isAutoIncrement(x))
103
+ result += e.nameOf(x) + ' serial';
104
+ else {
105
+ result += postgresColumnSyntax(x, e.nameOf(x));
106
+ if (x == entity.idMetadata.field)
107
+ result += ' primary key';
108
+ }
109
+ }
110
+ }
111
+ let sql = 'create table ' + e.entityName + ' (' + result + '\r\n)';
112
+ //console.log(sql);
113
+ await this.pool.execute(sql);
114
+ }
115
+ });
116
+ }
117
+ async addColumnIfNotExist(entity, c) {
118
+ let e = await getDbNameProvider(entity);
119
+ if (e.isDbReadonly(c(entity)))
120
+ return;
121
+ try {
122
+ let cmd = this.pool.createCommand();
123
+ const colName = e.nameOf(c(entity));
124
+ if ((await cmd.execute(`select 1
125
+ FROM information_schema.columns
126
+ WHERE table_name=${cmd.addParameterAndReturnSqlToken((e.entityName).toLocaleLowerCase())} and column_name=${cmd.addParameterAndReturnSqlToken((colName).toLocaleLowerCase())}` + this.additionalWhere)).rows.length == 0) {
127
+ let sql = `alter table ${e.entityName} add column ${postgresColumnSyntax(c(entity), colName)}`;
128
+ //console.log(sql);
129
+ await this.pool.execute(sql);
130
+ }
131
+ }
132
+ catch (err) {
133
+ console.log(err);
134
+ }
135
+ }
136
+ async verifyAllColumns(entity) {
137
+ try {
138
+ let cmd = this.pool.createCommand();
139
+ let e = await getDbNameProvider(entity);
140
+ let cols = (await cmd.execute(`select column_name
141
+ FROM information_schema.columns
142
+ WHERE table_name=${cmd.addParameterAndReturnSqlToken((e.entityName).toLocaleLowerCase())} ` + this.additionalWhere)).rows.map(x => x.column_name);
143
+ for (const col of entity.fields) {
144
+ if (!e.isDbReadonly(col))
145
+ if (!cols.includes(e.nameOf(col).toLocaleLowerCase())) {
146
+ let sql = `alter table ${e.entityName} add column ${postgresColumnSyntax(col, e.nameOf(col))}`;
147
+ //console.log(sql);
148
+ await this.pool.execute(sql);
149
+ }
150
+ }
151
+ }
152
+ catch (err) {
153
+ console.log(err);
154
+ }
155
+ }
156
+ }
157
+ export async function preparePostgresQueueStorage(sql) {
158
+ let c = new Remult();
159
+ c.setDataProvider(sql);
160
+ let JobsInQueueEntity = (await import('../server/expressBridge')).JobsInQueueEntity;
161
+ let e = c.repo(JobsInQueueEntity);
162
+ await new PostgresSchemaBuilder(sql).createIfNotExist(e.metadata);
163
+ await new PostgresSchemaBuilder(sql).verifyAllColumns(e.metadata);
164
+ return new (await import('../server/expressBridge')).EntityQueueStorage(c.repo(JobsInQueueEntity));
165
+ }
166
+ export async function createPostgresConnection(options) {
167
+ if (!options)
168
+ options = {};
169
+ let config = {};
170
+ if (options.configuration)
171
+ if (options.configuration == "heroku") {
172
+ config = {
173
+ connectionString: process.env.DATABASE_URL,
174
+ ssl: process.env.NODE_ENV !== "production" && !options.sslInDev ? false : {
175
+ rejectUnauthorized: false
176
+ }
177
+ };
178
+ }
179
+ else
180
+ config = options.configuration;
181
+ else {
182
+ if (!options.connectionString)
183
+ options.connectionString = process.env.DATABASE_URL;
184
+ }
185
+ if (!config.connectionString && options.connectionString) {
186
+ config.connectionString = options.connectionString;
187
+ }
188
+ const db = new SqlDatabase(new PostgresDataProvider(new Pool(config)));
189
+ let remult = new Remult();
190
+ remult.setDataProvider(db);
191
+ if (options.autoCreateTables === undefined || options.autoCreateTables)
192
+ await verifyStructureOfAllEntities(db, remult);
193
+ return db;
194
+ }
@@ -0,0 +1,2 @@
1
+ import { FieldMetadata } from '../src/column-interfaces';
2
+ export declare function postgresColumnSyntax(x: FieldMetadata, dbName: string): string;