pinstripe 0.21.0 → 0.23.0

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 (54) hide show
  1. package/README.md +10 -0
  2. package/lib/client.js +2 -3
  3. package/lib/command.js +1 -1
  4. package/lib/commands/generate_migration.js +16 -8
  5. package/lib/commands/generate_model.js +1 -1
  6. package/lib/commands/generate_project.js +3 -1
  7. package/lib/component.js +38 -27
  8. package/lib/component_event.js +28 -0
  9. package/lib/components/_file_importer.js +1 -1
  10. package/lib/components/pinstripe_markdown_editor.js +2 -2
  11. package/lib/components/pinstripe_overlay.js +1 -1
  12. package/lib/components/pinstripe_silo.js +2 -0
  13. package/lib/constants.js +4 -0
  14. package/lib/database/client.js +14 -2
  15. package/lib/database/migration.js +2 -2
  16. package/lib/database/migrator.js +2 -2
  17. package/lib/database/row.js +64 -55
  18. package/lib/database/table.js +5 -3
  19. package/lib/database/union.js +4 -4
  20. package/lib/database.js +19 -15
  21. package/lib/escape_html.js +2 -0
  22. package/lib/html.js +0 -1
  23. package/lib/import_all.js +26 -13
  24. package/lib/index.js +1 -3
  25. package/lib/model.js +1 -1
  26. package/lib/project.js +1 -1
  27. package/lib/registry.js +1 -1
  28. package/lib/service_consumer.js +1 -1
  29. package/lib/service_factory.js +1 -1
  30. package/lib/services/defer.js +1 -1
  31. package/lib/services/inflector.js +1 -1
  32. package/lib/services/render_form.js +5 -5
  33. package/lib/services/render_markdown.js +1 -2
  34. package/lib/unescape_html.js +1 -20
  35. package/lib/util.js +3 -0
  36. package/lib/view.js +1 -0
  37. package/lib/virtual_node.js +3 -4
  38. package/lib/virtual_node.test.js +17 -14
  39. package/package.json +6 -7
  40. package/lib/event_wrapper.js +0 -26
  41. package/lib/migrations/1627976184_create_user.js +0 -13
  42. package/lib/migrations/1628057822_create_session.js +0 -10
  43. package/lib/migrations/_file_importer.js +0 -1
  44. package/lib/models/_file_importer.js +0 -1
  45. package/lib/models/session.js +0 -9
  46. package/lib/models/user.js +0 -53
  47. package/lib/services/session.js +0 -19
  48. package/lib/views/sign_in/index.js +0 -34
  49. package/lib/views/sign_in/verify_password.js +0 -52
  50. package/lib/views/sign_out.js +0 -16
  51. /package/lib/components/{pinstripe_anchor.js → a.js} +0 -0
  52. /package/lib/components/{pinstripe_body.js → body.js} +0 -0
  53. /package/lib/components/{pinstripe_document.js → document.js} +0 -0
  54. /package/lib/components/{pinstripe_form.js → form.js} +0 -0
