sedentary 0.0.11 → 0.0.15

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