sedentary 0.0.10 → 0.0.14

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.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2017-2020 Daniele Ricci
3
+ Copyright (c) 2017 Daniele Ricci
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,15 +1,15 @@
1
1
  # sedentary
2
2
 
3
- [![NPM version][npm-badge]][npm-url]
4
- [![Types][types-badge]][npm-url]
5
- [![NPM downloads][npm-downloads-badge]][npm-url]
6
-
7
3
  [![Build Status][travis-badge]][travis-url]
8
4
  [![Code Climate][code-badge]][code-url]
9
5
  [![Test Coverage][cover-badge]][code-url]
10
6
 
11
- [![Dependents][deps-badge]][npm-url]
7
+ [![NPM version][npm-badge]][npm-url]
8
+ [![NPM downloads][npm-downloads-badge]][npm-url]
12
9
  [![Stars][stars-badge]][github-url]
10
+
11
+ [![Types][types-badge]][npm-url]
12
+ [![Dependents][deps-badge]][npm-url]
13
13
  [![Donate][donate-badge]][donate-url]
14
14
 
15
15
  [code-badge]: https://codeclimate.com/github/iccicci/sedentary/badges/gpa.svg
@@ -24,7 +24,7 @@
24
24
  [npm-url]: https://www.npmjs.com/package/sedentary
25
25
  [stars-badge]: https://badgen.net/github/stars/iccicci/sedentary?icon=github&cache=300
26
26
  [travis-badge]: https://badgen.net/travis/iccicci/sedentary?icon=travis&cache=300
27
- [travis-url]: https://travis-ci.com/iccicci/sedentary
27
+ [travis-url]: https://app.travis-ci.com/github/iccicci/sedentary
28
28
  [types-badge]: https://badgen.net/npm/types/sedentary?color=green&icon=typescript&cache=300
29
29
 
30
30
  # under development