package/README.md ADDED
@@ -0,0 +1,10 @@
1
+
2
+ # Welcome to Pinstripe
3
+
4
+ ## What is Pinstripe?
5
+
6
+ A slick web framework for Node.js.
7
+
8
+ ## License
9
+
10
+ Pinstripe is released under the [MIT License](https://opensource.org/licenses/MIT).
package/lib/client.js CHANGED
@@ -1,8 +1,7 @@
1
1
  import { fileURLToPath } from 'url';
2
2
 
3
- import { Class } from "./class.js";
4
- import { Singleton } from "./singleton.js";
5
-
3
+ import { Class } from './class.js';
4
+ import { Singleton } from './singleton.js';
6
5
 
7
6
  export const Client = Class.extend().include({
8
7
  meta(){
package/lib/command.js CHANGED
@@ -1,8 +1,8 @@
1
1
 
2
2
  import { Class } from './class.js';
3
+ import { inflector } from './inflector.js';
3
4
  import { Registry } from './registry.js';
4
5
  import { ServiceConsumer } from './service_consumer.js';
5
- import { inflector } from "./inflector.js";
6
6
 
7
7
  export const Command = Class.extend().include({
8
8
  meta(){
@@ -29,15 +29,23 @@ export default {
29
29
 
30
30
  await generateFile(`lib/migrations/${name}.js`, () => {
31
31
  line();
32
- line(`export default async ({ database }) => {`);
32
+ line(`export default {`);
33
33
  indent(() => {
34
- line();
35
- if(table && fields.length){
36
- fields.forEach(({ name, type }) => {
37
- line(`await database.${table}.addColumn('${name}', '${type}');`);
38
- });
39
- line();
40
- }
34
+ line(`async migrate(){`);
35
+ indent(() => {
36
+ if(table && fields.length){
37
+ line(`await this.database.table('${table}', async ${table} => {`);
38
+ indent(() => {
39
+ fields.forEach(({ name, type }) => {
40
+ line(`await ${table}.addColumn('${name}', '${type}');`);
41
+ });
42
+ })
43
+ line(`});`);
44
+ } else {
45
+ line();
46
+ }
47
+ })
48
+ line(`}`);
41
49
  })
42
50
  line('};');
43
51
  line();
@@ -11,7 +11,7 @@ export default {
11
11
  const fields = extractFields();
12
12
 
13
13
  const collectionName = this.inflector.camelize(this.inflector.pluralize(name));
14
- if(!await this.database[collectionName].exists){
14
+ if(!await this.database[collectionName]){
15
15
  const denormalizedFields = fields.map(({ mandatory, name, type }) => {
16
16
  return `${ mandatory ? '^' : '' }${name}:${type}`
17
17
  });
@@ -1,5 +1,6 @@
1
1
 
2
2
  import { spawnSync } from 'child_process';
3
+ import * as crypto from 'crypto';
3
4
 
4
5
  export default {
5
6
  async run(){
@@ -92,7 +93,8 @@ export default {
92
93
  line(`export default {`);
93
94
  indent(() => {
94
95
  line(`database,`);
95
- line(`mail`);
96
+ line(`mail,`);
97
+ line(`salt: '${crypto.randomUUID()}'`)
96
98
  })
97
99
  line(`};`);
98
100
  });
package/lib/component.js CHANGED
@@ -1,14 +1,13 @@
1
1
 
2
2
  import { fileURLToPath } from 'url'; // pinstripe-if-client: const fileURLToPath = undefined;
3
3
 
4
- import { VirtualNode } from './virtual_node.js';
5
- import { EventWrapper } from './event_wrapper.js';
6
- import { TEXT_ONLY_TAGS } from './constants.js';
7
-
8
4
  import { Class } from './class.js';
5
+ import { TEXT_ONLY_TAGS } from './constants.js';
6
+ import { Inflector } from './inflector.js';
7
+ import { VirtualNode } from './virtual_node.js';
9
8
  import { Registry } from './registry.js';
9
+ import { ComponentEvent } from './component_event.js';
10
10
  import { Client } from './client.js'; // pinstripe-if-client: const Client = undefined;
11
- import { Inflector } from './inflector.js';
12
11
 
13
12
  export const Component = Class.extend().include({
14
13
  meta(){
@@ -41,6 +40,10 @@ export const Component = Class.extend().include({
41
40
  import include from ${JSON.stringify(filePath)};
42
41
  Component.register(${JSON.stringify(relativeFilePathWithoutExtension)}, include);
43
42
  `);
43
+ } else {
44
+ Client.instance.addModule(`
45
+ import ${JSON.stringify(filePath)};
46
+ `);
44
47
  }
45
48
  return importFile.call(this, params);
46
49
  }
@@ -124,7 +127,9 @@ export const Component = Class.extend().include({
124
127
  },
125
128
 
126
129
  get realParent(){
127
- return this.node.parentNode ? this.constructor.instanceFor(this.node.parentNode) : null;
130
+ if(this.node.parentNode) return this.constructor.instanceFor(this.node.parentNode);
131
+ if(this.node.host instanceof Element) return this.constructor.instanceFor(this.node.host);
132
+ return null;
128
133
  },
129
134
 
130
135
  get parent(){
@@ -298,7 +303,7 @@ export const Component = Class.extend().include({
298
303
  const selector = args.pop()
299
304
 
300
305
  const wrapperFn = (event, ...args) => {
301
- const eventWrapper = EventWrapper.instanceFor(event)
306
+ const eventWrapper = ComponentEvent.instanceFor(event)
302
307
  if(selector){
303
308
  if(eventWrapper.target.is(selector)){
304
309
  return fn.call(eventWrapper.target, eventWrapper, ...args);
@@ -485,6 +490,9 @@ const matchesSelector = (() => {
485
490
  })();
486
491
 
487
492
  function cleanChildren(){
493
+ if(this.node.shadowRoot){
494
+ this.shadow.children.forEach(child => clean.call(child));
495
+ }
488
496
  this.children.forEach(child => clean.call(child));
489
497
  }
490
498
 
@@ -515,6 +523,9 @@ function clearTimers(){
515
523
  }
516
524
 
517
525
  function initChildren(){
526
+ if(this.node.shadowRoot){
527
+ this.shadow.children.forEach(child => initChildren.call(child));
528
+ }
518
529
  this.children.forEach(child => initChildren.call(child));
519
530
  }
520
531
 
@@ -537,13 +548,19 @@ function createVirtualNode(html){
537
548
  }
538
549
 
539
550
  function patch(attributes, virtualChildren){
540
- const isEmptyFrame = this.is('.frame') && virtualChildren.length == 0;
551
+ const isFrame = this.type == 'pinstripe-frame' || this.attributes['data-component'] == 'pinstripe-frame';
552
+ const isEmptyFrame = isFrame && virtualChildren.length == 0;
541
553
  if(isEmptyFrame && attributes['data-load-on-init'] === undefined){
542
554
  attributes['data-load-on-init'] = 'true';
543
555
  }
544
556
  patchAttributes.call(this, attributes);
545
557
  if(isEmptyFrame) return;
546
- patchChildren.call(this, virtualChildren);
558
+ if(this.is('pinstripe-silo, [data-component="pinstripe-silo"]')){
559
+ patchChildren.call(this.shadow, virtualChildren);
560
+ patchChildren.call(this, []);
561
+ } else {
562
+ patchChildren.call(this, virtualChildren);
563
+ }
547
564
  }
548
565
 
549
566
  function patchAttributes(attributes){
@@ -622,10 +639,17 @@ function insert(virtualNode, referenceChild, returnComponent = true){
622
639
  insert.call(new Component(node, true), child, null, false);
623
640
  })
624
641
 
625
- this.node.insertBefore(
626
- node,
627
- referenceChild && referenceChild.node
628
- );
642
+ if(this.is('pinstripe-silo, [data-component="pinstripe-silo"]')){
643
+ this.shadow.node.insertBefore(
644
+ node,
645
+ referenceChild && referenceChild.node
646
+ );
647
+ } else {
648
+ this.node.insertBefore(
649
+ node,
650
+ referenceChild && referenceChild.node
651
+ );
652
+ }
629
653
 
630
654
  if(returnComponent){
631
655
  return Component.instanceFor(node);
@@ -653,17 +677,4 @@ function normalizeVirtualNode(){
653
677
  }
654
678
  }
655
679
 
656
- EventWrapper.Component = Component;
657
-
658
- [
659
- ['#document', 'pinstripe-document'],
660
- ['a', 'pinstripe-anchor'],
661
- ['body', 'pinstripe-body'],
662
- ['form', 'pinstripe-form']
663
- ].forEach(([name, include]) => {
664
- Component.register(name, {
665
- meta(){
666
- this.include(include);
667
- }
668
- })
669
- });
680
+ ComponentEvent.Component = Component;
@@ -0,0 +1,28 @@
1
+
2
+ import { Class } from './class.js';
3
+ import { trapify } from './trapify.js';
4
+
5
+ export const ComponentEvent = Class.extend().include({
6
+ meta(){
7
+ this.assignProps({
8
+ instanceFor(event){
9
+ if(!event._componentEvent){
10
+ event._componentEvent = ComponentEvent.new(event);
11
+ }
12
+ return event._componentEvent;
13
+ }
14
+ });
15
+ },
16
+
17
+ initialize(event){
18
+ this.event = event;
19
+ return trapify(this);
20
+ },
21
+
22
+ __get(target, name){
23
+ const out = target.event[name];
24
+ if(out instanceof Node) return ComponentEvent.Component.instanceFor(out);
25
+ if(typeof out == 'function') return (...args) => out.call(target.event, ...args);
26
+ return out;
27
+ }
28
+ });
@@ -1 +1 @@
1
- export { Component as default } from 'pinstripe'
1
+ export { Component as default } from 'pinstripe';
@@ -59,11 +59,11 @@ Component.register('pinstripe-markdown-editor/line-inserter', {
59
59
 
60
60
  Component.register('pinstripe-markdown-editor/anchor', {
61
61
  meta(){
62
- this.include('pinstripe-anchor');
62
+ this.include('a');
63
63
  },
64
64
 
65
65
  initialize(...args){
66
- this.constructor.for('pinstripe-anchor').prototype.initialize.call(this, ...args);
66
+ this.constructor.for('a').prototype.initialize.call(this, ...args);
67
67
 
68
68
  this.patch({
69
69
  ...this.attributes,
@@ -1,5 +1,5 @@
1
1
 
2
- export default {
2
+ export default {
3
3
  meta(){
4
4
  this.include('pinstripe-frame');
5
5
  },
@@ -0,0 +1,2 @@
1
+
2
+ export default {};
package/lib/constants.js CHANGED
@@ -20,3 +20,7 @@ export const TEXT_ONLY_TAGS = [
20
20
  'script',
21
21
  'style'
22
22
  ];
23
+
24
+ export const IS_SERVER = typeof window == 'undefined';
25
+
26
+ export const IS_CLIENT = !IS_SERVER;
@@ -2,7 +2,8 @@ import mysql from 'mysql2';
2
2
  import sqlite from 'sqlite3';
3
3
  import { existsSync, unlinkSync } from 'fs';
4
4
 
5
- import { Class } from "../class.js";
5
+ import { Class } from '../class.js';
6
+
6
7
 
7
8
  export const Client = Class.extend().include({
8
9
  initialize(config){
@@ -31,7 +32,7 @@ export const Client = Class.extend().include({
31
32
  }
32
33
  });
33
34
  }
34
- return run.call(this, ...prepare.call(this, query));
35
+ return run.call(this, ...prepare.call(this, await resolveQuery(query)));
35
36
  },
36
37
 
37
38
  async lock(fn){
@@ -130,6 +131,17 @@ export const Client = Class.extend().include({
130
131
  });
131
132
 
132
133
 
134
+ async function resolveQuery(query){
135
+ let out = await query;
136
+ if(Array.isArray(out)){
137
+ out = [ ...out ];
138
+ for(let i = 0; i < out.length; i++){
139
+ out[i] = await resolveQuery(out[i]);
140
+ }
141
+ }
142
+ return out;
143
+ }
144
+
133
145
  function flattenFirst(query){
134
146
  if(!Array.isArray(query[0])) return query;
135
147
  return flattenFirst([...query[0], ...query.slice(1)]);
@@ -1,6 +1,6 @@
1
1
 
2
- import { Class } from "../class.js";
3
- import { Registry } from "../registry.js";
2
+ import { Class } from '../class.js';
3
+ import { Registry } from '../registry.js';
4
4
 
5
5
  export const Migration = Class.extend().include({
6
6
  meta(){
@@ -1,5 +1,5 @@
1
1
 
2
- import { Class } from "../class.js";
2
+ import { Class } from '../class.js';
3
3
  import { Migration } from "./migration.js";
4
4
 
5
5
  export const Migrator = Class.extend().include({
@@ -8,7 +8,7 @@ export const Migrator = Class.extend().include({
8
8
  },
9
9
 
10
10
  async migrate(){
11
- if(!this.database.table('pinstripeAppliedMigrations').exists){
11
+ if(!await this.database.table('pinstripeAppliedMigrations').exists){
12
12
  await this.database.table('pinstripeAppliedMigrations', async pinstripeAppliedMigrations => {
13
13
  await pinstripeAppliedMigrations.addColumn('schemaVersion', 'integer');
14
14
  });
@@ -1,11 +1,12 @@
1
+
1
2
  import crypto from 'crypto';
2
3
 
4
+ import { Registry } from '../registry.js';
3
5
  import { Model, defineCallbacks } from "../model.js";
4
- import { Registry } from "../registry.js";
5
6
  import { Table } from "./table.js";
6
7
  import { TableReference } from './table_reference.js';
7
8
  import { defer } from '../defer.js';
8
- import { inflector } from '../inflector.js'
9
+ import { inflector } from '../inflector.js';
9
10
  import { COLUMN_TYPE_TO_FORM_FIELD_TYPE_MAP } from './constants.js';
10
11
 
11
12
  export const Row = Model.extend().include({
@@ -150,79 +151,82 @@ export const Row = Model.extend().include({
150
151
  modifiedFields[name] = this[name];
151
152
  }
152
153
  });
153
- if(Object.keys(modifiedFields).length == 0) return this;
154
-
155
- const query = [];
154
+
155
+ if(Object.keys(modifiedFields).length) {
156
+ const query = [];
156
157
 
157
- const tableReference = TableReference.new(this.constructor.collectionName);
158
+ const tableReference = TableReference.new(this.constructor.collectionName);
158
159
 
159
- if(this._exists){
160
- query.push('update ? set ', tableReference);
161
- Object.keys(modifiedFields).forEach((name, i) => {
162
- if(name == 'id') return;
163
- this.database.client.adapt({
164
- mysql(){
165
- if(name.match(/(^id|Id)$/)){
166
- query.push(i > 0 ? ', ? = uuid_to_bin(?)' : '? = uuid_to_bin(?)', tableReference.createColumnReference(name), modifiedFields[name]);
167
- } else {
168
- query.push(i > 0 ? ', ? = ?' : '? = ?', tableReference.createColumnReference(name), modifiedFields[name]);
169
- }
170
- },
160
+ if(this._exists){
161
+ query.push('update ? set ', tableReference);
162
+ Object.keys(modifiedFields).forEach((name, i) => {
163
+ if(name == 'id') return;
164
+ this.database.client.adapt({
165
+ mysql(){
166
+ if(name.match(/(^id|Id)$/)){
167
+ query.push(i > 0 ? ', ? = uuid_to_bin(?)' : '? = uuid_to_bin(?)', tableReference.createColumnReference(name), modifiedFields[name]);
168
+ } else {
169
+ query.push(i > 0 ? ', ? = ?' : '? = ?', tableReference.createColumnReference(name), modifiedFields[name]);
170
+ }
171
+ },
171
172
 
172
- sqlite(){
173
- query.push(i > 0 ? `, \`${name}\` = ?` : `\`${name}\` = ?`, modifiedFields[name]);
174
- }
173
+ sqlite(){
174
+ query.push(i > 0 ? `, \`${name}\` = ?` : `\`${name}\` = ?`, modifiedFields[name]);
175
+ }
176
+ });
175
177
  });
176
- });
177
- this.database.client.adapt(this, {
178
- mysql(){
179
- query.push(' where ? = uuid_to_bin(?)', tableReference.createColumnReference('id'), this._initialFields.id);
180
- },
181
-
182
- sqlite(){
183
- query.push(' where ? = ?', tableReference.createColumnReference('id'), this._initialFields.id);
184
- }
185
- });
186
-
187
- } else {
188
- query.push('insert into ?(', tableReference);
189
- Object.keys(modifiedFields).forEach((name, i) => {
190
- this.database.client.adapt({
178
+ this.database.client.adapt(this, {
191
179
  mysql(){
192
- query.push(i > 0 ? ', ?' : '?', tableReference.createColumnReference(name));
180
+ query.push(' where ? = uuid_to_bin(?)', tableReference.createColumnReference('id'), this._initialFields.id);
193
181
  },
194
182
 
195
183
  sqlite(){
196
- query.push(i > 0 ? `, \`${name}\`` : `\`${name}\``,);
184
+ query.push(' where ? = ?', tableReference.createColumnReference('id'), this._initialFields.id);
197
185
  }
198
186
  });
199
- });
200
- query.push(') values(');
201
- Object.keys(modifiedFields).forEach((name, i) => {
202
- if(name.match(/(^id|Id)$/)){
187
+
188
+ } else {
189
+ query.push('insert into ?(', tableReference);
190
+ Object.keys(modifiedFields).forEach((name, i) => {
203
191
  this.database.client.adapt({
204
192
  mysql(){
205
- query.push(i > 0 ? ', uuid_to_bin(?)' : 'uuid_to_bin(?)', modifiedFields[name]);
193
+ query.push(i > 0 ? ', ?' : '?', tableReference.createColumnReference(name));
206
194
  },
207
195
 
208
196
  sqlite(){
209
- query.push(i > 0 ? ', ?' : '?', modifiedFields[name]);
197
+ query.push(i > 0 ? `, \`${name}\`` : `\`${name}\``,);
210
198
  }
211
199
  });
212
- } else {
213
- query.push(i > 0 ? ', ?' : '?', modifiedFields[name]);
214
- }
215
- });
216
- query.push(')');
217
- }
200
+ });
201
+ query.push(') values(');
202
+ Object.keys(modifiedFields).forEach((name, i) => {
203
+ if(name.match(/(^id|Id)$/)){
204
+ this.database.client.adapt({
205
+ mysql(){
206
+ query.push(i > 0 ? ', uuid_to_bin(?)' : 'uuid_to_bin(?)', modifiedFields[name]);
207
+ },
208
+
209
+ sqlite(){
210
+ query.push(i > 0 ? ', ?' : '?', modifiedFields[name]);
211
+ }
212
+ });
213
+ } else {
214
+ query.push(i > 0 ? ', ?' : '?', modifiedFields[name]);
215
+ }
216
+ });
217
+ query.push(')');
218
+ }
218
219
 
219
- await this.database.run(query);
220
+ await this.database.run(query);
220
221
 
221
- Object.keys(modifiedFields).forEach(name => {
222
- this[name] = modifiedFields[name];
223
- });
222
+ Object.keys(modifiedFields).forEach(name => {
223
+ this[name] = modifiedFields[name];
224
+ this._initialFields[name] = modifiedFields[name];
225
+ });
224
226
 
225
- this._exists = true;
227
+ this._exists = true;
228
+
229
+ }
226
230
 
227
231
  await (this._exists ? this._runAfterUpdateCallbacks() : this._runAfterInsertCallbacks());
228
232
 
@@ -326,6 +330,11 @@ function defineRelationship({ name, type, collectionName, fromKey, toKey, cascad
326
330
  this.prototype.assignProps({
327
331
  get [name](){
328
332
  return defer(() => {
333
+ if(fromKey != 'id'){
334
+ const out = this.database[collectionName].where({ [toKey]: this[fromKey] });
335
+ if(type == 'singular') return out.first();
336
+ return out;
337
+ }
329
338
  const out = this.database[this.constructor.collectionName].where({ id: this.id })[name];
330
339
  if(type == 'singular') return out.first();
331
340
  return out;
@@ -1,6 +1,7 @@
1
1
 
2
- import { Class } from "../class.js";
3
- import { Registry } from "../registry.js";
2
+ import { Class } from '../class.js';
3
+ import { inflector } from '../inflector.js';
4
+ import { Registry } from '../registry.js';
4
5
  import { TableReference } from "./table_reference.js";
5
6
  import {
6
7
  MYSQL_COLUMN_TYPE_TO_TYPE_MAP,
@@ -13,7 +14,6 @@ import {
13
14
  COLUMN_TYPE_TO_FORM_FIELD_TYPE_MAP
14
15
  } from './constants.js';
15
16
  import { Union } from "./union.js";
16
- import { inflector } from "../inflector.js";
17
17
 
18
18
  export const Table = Class.extend().include({
19
19
  meta(){
@@ -489,6 +489,8 @@ export const Table = Class.extend().include({
489
489
  }
490
490
  });
491
491
 
492
+ Union.Table = Table;
493
+
492
494
  function joinToUnion(fromKey, collectionName, toKey){
493
495
  return Union.new(
494
496
  this.database,
@@ -1,7 +1,7 @@
1
1
 
2
- import { Class } from "../class.js";
2
+ import { Class } from '../class.js';
3
+ import { inflector } from '../inflector.js';
3
4
  import { Row } from './row.js';
4
- import { inflector } from "../inflector.js";
5
5
 
6
6
  export const Union = Class.extend().include({
7
7
  meta(){
@@ -12,7 +12,7 @@ export const Union = Class.extend().include({
12
12
  },
13
13
 
14
14
  create(name, database){
15
- return this.new(database, this.tableNamesFor(name).map(tableName => database.table(tableName)));
15
+ return this.new(database, this.tableNamesFor(name).map(tableName => this.Table.create(tableName, database)));
16
16
  }
17
17
  });
18
18
  },
@@ -125,4 +125,4 @@ export const Union = Class.extend().include({
125
125
  }
126
126
  return this;
127
127
  }
128
- });
128
+ });
package/lib/database.js CHANGED
@@ -1,7 +1,7 @@
1
-
2
1
  import { Class } from './class.js';
3
- import { Table, Union, Row, Migrator } from './database/index.js';
4
2
  import { trapify } from './trapify.js';
3
+ import { defer } from './defer.js';
4
+ import { Table, Union, Row, Migrator } from './database/index.js';
5
5
 
6
6
  let loadSchemaPromise;
7
7
 
@@ -23,26 +23,30 @@ export const Database = Class.extend().include({
23
23
  },
24
24
 
25
25
  table(name, fn){
26
- const out = Table.create(name, this);
27
- if(fn) return fn.call(out, out);
28
- return out;
26
+ return defer(() => {
27
+ const out = Table.create(name, this);
28
+ if(fn) return fn.call(out, out);
29
+ return out;
30
+ });
29
31
  },
30
32
 
31
33
  union(name){
32
- return Union.create(name, this);
34
+ return defer(() => Union.create(name, this));
33
35
  },
34
36
 
35
- async singleton(name){
36
- const { abstract, singleton, collectionName } = Row.for(name);
37
- if(!singleton || abstract) return;
38
- const table = this.table(collectionName);
39
- const out = await table.first();
40
- if(out) return out;
41
- return this.lock(async () => {
37
+ singleton(name){
38
+ return defer(async () => {
39
+ const { abstract, singleton, collectionName } = Row.for(name);
40
+ if(!singleton || abstract) return;
41
+ const table = this.table(collectionName);
42
42
  const out = await table.first();
43
43
  if(out) return out;
44
- await table.insert();
45
- return table.first();
44
+ return this.lock(async () => {
45
+ const out = await table.first();
46
+ if(out) return out;
47
+ await table.insert();
48
+ return table.first();
49
+ });
46
50
  });
47
51
  },
48
52
 
@@ -0,0 +1,2 @@
1
+
2
+ export { encode as escapeHtml } from "html-entities";
package/lib/html.js CHANGED
@@ -1,6 +1,5 @@
1
1
 
2
2
  import { Class } from './class.js';
3
- import { defer } from './defer.js';
4
3
 
5
4
  export const Html = Class.extend().include({
6
5
  meta(){