@@ -95,10 +95,10 @@ The full documentation is on [sedentary.readthedocs.io](https://sedentary.readth
95
95
 
96
96
  Requires:
97
97
 
98
- - Node.js: **v10**
98
+ - Node.js: **v12**
99
99
  - TypeScript: **v4.1** (or none if used in a JavaScript project).
100
100
 
101
- The package is tested under [all Node.js versions](https://travis-ci.org/iccicci/sedentary)
101
+ The package is tested under [all Node.js versions](https://app.travis-ci.com/github/iccicci/sedentary)
102
102
  currently supported accordingly to [Node.js Release](https://github.com/nodejs/Release#readme).
103
103
 
104
104
  To work with the package under Windows, be sure to configure `bash.exe` as your _script-shell_.
package/index.d.ts CHANGED
@@ -1,77 +1,115 @@
1
- import { DB, Meta, Record, Type } from "./lib/db";
2
- declare type TypeDefinition<N extends unknown, R extends unknown> = (() => Type<N, R>) | Type<N, R>;
3
- interface FieldOptions<N extends unknown, R extends unknown> {
1
+ import { DB, Entry, Meta, Natural, Type } from "./lib/db";
2
+ export { Entry, Natural, Type } from "./lib/db";
3
+ export declare type TypeDefinition<N extends Natural, E> = (() => Type<N, E>) | Type<N, E>;
4
+ export interface AttributeOptions<N extends Natural, E> {
4
5
  defaultValue?: N;
5
6
  fieldName?: string;
6
7
  notNull?: boolean;
7
- type: TypeDefinition<N, R>;
8
+ type: TypeDefinition<N, E>;
8
9
  unique?: boolean;
9
10
  }
10
- declare type FieldDefinition<N extends unknown, R extends unknown> = TypeDefinition<N, R> | FieldOptions<N, R>;
11
- declare type FieldsDefinition = {
12
- [key: string]: FieldDefinition<unknown, unknown>;
11
+ export declare type AttributeDefinition<N extends Natural, E> = TypeDefinition<N, E> | AttributeOptions<N, E>;
12
+ export declare type AttributesDefinition = {
13
+ [key: string]: AttributeDefinition<Natural, unknown>;
13
14
  };
14
- declare type ForeignKeyFileds<T, k> = T extends FieldDefinition<unknown, infer R> ? (R extends Record ? k : never) : never;
15
- declare type ForeignKey<T> = T extends FieldDefinition<unknown, infer R> ? () => Promise<R> : never;
16
- declare type Keys<F extends FieldsDefinition> = {
17
- [f in keyof F]?: ForeignKeyFileds<F[f], f>;
15
+ declare type KeysAttributes<T, k> = T extends AttributeDefinition<Natural, infer E> ? (E extends Entry ? k : never) : never;
16
+ declare type Keys<F extends AttributesDefinition> = {
17
+ [f in keyof F]?: KeysAttributes<F[f], f>;
18
18
  }[keyof F];
19
19
  declare type Methods<T> = {
20
20
  [key: string]: (this: T) => unknown;
21
21
  };
22
22
  declare type Native__<T> = T extends Type<infer N, unknown> ? N : never;
23
- declare type Native_<T> = T extends () => Type<infer N, infer R> ? Native__<Type<N, R>> : Native__<T>;
24
- declare type Native<T> = T extends FieldOptions<infer N, infer R> ? Native__<Type<N, R>> : Native_<T>;
25
- declare type Parent<T> = T extends Meta<unknown, infer R> ? R : never;
26
- declare type Options<M, T> = {
23
+ declare type Native_<T> = T extends () => Type<infer N, infer E> ? Native__<Type<N, E>> : Native__<T>;
24
+ declare type Native<T> = T extends AttributeOptions<infer N, infer E> ? Native__<Type<N, E>> : Native_<T>;
25
+ declare type Parent<T> = T extends Meta<Natural, infer E> ? E : never;
26
+ export declare type IndexAttributes = string[] | string;
27
+ export interface IndexOptions {
28
+ attributes: IndexAttributes;
29
+ type?: "btree" | "hash";
30
+ unique?: boolean;
31
+ }
32
+ export declare type IndexDefinition = IndexAttributes | IndexOptions;
33
+ export declare type BaseModelOptions<T> = {
34
+ indexes?: {
35
+ [key: string]: IndexDefinition;
36
+ };
27
37
  init?: (this: T) => void;
28
- methods?: M;
29
38
  sync?: boolean;
30
39
  tableName?: string;
31
40
  };
32
- declare type Model<F extends FieldsDefinition, M> = {
33
- [f in keyof F]?: Native<F[f]>;
41
+ export declare type ModelOptions<K extends string, M extends Methods<T>, P extends Meta<Natural, Entry>, T extends Entry> = BaseModelOptions<T> & {
42
+ int8id?: boolean;
43
+ methods?: M;
44
+ parent?: P;
45
+ primaryKey?: K;
46
+ };
47
+ declare type ForeignKey<T> = T extends AttributeDefinition<Natural, infer E> ? () => Promise<E> : never;
48
+ declare type ModelWithMetods<A extends AttributesDefinition, M> = {
49
+ [a in keyof A]?: Native<A[a]>;
34
50
  } & {
35
- [f in Keys<F> & string as `${f}Load`]?: ForeignKey<F[f]>;
51
+ [a in Keys<A> & string as `${a}Load`]?: ForeignKey<A[a]>;
36
52
  } & M;
37
- declare type Ancestor<F, N extends unknown, T extends Record> = (new () => T) & {
38
- [f in keyof F]?: Meta<Native<F[f]>, T>;
53
+ declare type Model<A extends AttributesDefinition> = {
54
+ [a in keyof A]?: Native<A[a]>;
55
+ } & {
56
+ [a in Keys<A> & string as `${a}Load`]?: ForeignKey<A[a]>;
57
+ };
58
+ declare type Ancestor<A, N extends Natural, T extends Entry> = (new () => T) & {
59
+ [a in keyof A]?: Meta<Native<A[a]>, T>;
39
60
  } & {
40
61
  load: (boh: boolean) => Promise<T[]>;
41
62
  } & Meta<N, T>;
42
63
  export interface SchemaOptions {
43
- log?: (message: string) => void;
64
+ log?: ((message: string) => void) | null;
44
65
  sync?: boolean;
45
66
  }
46
67
  export declare class Sedentary {
47
68
  protected db: DB;
48
- protected log: (message: string) => void;
69
+ protected log: (...data: unknown[]) => void;
49
70
  private sync;
50
71
  private models;
51
72
  constructor(filename: string, options?: SchemaOptions);
73
+ DATETIME(): Type<Date, unknown>;
74
+ FKEY<N extends Natural, E extends Entry>(attribute: Type<N, E>): Type<N, E>;
52
75
  INT(size?: number): Type<number, unknown>;
53
76
  INT8(): Type<string, unknown>;
54
- FKEY<N extends unknown, R extends Record>(record: Type<N, R>): Type<N, R>;
77
+ VARCHAR(size?: number): Type<string, unknown>;
55
78
  connect(): Promise<void>;
56
79
  end(): Promise<void>;
57
- fldString<R extends unknown>(options?: {
58
- foreignKey: R;
59
- }): Type<string, R>;
60
- model<F extends FieldsDefinition, M extends Methods<T>, T extends Record & {
80
+ model<A extends AttributesDefinition, M extends Methods<T>, T extends Entry & {
81
+ id?: string;
82
+ } & ModelWithMetods<A, M>>(name: string, attributes: A, options?: BaseModelOptions<T> & {
83
+ int8id: true;
84
+ methods: M;
85
+ }): Ancestor<A, string, T>;
86
+ model<A extends AttributesDefinition, K extends keyof A, M extends Methods<T>, N extends K extends keyof A ? Native<A[K]> : never, T extends Entry & ModelWithMetods<A, M>>(name: string, attributes: A, options?: BaseModelOptions<T> & {
87
+ methods: M;
88
+ primaryKey: K;
89
+ }): Ancestor<A, N, T>;
90
+ model<A extends AttributesDefinition, M extends Methods<T>, P extends Meta<Natural, Entry>, N extends P extends Meta<infer N, Entry> ? N : never, T extends Parent<P> & ModelWithMetods<A, M>>(name: string, attributes: A, options?: BaseModelOptions<T> & {
91
+ methods: M;
92
+ parent: P;
93
+ }): Ancestor<A, N, T>;
94
+ model<A extends AttributesDefinition, M extends Methods<T>, T extends Entry & {
95
+ id?: number;
96
+ } & ModelWithMetods<A, M>>(name: string, attributes: A, options?: BaseModelOptions<T> & {
97
+ methods: M;
98
+ }): Ancestor<A, number, T>;
99
+ model<A extends AttributesDefinition, T extends Entry & {
61
100
  id?: string;
62
- } & Model<F, M>>(name: string, fields: F, options?: Options<M, T> & {
101
+ } & Model<A>>(name: string, attributes: A, options?: BaseModelOptions<T> & {
63
102
  int8id: true;
64
- }): Ancestor<F, string, T>;
65
- model<F extends FieldsDefinition, K extends keyof F, M extends Methods<T>, N extends K extends keyof F ? Native<F[K]> : never, T extends Record & Model<F, M>>(name: string, fields: F, options?: Options<M, T> & {
103
+ }): Ancestor<A, string, T>;
104
+ model<A extends AttributesDefinition, K extends keyof A, N extends K extends keyof A ? Native<A[K]> : never, T extends Entry & Model<A>>(name: string, attributes: A, options?: BaseModelOptions<T> & {
66
105
  primaryKey: K;
67
- }): Ancestor<F, N, T>;
68
- model<F extends FieldsDefinition, M extends Methods<T>, P extends Meta<unknown, Record>, N extends P extends Meta<infer N, Record> ? N : never, T extends Parent<P> & Model<F, M>>(name: string, fields: F, options?: Options<M, T> & {
106
+ }): Ancestor<A, N, T>;
107
+ model<A extends AttributesDefinition, P extends Meta<Natural, Entry>, N extends P extends Meta<infer N, Entry> ? N : never, T extends Parent<P> & Model<A>>(name: string, attributes: A, options?: BaseModelOptions<T> & {
69
108
  parent: P;
70
- }): Ancestor<F, N, T>;
71
- model<F extends FieldsDefinition, M extends Methods<T>, T extends Record & {
109
+ }): Ancestor<A, N, T>;
110
+ model<A extends AttributesDefinition, T extends Entry & {
72
111
  id?: number;
73
- } & Model<F, M>>(name: string, fields: F, options?: Options<M, T>): Ancestor<F, number, T>;
112
+ } & Model<A>>(name: string, attributes: A, options?: BaseModelOptions<T>): Ancestor<A, number, T>;
74
113
  checkSize(size: number, message: string): number;
75
114
  }
76
115
  export declare const Package: typeof Sedentary;
77
- export {};
package/index.js CHANGED
@@ -1,29 +1,46 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Package = exports.Sedentary = void 0;
3
+ exports.Package = exports.Sedentary = exports.Type = exports.Entry = void 0;
4
4
  const db_1 = require("./lib/db");
5
+ const log_1 = require("./lib/log");
5
6
  const minidb_1 = require("./lib/minidb");
7
+ var db_2 = require("./lib/db");
8
+ Object.defineProperty(exports, "Entry", { enumerable: true, get: function () { return db_2.Entry; } });
9
+ Object.defineProperty(exports, "Type", { enumerable: true, get: function () { return db_2.Type; } });
10
+ const allowedOption = ["indexes", "init", "int8id", "methods", "parent", "primaryKey", "sync", "tableName", "type"];
11
+ const reservedNames = [
12
+ ...["attributeName", "base", "class", "constructor", "defaultValue", "entry", "fieldName", "init", "isModel"],
13
+ ...["load", "meta", "methods", "name", "primaryKey", "prototype", "save", "size", "tableName", "type"]
14
+ ];
6
15
  class Sedentary {
7
16
  constructor(filename, options) {
8
17
  this.sync = true;
9
18
  this.models = {};
10
19
  if (typeof filename !== "string")
11
- throw new Error("Sedentary.constructor: 'filename' argument: Wrong type, expected 'string'");
20
+ throw new Error("new Sedentary: 'filename' argument: Wrong type, expected 'string'");
12
21
  if (!options)
13
22
  options = {};
14
23
  if (!(options instanceof Object))
15
- throw new Error("Sedentary.constructor: 'options' argument: Wrong type, expected 'Object'");
16
- for (const k in options) {
17
- if (["log", "sync"].indexOf(k) === -1)
18
- throw new Error(`Sedentary.constructor: 'options' argument: Unknown '${k}' option`);
19
- this[k] = options[k];
20
- }
21
- // eslint-disable-next-line no-console
22
- this.log || (this.log = console.log);
24
+ throw new Error("new Sedentary: 'options' argument: Wrong type, expected 'Object'");
25
+ for (const k in options)
26
+ if (!["log", "sync"].includes(k))
27
+ throw new Error(`new Sedentary: 'options' argument: Unknown '${k}' option`);
28
+ this.log = (0, log_1.createLogger)(options.log);
29
+ if ("sync" in options)
30
+ this.sync = options.sync;
23
31
  this.db = new minidb_1.MiniDB(filename, this.log);
24
32
  }
33
+ DATETIME() {
34
+ return new db_1.Type({ base: Date, type: "DATETIME" });
35
+ }
36
+ FKEY(attribute) {
37
+ const { attributeName, base, fieldName, size, tableName, type, unique } = attribute;
38
+ if (!unique)
39
+ throw new Error(`Sedentary.FKEY: '${tableName}' table: '${attributeName}' attribute: is not unique: can't be used as FKEY target`);
40
+ return new db_1.Type({ base, foreignKey: { attributeName, fieldName, tableName }, size, type });
41
+ }
25
42
  INT(size) {
26
- const message = "Sedentary.INT: Wrong 'size': expected 2 or 4";
43
+ const message = "Sedentary.INT: 'size' argument: Wrong value, expected 2 or 4";
27
44
  size = size ? this.checkSize(size, message) : 4;
28
45
  if (size !== 2 && size !== 4)
29
46
  throw new Error(message);
@@ -32,8 +49,10 @@ class Sedentary {
32
49
  INT8() {
33
50
  return new db_1.Type({ base: String, size: 8, type: "INT8" });
34
51
  }
35
- FKEY(record) {
36
- return new db_1.Type({ base: record.base, size: 0, type: "" });
52
+ VARCHAR(size) {
53
+ const message = "Sedentary.VARCHAR: 'size' argument: Wrong value, expected positive integer";
54
+ size = size ? this.checkSize(size, message) : undefined;
55
+ return new db_1.Type({ base: String, size, type: "VARCHAR" });
37
56
  }
38
57
  async connect() {
39
58
  try {
@@ -44,7 +63,7 @@ class Sedentary {
44
63
  this.log("Synced");
45
64
  }
46
65
  catch (e) {
47
- this.log("Connecting: " + e.message);
66
+ this.log("Connecting:", e.message);
48
67
  throw e;
49
68
  }
50
69
  }
@@ -53,37 +72,39 @@ class Sedentary {
53
72
  await this.db.end();
54
73
  this.log("Connection closed");
55
74
  }
56
- fldString(options) {
57
- return new db_1.Type({ base: String, size: 0, type: "" });
58
- }
59
- model(name, fields, options) {
75
+ model(name, attributes, options) {
60
76
  if (typeof name !== "string")
61
77
  throw new Error("Sedentary.model: 'name' argument: Wrong type, expected 'string'");
62
78
  if (this.models[name])
63
79
  throw new Error(`Sedentary.model: '${name}' model: Model already defined`);
64
- if (!fields)
65
- fields = {};
66
- if (!(fields instanceof Object))
67
- throw new Error(`Sedentary.model: '${name}' model: 'fields' argument: Wrong type, expected 'Object'`);
80
+ if (!attributes)
81
+ attributes = {};
82
+ if (!(attributes instanceof Object))
83
+ throw new Error(`Sedentary.model: '${name}' model: 'attributes' argument: Wrong type, expected 'Object'`);
68
84
  if (!options)
69
85
  options = {};
70
86
  if (!(options instanceof Object))
71
87
  throw new Error(`Sedentary.model: '${name}' model: 'options' argument: Wrong type, expected 'Object'`);
72
88
  for (const k in options)
73
- if (["init", "int8id", "methods", "parent", "primaryKey", "sync", "tableName", "type"].indexOf(k) === -1)
89
+ if (!allowedOption.includes(k))
74
90
  throw new Error(`Sedentary.model: '${name}' model: 'options' argument: Unknown '${k}' option`);
75
- const constraints = [];
76
- const { int8id, parent, primaryKey, sync, tableName } = Object.assign({ sync: this.sync, tableName: name + "s" }, options);
91
+ if (options.int8id && options.parent)
92
+ throw new Error(`Sedentary.model: '${name}' model: 'int8id' and 'parent' options conflict each other`);
93
+ if (options.int8id && options.primaryKey)
94
+ throw new Error(`Sedentary.model: '${name}' model: 'int8id' and 'primaryKey' options conflict each other`);
95
+ if (options.parent && options.primaryKey)
96
+ throw new Error(`Sedentary.model: '${name}' model: 'parent' and 'primaryKey' options conflict each other`);
97
+ const { indexes, int8id, parent, primaryKey, sync, tableName } = Object.assign({ sync: this.sync, tableName: name }, options);
77
98
  let { methods } = options;
78
- const pkName = primaryKey || "id";
79
- let farray = int8id
80
- ? [new db_1.Field({ fieldName: "id", notNull: true, size: 8, type: "INT8", unique: true })]
81
- : [new db_1.Field({ fieldName: "id", notNull: true, size: 4, type: "INT", unique: true })];
99
+ let aarray = int8id
100
+ ? [new db_1.Attribute(Object.assign(Object.assign({}, this.INT8()), { attributeName: "id", fieldName: "id", notNull: true, tableName, unique: true }))]
101
+ : [new db_1.Attribute(Object.assign(Object.assign({}, this.INT(4)), { attributeName: "id", fieldName: "id", notNull: true, tableName, unique: true }))];
102
+ let constraints = [{ attribute: aarray[0], constraintName: `${tableName}_id_unique`, type: "u" }];
103
+ const iarray = [];
104
+ const pk = aarray[0];
82
105
  if (methods && !(methods instanceof Object))
83
106
  throw new Error(`Sedentary.model: '${name}' model: 'methods' option: Wrong type, expected 'Object'`);
84
107
  if (parent) {
85
- if (primaryKey)
86
- throw new Error(`Sedentary.model: '${name}' model: Both 'parent' and 'primaryKey' options provided`);
87
108
  methods = (methods ? Object.assign(Object.assign({}, (parent.methods || {})), methods) : parent.methods);
88
109
  try {
89
110
  if (!parent.isModel())
@@ -95,72 +116,126 @@ class Sedentary {
95
116
  }
96
117
  if (primaryKey && typeof primaryKey !== "string")
97
118
  throw new Error(`Sedentary.model: '${name}' model: 'primaryKey' option: Wrong type, expected 'string'`);
98
- if (primaryKey && Object.keys(fields).indexOf(primaryKey) === -1)
99
- throw new Error(`Sedentary.model: '${name}' model: 'primaryKey' option: Field '${primaryKey}' does not exists`);
100
- if (parent || primaryKey)
101
- farray = [];
102
- if (!parent)
103
- constraints.push({ name: `${tableName}_${pkName}_unique`, type: "u", field: pkName });
104
- for (const fname in fields) {
105
- if (["base", "constructor", "load", "meta", "name", "prototype", "save", "size", "type"].indexOf(fname) !== -1)
106
- throw new Error(`Sedentary.model: '${name}' model: '${fname}' field: Reserved name`);
107
- const field = fields[fname];
108
- // eslint-disable-next-line prefer-const
109
- let { defaultValue, fieldName, notNull, size, type, unique } = (() => {
119
+ if (primaryKey && !Object.keys(attributes).includes(primaryKey))
120
+ throw new Error(`Sedentary.model: '${name}' model: 'primaryKey' option: Attribute '${primaryKey}' does not exists`);
121
+ if (parent || primaryKey) {
122
+ aarray = [];
123
+ constraints = [];
124
+ }
125
+ for (const attributeName in attributes) {
126
+ if (reservedNames.includes(attributeName))
127
+ throw new Error(`Sedentary.model: '${name}' model: '${attributeName}' attribute: Reserved name`);
128
+ const call = (defaultValue, fieldName, notNull, unique, func, message1, message2) => {
129
+ if (func === this.FKEY)
130
+ throw new Error(`${message1} 'this.FKEY' can't be used directly`);
131
+ if (func !== this.DATETIME && func !== this.INT && func !== this.INT8 && func !== this.VARCHAR)
132
+ throw new Error(`${message1} ${message2}`);
133
+ return new db_1.Attribute(Object.assign({ attributeName, defaultValue, fieldName, notNull, tableName, unique }, func()));
134
+ };
135
+ const attributeDefinition = attributes[attributeName];
136
+ let { base, defaultValue, fieldName, foreignKey, notNull, size, type, unique } = (() => {
110
137
  const ret = (() => {
111
- // eslint-disable-next-line prefer-const
112
- let { defaultValue, fieldName, unique, type } = { defaultValue: undefined, fieldName: fname, unique: false, type: null };
113
- const call = (defaultValue, fieldName, unique, func, message) => {
114
- if (func !== this.FKEY && func !== this.INT && func !== this.INT8)
115
- throw new Error(message);
116
- return new db_1.Field(Object.assign({ defaultValue, fieldName, unique }, func()));
117
- };
118
- if (field instanceof db_1.Type)
119
- return new db_1.Field(Object.assign({ fieldName: fname }, field));
120
- if (field instanceof Function)
121
- return call(undefined, fname, false, field, `Sedentary.model: '${name}' model: '${fname}' field: Wrong type, expected 'Field'`);
122
- if (!(field instanceof Object))
123
- throw new Error(`Sedentary.model: '${name}' model: '${fname}' field: Wrong field type, expected 'Field'`);
124
- ({ defaultValue, fieldName, unique, type } = field);
125
- if (!fieldName)
126
- fieldName = fname;
138
+ if (attributeDefinition instanceof db_1.Type)
139
+ return new db_1.Attribute(Object.assign({ attributeName, fieldName: attributeName, notNull: false, tableName }, attributeDefinition));
140
+ if (attributeDefinition instanceof Function)
141
+ return call(undefined, attributeName, false, false, attributeDefinition, `Sedentary.model: '${name}' model: '${attributeName}' attribute:`, "Wrong type, expected 'Attribute'");
142
+ if (!(attributeDefinition instanceof Object))
143
+ throw new Error(`Sedentary.model: '${name}' model: '${attributeName}' attribute: Wrong attribute type, expected 'Attribute'`);
144
+ const attributeDefaults = Object.assign({ defaultValue: undefined, fieldName: attributeName, notNull: false, unique: false }, attributeDefinition);
145
+ const { defaultValue, fieldName, notNull, unique, type } = attributeDefaults;
127
146
  if (defaultValue === null)
128
- throw new Error(`Sedentary.model: '${name}' model: '${fname}' field: 'defaultValue' option: Does 'null' default value really makes sense?`);
147
+ throw new Error(`Sedentary.model: '${name}' model: '${attributeName}' attribute: 'defaultValue' option: Does 'null' default value really makes sense?`);
129
148
  if (typeof fieldName !== "string")
130
- throw new Error(`Sedentary.model: '${name}' model: '${fname}' field: 'fieldName' option: Wrong type, expected 'string'`);
131
- if (!type)
132
- throw new Error(`Sedentary.model: '${name}' model: '${fname}' field: Missing 'type' option`);
149
+ throw new Error(`Sedentary.model: '${name}' model: '${attributeName}' attribute: 'fieldName' option: Wrong type, expected 'string'`);
150
+ if (typeof notNull !== "boolean")
151
+ throw new Error(`Sedentary.model: '${name}' model: '${attributeName}' attribute: 'notNull' option: Wrong type, expected 'boolean'`);
152
+ if (typeof unique !== "boolean")
153
+ throw new Error(`Sedentary.model: '${name}' model: '${attributeName}' attribute: 'unique' option: Wrong type, expected 'boolean'`);
154
+ if (type === undefined)
155
+ throw new Error(`Sedentary.model: '${name}' model: '${attributeName}' attribute: Missing 'type' option`);
133
156
  if (type instanceof db_1.Type)
134
- return new db_1.Field(Object.assign(Object.assign(Object.assign({}, field), { fieldName }), type));
157
+ return new db_1.Attribute(Object.assign({ attributeName, defaultValue, fieldName, notNull, tableName, unique }, type));
135
158
  if (type instanceof Function)
136
- return call(defaultValue, fieldName, unique, type, `Sedentary.model: '${name}' model: '${fname}' field: 'type' option: Wrong type, expected 'Type'`);
137
- throw new Error(`Sedentary.model: '${name}' model: '${fname}' field: 'type' option: Wrong type, expected 'Type'`);
159
+ return call(defaultValue, fieldName, notNull, unique, type, `Sedentary.model: '${name}' model: '${attributeName}' attribute: 'type' option:`, "Wrong type, expected 'Type'");
160
+ throw new Error(`Sedentary.model: '${name}' model: '${attributeName}' attribute: 'type' option: Wrong type, expected 'Type'`);
138
161
  })();
139
162
  const { base, defaultValue } = ret;
140
163
  if (defaultValue !== undefined) {
164
+ if (base === Date && !(defaultValue instanceof Date))
165
+ throw new Error(`Sedentary.model: '${name}' model: '${attributeName}' attribute: 'defaultValue' option: Wrong type, expected 'Date'`);
141
166
  if (base === Number && typeof defaultValue !== "number")
142
- throw new Error(`Sedentary.model: '${name}' model: '${fname}' field: 'defaultValue' option: Wrong type, expected 'number'`);
167
+ throw new Error(`Sedentary.model: '${name}' model: '${attributeName}' attribute: 'defaultValue' option: Wrong type, expected 'number'`);
143
168
  if (base === String && typeof defaultValue !== "string")
144
- throw new Error(`Sedentary.model: '${name}' model: '${fname}' field: 'defaultValue' option: Wrong type, expected 'string'`);
169
+ throw new Error(`Sedentary.model: '${name}' model: '${attributeName}' attribute: 'defaultValue' option: Wrong type, expected 'string'`);
145
170
  }
146
171
  return ret;
147
172
  })();
148
- if (primaryKey === fname) {
173
+ if (primaryKey === attributeName) {
149
174
  notNull = true;
150
175
  unique = true;
151
176
  }
152
177
  if (defaultValue)
153
178
  notNull = true;
154
- farray.push(new db_1.Field({ defaultValue, fieldName, notNull, size, type, unique }));
155
- if (unique) {
156
- constraints.push({
157
- name: `${tableName}_${fieldName}_unique`,
158
- type: "u",
159
- field: fieldName
160
- });
179
+ const attribute = new db_1.Attribute({ attributeName, base, defaultValue, fieldName, foreignKey, notNull, size, tableName, type, unique });
180
+ aarray.push(attribute);
181
+ if (foreignKey)
182
+ constraints.push({ attribute, constraintName: `fkey_${fieldName}_${foreignKey.tableName}_${foreignKey.fieldName}`, type: "f" });
183
+ if (unique)
184
+ constraints.push({ attribute, constraintName: `${tableName}_${fieldName}_unique`, type: "u" });
185
+ }
186
+ if (indexes) {
187
+ const flds = attributes;
188
+ if (!(indexes instanceof Object))
189
+ throw new Error(`Sedentary.model: '${name}' model: 'indexes' option: Wrong type, expected 'Object'`);
190
+ for (const indexName in indexes) {
191
+ if (aarray.filter(({ fieldName, unique }) => unique && `${tableName}_${fieldName}_unique` === indexName).length !== 0)
192
+ throw new Error(`Sedentary.model: '${name}' model: '${indexName}' index: index name already inferred by the unique constraint on an attribute`);
193
+ const idx = indexes[indexName];
194
+ const checkAttribute = (attribute, l) => {
195
+ if (typeof attribute !== "string")
196
+ throw new Error(`Sedentary.model: '${name}' model: '${indexName}' index: #${l + 1} attribute: Wrong type, expected 'string'`);
197
+ if (!(attribute in flds))
198
+ throw new Error(`Sedentary.model: '${name}' model: '${indexName}' index: #${l + 1} attribute: Unknown attribute '${attribute}'`);
199
+ };
200
+ let attributes;
201
+ let type = "btree";
202
+ let unique = false;
203
+ if (idx instanceof Array) {
204
+ idx.forEach(checkAttribute);
205
+ attributes = idx;
206
+ }
207
+ else if (typeof idx === "string") {
208
+ checkAttribute(idx, 0);
209
+ attributes = [idx];
210
+ }
211
+ else if (idx instanceof Object) {
212
+ for (const k in idx)
213
+ if (!["attributes", "type", "unique"].includes(k))
214
+ throw new Error(`Sedentary.model: '${name}' model: '${indexName}' index: Unknown index option '${k}'`);
215
+ ({ attributes, type, unique } = Object.assign({ type: "btree", unique: false }, idx));
216
+ if (!attributes)
217
+ throw new Error(`Sedentary.model: '${name}' model: '${indexName}' index: Missing 'attributes' option`);
218
+ if (attributes instanceof Array)
219
+ attributes.forEach(checkAttribute);
220
+ else if (typeof attributes === "string") {
221
+ checkAttribute(attributes, 0);
222
+ attributes = [attributes];
223
+ }
224
+ else
225
+ throw new Error(`Sedentary.model: '${name}' model: '${indexName}' index: 'attributes' option: Wrong type, expected 'FieldNames'`);
226
+ if (typeof type !== "string")
227
+ throw new Error(`Sedentary.model: '${name}' model: '${indexName}' index: 'type' option: Wrong type, expected 'string'`);
228
+ if (!["btree", "hash"].includes(type))
229
+ throw new Error(`Sedentary.model: '${name}' model: '${indexName}' index: 'type' option: Wrong value, expected 'btree' or 'hash'`);
230
+ if (typeof unique !== "boolean")
231
+ throw new Error(`Sedentary.model: '${name}' model: '${indexName}' index: 'unique' option: Wrong type, expected 'boolean'`);
232
+ }
233
+ else
234
+ throw new Error(`Sedentary.model: '${name}' model: '${indexName}' index: Wrong type, expected 'Object'`);
235
+ iarray.push({ fields: attributes, indexName, type, unique });
161
236
  }
162
237
  }
163
- this.db.addTable(new db_1.Table({ constraints, fields: farray, parent, primaryKey, sync, tableName }));
238
+ this.db.addTable(new db_1.Table({ constraints, attributes: aarray, indexes: iarray, parent, primaryKey, sync, tableName }));
164
239
  this.models[name] = true;
165
240
  const init = parent
166
241
  ? options.init
@@ -171,7 +246,7 @@ class Sedentary {
171
246
  : parent.init
172
247
  : options.init;
173
248
  const flds = {};
174
- for (const key in fields)
249
+ for (const key in attributes)
175
250
  flds[key] = null;
176
251
  class Class {
177
252
  constructor() {
@@ -186,20 +261,24 @@ class Sedentary {
186
261
  });
187
262
  }
188
263
  }
189
- const load2 = (boh) => new Promise((resolve, reject) => setTimeout(() => {
264
+ const load = (boh) => new Promise((resolve, reject) => setTimeout(() => {
190
265
  if (boh)
191
266
  return resolve([new Class()]);
192
267
  reject(new Error("boh"));
193
268
  }, 10));
194
- Object.defineProperty(load2, "name", { value: name + "s.load" });
195
- const meta = { tableName, primaryKey, init, methods };
196
- Object.defineProperty(Class, "name", { value: name });
197
- Object.defineProperty(Class, "load", { value: load2 });
269
+ Object.defineProperty(load, "name", { value: name + ".load" });
270
+ const meta = { base: Number, type: "meta", tableName, primaryKey, init, methods };
271
+ Object.defineProperty(Class, "isModel", { value: () => true });
272
+ Object.defineProperty(Class, "load", { value: load });
198
273
  Object.defineProperty(Class, "meta", { value: new db_1.Meta(meta) });
274
+ Object.defineProperty(Class, "name", { value: name });
199
275
  Object.defineProperty(Class.prototype.save, "name", { value: name + ".save" });
200
276
  Object.assign(Class, new db_1.Meta(meta));
201
- Object.assign(Class, Object.assign(Object.assign({}, fields), { isModel: () => true }));
202
277
  Object.assign(Class.prototype, methods);
278
+ for (const attribute of aarray)
279
+ Object.defineProperty(Class, attribute.attributeName, { value: attribute });
280
+ for (const key of ["attributeName", "base", "fieldName", "size", "type", "unique"])
281
+ Object.defineProperty(Class, key, { value: pk[key] });
203
282
  return Class;
204
283
  }
205
284
  checkSize(size, message) {
@@ -213,12 +292,11 @@ class Sedentary {
213
292
  exports.Sedentary = Sedentary;
214
293
  exports.Package = Sedentary;
215
294
  const db = new Sedentary("gino");
216
- const Users = db.model("User", { foo: db.INT(), bar: db.fldString() }, {});
217
- const fields = {
295
+ const Users = db.model("User", { foo: db.INT(), bar: { type: db.VARCHAR(), unique: true } }, {});
296
+ class Item extends db.model("Item", {
218
297
  num: db.FKEY(Users),
219
- str: db.fldString()
220
- };
221
- class Item extends db.model("Item", fields, {
298
+ str: db.VARCHAR()
299
+ }, {
222
300
  init: function () {
223
301
  this.num = 0;
224
302
  this.str = "0";
@@ -251,7 +329,7 @@ class Next extends db.model("Next", { a: db.INT, b: db.INT }, {
251
329
  primaryKey: "a"
252
330
  }) {
253
331
  }
254
- class Current extends db.model("Current", { b: db.FKEY(Next) }, {
332
+ class Current extends db.model("Current", { b: { type: db.FKEY(Next), unique: true } }, {
255
333
  init: function () {
256
334
  this.b = 24;
257
335
  }